Commit Graph

179 Commits

Author SHA1 Message Date
Alaister Young 9af6e65df4 fix(studio): DOM-nesting hydration errors, ghost deleted-snippet nav, and migrations query 400s (#47667)
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>
2026-07-08 12:32:11 +08:00
Danny White 5dc054ae8f feat(studio): warn in Connect sheet when Data API is disabled (#47537)
## What kind of change does this PR introduce?

Feature. Resolves DEPR-599.

## What is the current behavior?

When the Data API is disabled (PostgREST has no exposed schemas), the
Connect sheet still shows client-library setup steps for Framework and
MCP modes without indicating that database queries will fail.

## What is the new behavior?

When database access via the Connect instructions requires PostgREST, an
inline warning appears above the steps (setup instructions remain
visible):

- **Framework**: warns when Data API is off; install, env vars, and
auth/SSR setup still work
- **MCP**: warns only when Database tools apply (selected explicitly, or
by default when no feature filter is set)

The warning fails open if PostgREST config cannot be loaded, and links
to Data API settings via an "Enable Data API" CTA.

| After |
| --- |
| <img width="1664" height="718" alt="CleanShot 2026-07-02 at 21 29
16@2x"
src="https://github.com/user-attachments/assets/80d21927-c4dd-4158-8946-bf648b95e451"
/>|

## Additional context

- Gating logic lives in `ConnectStepsSection.utils.ts` with unit tests
- Out of scope: warning when Data API is on but zero tables/schemas are
exposed
- Coexists with the upcoming warehouse branch's catalog warning — that
lives in a separate `WarehouseCatalogPanel` for `catalog` mode only

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Connection setup now checks Data API enablement and conditionally
shows a “Data API disabled” warning, including an action to open Data
API settings.
* **Bug Fixes**
* Warning logic now more accurately reflects the selected connection
mode and chosen feature/tool selections.
* **Tests**
* Added a focused test suite covering the Data API configuration
decision rules and when the warning should appear.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-07 18:05:19 +00:00
Ali Waseem 3fcf980b0a fix(studio): batch of production Sentry crash fixes (array/null guards) (#47460)
Fixes a batch of production Studio crashes from Sentry (all caught by
the global error boundary). Most are missing array/null guards where an
endpoint typed as an array — or with a nested array field — returned a
non-array body in production; a few are one-off render crashes.

Resolves FE-3748.

## Issues fixed

| Sentry | Error | Fix |
| --- | --- | --- |
| [J7R](https://supabase.sentry.io/issues/7492997940/) | Maximum update
depth exceeded | Disable RadialBar animation in disk-cooldown countdown
|
| [JR5](https://supabase.sentry.io/issues/7548484681/) |
resourceWarnings.find is not a function | Guard in
ResourceExhaustionWarningBanner |
| [JCJ](https://supabase.sentry.io/issues/7506024989/) |
resourceWarnings.find is not a function | Guard in ProjectLayout +
normalize query |
| [K1Y](https://supabase.sentry.io/issues/7584792331/) | snippet.name on
undefined | Optional-chain SQL editor download filename |
| [B3K](https://supabase.sentry.io/issues/7141649636/) |
pagination.count on undefined | Guard pagination in projects infinite
query |
| [JVP](https://supabase.sentry.io/issues/7560437621/) | schemas.some /
extensions.find | Coerce pg-meta lists to arrays in
useInstalledIntegrations |
| [JR2](https://supabase.sentry.io/issues/7548339272/) | extensions.find
is not a function | (same fix as JVP) |
| [JQR](https://supabase.sentry.io/issues/7547163939/) | lints.filter is
not a function | Normalize project lints query |
| [JR3](https://supabase.sentry.io/issues/7548433501/) |
entitlements.find is not a function | Guard call sites + normalize
entitlements query |
| [JQS](https://supabase.sentry.io/issues/7547557098/) |
selected_addons.find is not a function | Normalize addons query arrays |


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved stability across several Studio screens by handling missing
or unexpected data more safely.
* Downloads now use a fallback name when a snippet name isn’t available.
* Project, entitlement, schema, addon, warning, and extension views are
less likely to break when data is missing or not in the expected format.
* Pagination and countdown visuals now behave more consistently, with
reduced chance of runtime errors or animation-related glitches.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
2026-07-02 08:38:17 +00:00
Charis 0abfbdd3d7 fix(studio): preserve session and redirect to MFA when AAL elevation is needed (#47145)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Bug fix.

## What is the current behavior?

`withAuth` calls `signOut()` and redirects to `/sign-in` whenever the
current AAL is below the required level. For IdP-initiated SSO logins —
where the user lands directly on `/dashboard` rather than passing
through `/sign-in-mfa` — this destroys the valid AAL1 session that was
just established. Subsequent mgmt-api requests then return 401
Unauthorized, and the user is dumped on `/sign-in` with no way to
recover except restarting the SSO flow (which loops them back to the
same state).

The platform already returns an actionable `403 Insufficient AAL: MFA
required` on the first mgmt-api request, but the dashboard does not
capture it.

## What is the new behavior?

`withAuth` now distinguishes between "not logged in" and "needs AAL
elevation":

- **Logged in but AAL1** → `router.push('/sign-in-mfa?returnTo=…')`,
session preserved. The existing `/sign-in-mfa` page picks up the
session, renders the MFA form, and bounces the user to `returnTo` after
a successful challenge.
- **Not logged in** → unchanged: `signOut()` then redirect to
`/sign-in?returnTo=…`.
- `/sign-in-mfa` is also added to the "already there, do nothing" guard
so the user isn't re-redirected mid-challenge.

This relies on the gotrue client's local AAL state via
`useAuthenticatorAssuranceLevelQuery`, which fires before any mgmt-api
request, so no fetcher-level error parsing is needed.

## Additional context

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved multi-factor authentication (MFA) elevation flow to preserve
user sessions instead of forcing sign-out and requiring users to restart
sign-in.
  * Fixed unnecessary redirects when users are already on sign-in pages.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-29 13:28:46 -04:00
Gildas Garcia c6fc456910 chore: cleanup duplicate exports studio (#47387)
## 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
2026-06-29 15:46:16 +02:00
Saxon Fletcher 143769afac feat(studio): shared High Availability disabled hook and UI primitives (#47322)
Add generic building blocks for blocking features on High Availability
projects:

- useHighAvailability hook: HA state only (isHighAvailability,
isPending)
- HighAvailabilityDisabledEmptyState (full-page empty state)
- HighAvailabilityDisabledSectionNotice (in-section admonition)

The components carry a generic default title/description; consuming
pages pass their own copy via props. HA state is read from the project's
high_availability flag (same source as the High Availability badge on
the project home page).


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added clearer messaging for features that aren’t available in High
Availability projects.
* Introduced a standard High Availability status check to help the app
adapt what it shows.
* **Bug Fixes**
* Hid non-applicable schema options when High Availability is enabled,
reducing confusion in selection lists.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 16:08:24 +08:00
Gildas Garcia f34aa108d5 chore: dead code cleanup (#47294)
## Problem

There's still more unused code in the repository which slows down
everything:
- checkouts
- tooling
- probably builds (not sure how good turbopack is at handling this)

## Solution

- remove old unused code
- remove more recent code after checking git history to ensure it's not
unfinished/ongoing work

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Removed several unused interface, onboarding, and helper components
from the studio app.
* Cleaned up outdated branching, integrations, query performance,
support, and table/grid UI elements.
  * Removed a few unused utility hooks and key-mapping logic.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-25 12:34:19 +02:00
Joshen Lim fd0f2dd459 Scope last visited organization local storage to profile (#47071)
## Context

If a user switches account without an explicit log out via the
dashboard, landing back on `/org` will redirect users to the last
visited organization as stored in local storage, in which it can result
in the following state if the last visited organization does not exist
in the current account
<img width="2538" height="1060" alt="image"
src="https://github.com/user-attachments/assets/270e482a-3515-48ef-898b-87e76fce80d6"
/>

## Changes involved
Am opting to scope the last visited organization to the user profile
instead - this would be a bit more cleaner than trying to actively clear
the last visited org slug from local storage with implicit account
changes as there's no deterministic way to track that (afaik) from FE
side of things

## To test
Can reproduce the problem as such
- Ensure that you have 2 accounts to log in with, and one account has an
org that the other is not a part of
- For the organization that has the "extra" org, ensure that you click
into it so that the last visited org slug is saved in local storage
- Mimic changing accounts by visiting
`/auth/v1/authorize?provider=github` (using the domain for the env that
you're testing on - e.g localhost:8000 for local, or green for staging
preview)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Unified “last visited organization” handling across the Studio UI with
a shared hook, improving consistency for home/dashboard return,
cancel/back navigation, and account routing.

* **Bug Fixes**
* Updated redirects to only route to an organization when a valid
last-visited value is available; otherwise users go to the general
organizations page.
* Kept MFA enrollment and factor delete/leave flows aligned to the
unified last-visited organization value.

* **Tests**
* Updated onboarding and layout tests to match the new last-visited
organization storage key format and hook/query success behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-18 17:42:18 +08:00
Saxon Fletcher e491182054 Auth flow improvements (#46967)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES/NO

## What kind of change does this PR introduce?

Bug fix, feature, docs update, ...

## What is the current behavior?

Please link any relevant issues here.

## What is the new behavior?

Feel free to include screenshots if it includes visual changes.

## Additional context

Add any other context or screenshots.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Release Notes

* **New Features**
* Added “Continue with {provider}” sign-in and sign-up flows using
enabled external identity providers.
* Enabled inbound branding to focus a specific provider for customized
sign-in/sign-up experiences.

* **Improvements**
* Refined the sign-in options layout and “last used” tracking for
clearer authentication choices.
* Updated account identity/provider connection experiences (link/unlink
and management UI).

* **Bug Fixes**
  * Fixed hydration mismatches in sign-in and password-related layouts.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-06-18 15:34:56 +08:00
Mert YEREKAPAN 2191669d08 feat(studio): add upgrade CTA placement experiment (#45858)
## Summary

Replaces the header upgrade CTA (PR #44494, which design team wanted to
iterate on) with a placement experiment that tests three non-chrome
surfaces for the free-plan "Upgrade to Pro" CTA.

PostHog flag `upgradeCtaPlacement` (free-plan users only) with four
arms:

| Variant | Surface |
| --- | --- |
| `control` | No CTA (baseline cohort, still tracked) |
| `user_dropdown` | Full-width button pinned in the account dropdown |
| `org_projects_list` | Project-card-shaped usage tile, first card in
the org project grid |

## Details

### `user_dropdown`
- Full-width `Upgrade to Pro` button in `UserDropdown`, gated to
org-scoped routes only (`/project/*`, `/org/*`) so the org-billing CTA
never shows on `/account`, `/organizations`, etc. — addresses the scope
concern raised in review.
- Dropdown uses controlled `open` state so it closes before navigation
(it lives in the global layout, so a route change alone wouldn't dismiss
the overlay).


### `org_projects_list`
- `PlanUsageCard` renders as the first `<li>` in the project grid (via
`ProjectList`'s `prependCard`), matching `ProjectCard` shape so it reads
like another project tile. Also renders during the project-list loading
state to avoid pop-in.
<img width="3804" height="1494" alt="Arc 2026-06-08 20 02 54"
src="https://github.com/user-attachments/assets/09c2218c-43d1-49ce-bae7-5075c9750d72"
/>

### Shared card styling
- Metric rows (Egress, Database size, Monthly active users, File
storage) show `current / limit` with a progress ring; ring/value turn
warning at ≥80% and over at ≥100%.
- Rows are clickable deep-links to `/org/[slug]/usage#<anchor>` with a
hover chevron and dashed separators; the same row component is used by
both the embedded and project-card variants.
- Skeleton placeholder renders from first paint so the card reserves
layout while `useOrgUsageQuery` resolves.
- Exposure is fired optimistically while the org query loads (skeleton
shows immediately), but the experiment exposure event only fires once
free-plan is confirmed.

### Telemetry
- `upgrade_cta_clicked` with `placement: user_dropdown | home_usage_card
| org_projects_list`.
- `upgrade_cta_placement_experiment_exposed` with `variant` — the custom
exposure event (snake_case experiment id `upgrade_cta_placement`; the
flag key stays camelCase `upgradeCtaPlacement`).

### Header CTA sunset
- `HeaderUpgradeButton` and its wiring in `LayoutHeader` /
`MobileNavigationBar` removed (master's #46144 already removed the
button; this branch drops the remaining `header_upgrade_cta_clicked`
event).

## Before merging
- [x] Create the `upgradeCtaPlacement` flag + experiment in PostHog (4
variants, free-plan targeting, custom exposure event
`upgrade_cta_placement_experiment_exposed`).
- [x] Archive the now-orphaned `headerUpgradeCta` flag.

## Test plan
- [x] Override the flag per variant via the dev toolbar on staging;
confirm each surface renders and `upgrade_cta_clicked` fires with the
right `placement`.
- [x] `control` shows no CTA but still emits the exposure event.
- [x] Paid-plan org and self-hosted (`IS_PLATFORM=false`) show nothing.
- [x] Clicking a metric row deep-links to the matching usage section;
clicking Upgrade routes to billing.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Experimentally surface an “Upgrade to Pro” CTA in the user dropdown
and on the projects page for eligible free-plan orgs.
* Added a Plan Usage card showing free-plan metrics and upgrade prompts
on the organization projects page; hides when irrelevant or errored.
* Project list and its loading view support inserting a custom/prepend
card in card mode.

* **Telemetry**
* Added tracking for CTA clicks and experiment exposure; placement is
persisted per org.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: kemal <hello@kemal.earth>
2026-06-10 11:20:27 +00:00
Ali Waseem 1c2d28d5b3 chore: wrap local storage into helper methods that are safer (#46628)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

- Noticing our code we have many patterns of calling localstorage and
handling those errors
- We should add those in a single well tested file
- Handle those errors in the singleton which makes it easier for us to
debug customer issues. Logger is outputing local storage warnings for
feature we expose
- Side effect of this is random crashes on studio when local storage
isn't available or handled correctly

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Improved browser storage handling across the app for more reliable
persistence and graceful behavior in restricted or non-browser
environments (settings, previews, charts, tabs, sign-in/session flows,
integrations, and UI state).

* **New Features**
* Introduced a safe storage layer to standardize and harden
local/session persistence.

* **Tests**
  * Added comprehensive tests covering the new safe storage behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-04 07:41:28 -06:00
Jordi Enric a7dda67549 feat(studio): add Multigres logs collection for HA projects (#46499)
## Problem

High availability (Multigres) projects don't expose Multigres service
logs in the Studio logs UI, so users on HA projects have no entry point
to inspect them.

## Fix

Add a `Multigres` logs collection, gated behind the `multigresLogs`
ConfigCat flag **and** the project's `high_availability` flag
(`useShowMultigresLogs`):

- New `Multigres` entry in the logs sidebar `Collections`, linking to a
new `multigres-logs` page that queries the `multigres_logs` table.
- Wire `multigres_logs` through the logs constants, types, table SQL,
query type, and service labels.
- Row formatting: parse the JSON `event_message` and render `level`
through `SeverityFormatter` and `msg` through `TextFormatter`, matching
the other service collections (instead of dumping raw JSON).
- `WARN` severity is now styled like `WARNING` (amber), since Multigres
emits `level: WARN`.
- Log detail drawer: parse the JSON `event_message` and spread its keys
onto the log so each field (level, msg, query, error, connection_id,
etc.) renders as its own collapsible row.
- Single-log query omits the `metadata` column for `multigres_logs` (the
table has no such column), fixing an `INVALID_ARGUMENT` error when
opening the detail drawer.
- Event chart: parse the level out of `event_message` via `JSON_VALUE`
so error/warning bars are counted (the table has no top-level level
column).
- Add the `multigres_logs` source schema to the Field Reference drawer,
same gating.

## Why a feature flag

`high_availability` is an existing product feature that predates
Multigres, so existing HA projects could otherwise see a broken
collection querying a `multigres_logs` table they don't have. Requiring
the `multigresLogs` flag ships the feature dark and decouples rollout
from HA status. The flag must be created in ConfigCat before enabling;
until then `useFlag` returns false and the feature stays hidden.

## How to test

- Enable the `multigresLogs` flag (or override locally) and open a
project where `high_availability` is `true`.
- Navigate to `Logs`. Confirm a `Multigres` entry appears under
`Collections` (after `Replication`).
- Open it: the page loads at `/project/<ref>/logs/multigres-logs` and
queries `multigres_logs`.
- Confirm rows show a colored severity pill (including amber `WARN`) and
a readable message rather than raw JSON.
- Confirm the chart counts error/warning bars correctly.
- Click a row: the detail drawer shows each parsed field as its own row,
with no error.
- Open the Field Reference drawer and confirm `Multigres` is listed as a
source.
- With the flag off, or on a non-HA project, confirm the collection and
Field Reference source are both hidden.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Multigres added as a dedicated log source with its own Logs page,
sidebar entry, and query type.
* Log list and preview now parse Multigres payloads to surface
timestamp, severity, and formatted message.
* Multigres integrated into charting, prompt labels, and field-reference
UI (hidden unless enabled).
* New hook controls showing Multigres UI only when feature flag + HA
project condition are met.
* **Bug Fixes**
  * Severity rendering treats "WARN" the same as "WARNING".
* **Tests**
  * Unit tests added for Multigres parsing and the show-Multigres hook.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-03 12:00:19 +02:00
Pamela Chia 7f5e3cab93 chore(studio): remove expired Fly.io deprecation banner (#46535) 2026-06-01 19:35:14 +08:00
Pamela Chia 47c084e51d refactor(studio): migrate telemetry to useTrack (#46140)
## 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 -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](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 -->
2026-05-27 15:19:54 +08:00
Andrey A. c1b473e472 fix: adjust connect sheet for cli and self-hosted (#46217) 2026-05-25 15:13:25 +02:00
Sean Oliver 2c651ddabc fix(experiment): make dataApiRevokeOnCreateDefault flag reads shape-agnostic (#46289) 2026-05-23 09:30:25 -07:00
Sean Oliver fdceb29260 fix(telemetry): exposure event captures dataApiDefaultPrivileges + drop race-fix hook (#46085)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Bug fix.

## What is the current behavior?

This PR addresses three issues with the implementation of the
`dataApiRevokeOnCreateDefault` experiment
([GROWTH-858](https://linear.app/supabase/issue/GROWTH-858)) on the
frontend side:

1. The `project_creation_default_privileges_exposed` event payload
captures `dataApiEnabled`, which is the parent "Enable Data API" toggle.
That value defaults to `true` for everyone in both arms, which doesn't
help understand how people are interacting with the form.

2. The hook itself was gating on PostHog JS SDK values rather than our
backend server values being sent from `/telemetry/feature-flags`.

3. The form on `/new/[slug]` captures `dataApiDefaultPrivileges`
defaults once at mount via react-hook-form's `defaultValues`. If the
flag is still loading when the page mounts,
`useDataApiRevokeOnCreateDefaultEnabled()` returns `false` (coerced from
undefined), and the form locks the field to the legacy default of
`true`. The flag later resolving has no effect, and treatment users get
the legacy default visually and in the exposure event.

## What is the new behavior?

1. Main-surface payload now sends `dataApiDefaultPrivileges` — the form
field the experiment actually controls (`true` = legacy grants kept,
`false` = revoked on create). Post-fix data will let us read out whether
treatment users actually got the new default.

2. Hook is simplified: drop `orgCountReady`, drop the `onFeatureFlags`
subscription, drop the `posthogClient` import. It now fires once when
the flag resolves, period. Vercel surface is unchanged (still no
`dataApiDefaultPrivileges` since there's no user-facing toggle there).
Tests updated.

3. New useEffect in `/new/[slug]` watches the raw flag value and syncs
`dataApiDefaultPrivileges` to the correct experiment-driven default when
the flag resolves, gated on `getFieldState(...).isDirty` so we don't
clobber intentional user input.

## Additional context

Backend half of this fix is at supabase/platform#32933 (passes
`org_count` and `signup_timestamp` in `personProperties` so the audience
filter actually evaluates correctly). Both PRs are needed for the
experiment to bucket at 5% and be measurable.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Changes**
* Telemetry now records the selected default-privileges setting
(dataApiDefaultPrivileges) in project-creation events; the previous
dataApiEnabled field was removed.
* Project-creation flows apply the experiment-driven default for that
setting once the experiment resolves, but they do not overwrite
user-edited choices. Vercel new-project flow syncs with the experiment
until the user changes the checkbox.

* **Tests**
* Updated tests to validate tracking, deduplication, and sync/timing
behaviors for dataApiDefaultPrivileges.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46085?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 -->
2026-05-19 12:54:36 -07:00
Pamela Chia 0bed80b340 chore(telemetry): clean up frontend event catalog (#45964)
## Summary
Resolves 13 findings (2 HIGH, 5 MEDIUM, 6 LOW) from the frontend
telemetry audit: 1 action-string collision, 1 camelCase experiment name,
9 dead events removed, 4 missing org groups attached, 1 ambiguous
property renamed, 1 raw-string property narrowed, plus consolidations
and a structural tightening on TABLE_EVENT_ACTIONS.

## Changes
### HIGH
- Rename `EventPageCtaClickedEvent.action` to
`www_event_page_cta_clicked` so it no longer collides with the pricing
CTA event (which had a different schema sharing the same action string)
- Snake_case the header-upgrade experiment exposure name
(`headerUpgradeCta_experiment_exposed` →
`header_upgrade_cta_experiment_exposed`); PostHog flag key and
`?source=` URL param unchanged

### MEDIUM
- Remove 4 dead `ProjectCreation*Step*` events (referenced a v2 route
that doesn't exist; 0 emissions)
- Remove 4 dead experiment exposure events:
`ProjectCreationRlsOptionExperimentExposed`, `HomeNewExperimentExposed`,
`TableCreateGeneratePoliciesExperimentExposed`,
`TableCreateGeneratePoliciesExperimentConverted` (0 emissions)
- Attach org group to `dpa_request_button_clicked` (0% had `$group_0`
per Hex)
- Delete `RegisterStateOfStartups2025NewsletterClicked` (interface
naming outlier, 0 emissions, page renamed to 2026)
- Rename `AssistantSuggestionRunQueryClickedEvent.category` to
`mutationType` with tightened literal union (`'functions' |
'rls-policies' | 'unknown'`)
- Attach org group to `project_creation_default_privileges_exposed` on
Vercel surface via explicit `groupOverrides` (auto-injection misses
because `useSelectedOrganizationQuery` is undefined on that page)

### LOW
- Consolidate `IndexAdvisorBannerEnableButtonClickedEvent` +
`IndexAdvisorDialogEnableButtonClickedEvent` into one event with
`origin: 'banner' | 'dialog'`
- Rename `ImportDataFileDroppedEvent` → `ImportDataFileAddedEvent` so
the interface name matches the action and the verb is on the approved
list
- Rename `LogDrainConfirmButtonSubmittedEvent` → `LogDrainRemovedEvent`
and action to `log_drain_removed` (fires on delete-confirm modal,
matches `CronJobRemovedEvent` pattern)
- Add `type` property to `CronJobRemovedEvent` (parsed from the job's
command), matching the create/update event shape
- Tighten `TABLE_EVENT_ACTIONS` values with `satisfies` against the
event union so renames in the union fail typecheck here too
- Attach org group to `www_pricing_plan_cta_clicked` at 5 emission sites
when an org is available in the page context
- Narrow `unified_logs_row_clicked.logType` from raw `string` to the
5-literal `LOG_TYPES` union (zod already validates server values)

### Bundled refactor
Migrated 5 emission sites from deprecated `useSendEventMutation` to
`useTrack` while their containing files were being edited: `DPA.tsx`,
`DisplayBlockRenderer.tsx`, `Grid.tsx` (2 events), `DeleteCronJob.tsx`.
Full sweep of the remaining ~79 files is a separate follow-up.

## Testing

Mostly just renaming of events

## Linear
- fixes GROWTH-798


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
* Standardized telemetry to a unified tracking system for more
consistent analytics.
  * Simplified experiment exposure reporting for upgrade prompts.

* **New Features**
* More granular tracking for CSV import, cron job deletions, log drain
removals, DPA downloads/requests, and pricing CTAs.
  * Assistant now classifies mutation queries more precisely.

* **Bug Fixes**
* Improved default-privileges exposure logic on Vercel deployments
(skips when org missing).

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45964)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-18 18:21:58 +08:00
Gildas Garcia 86a3f8b03d chore: upgrade to react-19 (#45886)
- 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 -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45886)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-15 16:04:41 +02:00
Sean Oliver 4c77ab5fef feat(telemetry): mirror org_count to PostHog person property (#45946)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Feature + two follow-on fixes — small, scoped to telemetry / experiment
plumbing.

## What is the current behavior?

PostHog feature flags evaluated in Studio only have access to the
`gotrue_id` person property (set in `useTelemetryIdentify`) and the
`organization`/`project` group associations from pageviews. Flags can't
target users by org membership without a behavioral cohort, which
refreshes on a ~hourly schedule and lags behind real-time signup state.

This is blocking the rollout of the `dataApiRevokeOnCreateDefault`
experiment ahead of the May 30 default-privileges breaking change — we
need to target brand-new dashboard signups with no prior org membership,
and there's no person property to filter on.

## What is the new behavior?

Three changes, scoped tightly to make experiment targeting reliable for
brand-new signups:

### 1. Mirror `org_count` to a PostHog person property
(`apps/studio/lib/telemetry.tsx`)

The Studio `Telemetry` component now mirrors the user's current org-list
length to a PostHog person property `org_count` via
`posthog.identify(user.id, { org_count })`. The effect:

- Subscribes to `useOrganizationsQuery` (shares the same React Query
cache as `useSelectedOrganizationQuery`, so no extra network requests).
- Dedupes via a ref keyed on `{ userId, orgCount }` so we only call
identify when the value actually changes — handles user-switch
(logout/login as different user with same count) correctly.
- Generic enough to be useful beyond this experiment — analytics
segmentation by org membership, future flags that depend on multi-org
behavior, etc.

### 2. Merge pre-init identify properties
(`packages/common/posthog-client.ts`)

The previous `pendingIdentification` slot was a single-write buffer —
calling `posthogClient.identify()` before the PostHog SDK initialized
would overwrite any prior queued identify. Latent until this PR added a
second identify caller (`org_count`), which exposed the last-write-wins
behavior on first-visitor-before-consent flows. Now merges properties
across pre-init calls for the same user so both `{ gotrue_id }` and `{
org_count }` land on the person record when the SDK flushes. Caught
during Codex review.

### 3. Gate the exposure event on `org_count` being present
(`apps/studio/hooks/misc/useDataApiRevokeOnCreateDefault.ts`)

`useTrackDefaultPrivilegesExposure` previously fired on the first
non-undefined value of the `dataApiRevokeOnCreateDefault` flag. For
brand-new signups, this races the `org_count` identify: the initial
`/flags/` response (before targeting can match) returns the untargeted
variant, the exposure locks it in via `hasTracked`, then our identify
fires and a subsequent `/flags/` refresh updates the flag — but the
exposure has already recorded the wrong variant.

Fix: gate the exposure on `org_count` being present on the SDK person,
subscribing via `onFeatureFlags` so we pick up the post-identify
`/flags/` response. Adds `posthogClient.getPersonProperty` as the
local-state reader. Without this, the experiment would have a ~5-15%
noise floor on cohort assignment for new signups.

## Verification

End-to-end verified locally against the staging PostHog project (34343):

- Local Studio's PostHog SDK has `$stored_person_properties: {
gotrue_id: <uuid>, org_count: 1 }` after sign-in.
- Both `$set` events landed server-side within ~300ms of each other, and
the staging person record now shows `org_count = 1.0` with `gotrue_id`
preserved.
- Targeting query `person.properties.org_count == 1` works end-to-end
against staging.

## Additional context

Ref: [GROWTH-853](https://linear.app/supabase/issue/GROWTH-853)

Targeting plan for the flag once shipped: `person.org_count == 1` plus a
behavioral filter on recent `sign_up` event, at 5% rollout.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Telemetry now records and syncs the user's organization count as an
analytics person property and avoids redundant identifications when
unchanged.
* Analytics client now merges queued identification properties made
before initialization and exposes a method to read stored person
properties.

* **Bug Fixes**
* Tracking now waits for organization-count readiness before firing
certain exposure events to prevent missing data.

* **Tests**
* Added/updated tests to cover person-property behavior and gating
logic.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45946)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-14 12:52:43 -07:00
Pamela Chia e55411da5e feat(studio): Fly.io deprecation banner (#45778)
## Summary

Adding an in-dashboard banner for the Fly.io May 31 suspension. Banner
targets users on a Fly project (or with a Fly project in their
currently-selected org) and surfaces a per-project breakdown of what's
affected in a dialog. Detection is self-correcting: as soon as the user
migrates off Fly, the banner disappears with no follow-up.

<img width="557" height="502" alt="Screenshot 2026-05-11 at 5 08 22 PM"
src="https://github.com/user-attachments/assets/7bafb712-3490-4555-9667-66e9909f1b1a"
/>
<img width="1675" height="536" alt="Screenshot 2026-05-11 at 3 55 06 PM"
src="https://github.com/user-attachments/assets/6c1bf9d1-4dcc-4aac-a679-2ed477d2ed1c"
/>


## Changes

- **Detection hook** (`useFlyDeprecationProjects`): reads only from
already-cached data — `useSelectedProjectQuery` for the current project,
plus `useOrgProjectsInfiniteQuery` scoped to the selected org. Zero
cross-org fan-out: worst case is one paginated query per session (the
same one the project list page already makes).
- **Banner component** (`FlyDeprecationBanner.tsx`): mounted in
`AppBannerWrapper`. Dynamic title (primaries / branches / both), dialog
lists affected projects with org name, numbered migration steps, links
to backup/restore CLI + Dashboard backup + branching docs. List
truncates to 5 entries with "…and N more." tail when more are affected.
- **Telemetry**: `fly_deprecation_banner_exposed` and
`fly_deprecation_banner_dismissed` events emitted via `useTrack`
(auto-injects project + org groups). Properties: `primaryCount`,
`branchCount`. CTA click tracking intentionally omitted — migration
outcome is measured via warehouse `cloud_provider = 'FLY'` decay.
- **LocalStorage**: dated dismissal key `FLY_DEPRECATION_2026_05_31`;
orphan `FLY_POSTGRES_DEPRECATION_WARNING` from PR #33510 removed in the
same change so users who dismissed the Feb 2025 banner still see this
one.
- **Support contact**: email `success@supabase.io` only (no support
ticket link), per Brian's outreach copy in the Linear issues.

## Coverage trade-off

Banner renders on project pages (selected-project check) and pages where
the selected org's projects list is cached (org overview, project list).
It does **not** render on `/dashboard` home or other pages without org
context. Email outreach from GROWTH-817 / GROWTH-819 handles those
users. This was a deliberate trade-off to avoid cross-org fan-out load.

## Lifecycle

Banner expires `2026-06-01T00:00:00Z` (right after the May 31 deadline).
Stale client bundles stop rendering it without a redeploy. Cleanup PR
planned post-deadline to remove the component, hook, localStorage key,
and telemetry events.

## Testing

Tested on the Vercel preview with React Query cache overrides to mock a
Fly project:

- [x] Banner renders for a user with at least one project where
`cloud_provider === 'FLY'`
- [x] Banner does **not** render for a user with no Fly projects
- [x] Banner does **not** render on `/sign-in`
- [x] Title varies by primaries-only / branches-only / both
- [x] Dialog lists affected projects with org name in parens
- [x] Dialog list truncates to 5 with "…and N more." for larger sets
- [x] Migration guide / Dashboard backup / branching links open in a new
tab
- [x] Dismiss (×) closes the banner and persists across hard reload
(localStorage `fly-deprecation-2026-05-31-dismissed`)
- [x] PostHog receives one `fly_deprecation_banner_exposed` per mount
with `primaryCount` + `branchCount` and `$groups.organization` populated
- [x] PostHog receives one `fly_deprecation_banner_dismissed` on close
with the same property shape

## Linear

- fixes GROWTH-817
- fixes GROWTH-819
2026-05-12 02:24:47 +08:00
Alaister Young d676c832f3 fix(studio): pre-empt React 19 regressions in tests + Support form (#45784)
Four React-19-sensitive patterns that pass on React 18 today but break
under React 19 (verified on the in-flight TanStack Start branch).
Landing on master now so the eventual React 19 upgrade is a no-op for
tests, instead of a separate cleanup pass under upgrade pressure.

Each fix is a strict superset / less-fragile equivalent of the existing
pattern, so master (React 18) stays green.

**Changed:**
- `hooks/misc/useStateTransition.ts` — fire on entry into `newTest` from
any state other than `newTest`, instead of requiring exactly `prevTest →
newTest`. React 18+ auto-batches dispatches across awaits (e.g.
`dispatch SUBMIT` in the handler, `dispatch ERROR` in `onError`),
collapsing `editing → submitting → error` into a single render where the
intermediate `submitting` tick is never observed. Strict superset of the
old check for our reducers — `success`/`error` are only reachable from
`submitting`.
- `Support/CategoryAndSeverityInfo.tsx` — guard `onValueChange` against
Radix Select's spurious `''` emission. When the controlled value
transitions from `undefined` to a defined value whose `SelectItem` isn't
mounted yet (dropdown closed → items haven't registered), Radix's hidden
`BubbleSelect` fires `onValueChange('')` and clobbers the field. No
`SelectItem` can have `value=""` (Radix throws), so any `''` is
guaranteed spurious — drop it before calling `field.onChange`.
([radix-ui/primitives#3381](https://github.com/radix-ui/primitives/issues/3381))
- `EditSecretModal.test.tsx` — `getByLabelText` → `findByLabelText`.
Under React 19's scheduling, the decrypted-value query resolves on a
separate render tick, so form fields appear one tick after the skeleton.
- `LogsPreviewer.test.tsx` — `addEventListener('click', spy)` instead of
`loadOlder.onclick = vi.fn()`. React 19 reassigns `.onclick` on managed
elements as part of its event wiring, clobbering the direct-property
spy.

## To test

### Unit tests
- `pnpm --filter studio test` — all unit tests pass on master (React 18)

### Support form URL prefill (Radix Select guard)
- `/support/new?category=Problem` → category dropdown reads "APIs and
client libraries" on first paint
- `/support/new?category=dashboard_bug` → "Dashboard bug"
(case-insensitive match)
- `/support/new?category=invalid_garbage` → falls back to "Select an
issue" placeholder, no crash
- `/support/new?subject=My%20issue&message=Details%20here` → subject and
message inputs are prefilled
- `/support/new?projectRef=<your-ref>&category=Problem` → both project
selector and category set, library selector appears
- With a prefilled URL, click the category dropdown and pick a different
option — the new value sticks (this is the path that surfaced the Radix
bug, want to confirm we didn't break user selection)
- DevTools console on first load should be clean — no React hydration
mismatch warning

### Support form submit (`useStateTransition` success + error branches)
- Submit a valid support form → green toast "Support request sent"
appears **once**, view swaps to the success screen, one `POST
/platform/feedback/send` in the network panel
- Block `POST /platform/feedback/send` in DevTools → submit → red error
toast appears **once** (not twice — if you see two toasts the relaxed
transition is firing more than it should), form stays editable with all
inputs preserved
- Unblock and submit again → success path runs cleanly

### Sidebar support form (same reducer + `useStateTransition`, separate
component)
- Open the support widget in the side nav (`SupportSidebarForm`)
- Repeat the success and error paths — should behave identically

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed category selector to prevent selected values from being
unexpectedly cleared during form interactions.

* **Tests**
* Improved test reliability for modal field rendering and event handling
assertions.

* **Chores**
  * Clarified internal comments for form initialization logic.

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45784)

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-05-11 21:56:51 +08:00
Saxon Fletcher 4452e0ac2e Support form sidebar (#45203)
Refactors our help sidebar within Studio to include the actual support
form itself when contact is selected. This PR also cleans up the initial
state of the sidebar and the options within.

## To test:
- Open an org and click the help icon top right
- Click contact support
- Submit a support ticket
- Click done to return to support sidebar state

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Support form V3 and support sidebar with status button; direct-email
helper and URL prefill
* Success screen supports onFinish callback and customizable finish
label
* AI Assistant and Help options accept optional click callbacks;
resource items gain keyboard/accessibility support

* **Refactor**
  * Help panel split into home/support views with back navigation
* Support components accept flexible align/className props and
layout/styling tweaks
  * Initial URL params loader added for support form

* **Tests**
* New/updated tests for support flows, success screen, and help options
interactions
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
2026-05-08 13:51:49 +10:00
Sean Oliver b14ecb5b1e fix: align grace-period banner copy on org usage page (#45652)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Bug fix — copy + visibility logic on the org Usage page.

## What is the current behavior?

On `/org/<slug>/usage` during a grace period, customers see two banners
that read as contradictory:

1. *"Organization plan has exceeded its quota — grace period until
{date}."*
2. *"You have not exceeded your Pro Plan quota in this billing cycle."*

<img width="1680" height="372" alt="image"
src="https://github.com/user-attachments/assets/13826260-55dd-4b55-a3dc-5afc51e6436e"
/>

Both are individually correct. The first is sticky from the previous
cycle's overage (`org.restriction_status`); the second is a live scan
over the current cycle. Neither anchors to which cycle it's talking
about, so together they read like the dashboard contradicting itself.
Surfaced by support off SU-368527 and SU-368395.

## What is the new behavior?

- Top chrome banner copy: *"Organization exceeded its quota in the
previous billing cycle / You have a grace period until {date} to bring
usage back under quota."*
- Inline `<Restriction />` grace-period alert switches from "is over its
quota" to "went over its quota in the previous billing cycle." Same
temporal anchor.
- The "…in this billing cycle" summary line in `<TotalUsage>` is hidden
whenever `restriction_status` is set. Mirrors the precedence rule
`<Restriction />` already applies internally — backend status flag wins
over the live cycle scan.

<img width="1678" height="937" alt="CleanShot 2026-05-06 at 12 58 02"
src="https://github.com/user-attachments/assets/df55eaed-1029-4f39-bea0-df77bcc5151e"
/>


## Additional context

Left the `gracePeriodOver` copy alone on purpose — it doesn't make a
current-overage claim, so there's nothing to contradict, and adding
"previous cycle" would muddy which cycle "previous" refers to.

**Verified**
- Lint and typecheck pass on `apps/studio`.

**Before merge**
- [ ] Load a grace-period org locally: confirm new copy on top banner
and inline `<Restriction />`, and that the "not exceeded in this billing
cycle" line is gone.
- [ ] Copy review with support — happy to workshop wording.

GROWTH-823

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Updates**
* Updated grace period alert messaging to clarify organization quota
status
  * Refined date formatting in billing restriction notifications
* Modified usage display to conditionally hide certain information when
account restrictions are active

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-05-07 15:46:22 -07:00
Inian e61853c59c fix(studio): clarify default privileges toggle covers tables (#45458)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Updated UI labels and descriptions across the Data API settings to
clarify that default privileges apply to new tables only (removed
references to functions).

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-04 11:35:02 +02:00
Joshen Lim 7f5865872a Enforce noUnusedLocals and noUnusedParameters in tsconfig.json + fix all related issues (#45264)
## Context

Enforce `noUnusedLocals` and `noUnusedParameters` in tsconfig.json + fix
all related issues
2026-04-27 17:42:34 +08:00
Alaister Young 75e08577c1 chore(studio): remove tableEditorApiAccessToggle flag (#45081)
Cleans up the `tableEditorApiAccessToggle` PostHog flag now that the
gated UI is shipping to everyone. Follow-up to #45034 — the new
project-creation checkbox makes the management UI a prerequisite, so no
reason to keep it behind a flag.

**Removed:**
- `useDataApiGrantTogglesEnabled` hook
- Old schemas-only multi-selector branch in the Data API settings page
(the rich per-table / per-function toggles + default-privileges switch
become the only UI)
- Flag gate around the `<ApiAccessToggle>` section in the table editor
side panel
- Flag gates around `updateTableApiAccess` calls in the save pipeline
(create / duplicate / update)
- `tableEditorApiAccessToggleEnabled` telemetry property + stale JSDoc /
docs references

**Changed:**
- `createTableApiAccessHandlerParams` no longer takes an `enabled` param
— it was always `true` after removal

## To test

- Integrations → Data API settings page: exposed tables, exposed
functions, default-privileges toggle all render and save correctly
- Table editor: creating, duplicating, and editing a table all run the
expected Data API privilege updates
- Project creation flow still works end-to-end (unchanged, but the
submit telemetry no longer includes `tableEditorApiAccessToggleEnabled`)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Improvements**
* API access configuration is now always available in the table editor
and PostgreSQL settings, removing previous conditional gating.
* Simplified the "Automatically expose new tables and functions"
interface by consolidating UI branches.

* **Documentation**
* Updated telemetry guidance and examples with current feature-flag
references.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-04-22 21:37:48 +08:00
Alaister Young d1a7d64e63 [FE-3023] feat(studio): default privileges toggle at project creation (#45034)
<img width="783" height="414" alt="Screenshot 2026-04-20 at 3 02 37 PM"
src="https://github.com/user-attachments/assets/a353c35a-3de5-4bfa-ab31-829c79c43165"
/>

Adds a "Default privileges for new entities" checkbox under "Enable Data
API" in both the main create flow and the Vercel deploy-button flow.
Default checked (current behaviour). When unchecked, runs
`buildDefaultPrivilegesSql('revoke')` after the base init script so new
entities in `public` aren't auto-granted to `anon` / `authenticated` /
`service_role`.

This PR decouples the two surfaces:

- **`tableEditorApiAccessToggle`** — unchanged; still gates only the
integrations → Data API settings UI.
- **`dataApiRevokeOnCreateDefault`** (new) — controls only the default
state of the new checkbox at project creation. `true` → checkbox
unchecked by default (revoke runs); `false`/absent → checkbox checked by
default (no behaviour change).

The new flag is already live in PostHog at **0% rollout, off for
everyone**, so shipping this PR changes nothing until the flag is
explicitly flipped.

## Added

- `apps/studio/hooks/misc/useDataApiRevokeOnCreateDefault.ts` — reads
the new PostHog flag. Returns `false` in `IS_TEST_ENV` so existing E2E
flows don't silently change default behaviour.
- Checkbox UI in `SecurityOptions.tsx` (main flow) and
`pages/integrations/vercel/[slug]/deploy-button/new-project.tsx` (Vercel
flow), with copy matching the integrations → Data API settings page.
- Tooltip + dimmed state for the main-flow checkbox when "Enable Data
API" is unchecked (can't configure default privileges if Data API is
off).
- Telemetry: `dataApiDefaultPrivilegesGranted` (raw checkbox value) and
`dataApiRevokeOnCreateDefaultEnabled` (raw flag, conditionally included
using the existing raw-flag pattern so undefined flag state → omitted
property, not `false`).
- Vitest unit tests for the new hook.

## Changed

- `pages/new/[slug].tsx`: removed the `false &&` rollback guard. Revoke
SQL now runs only when `dataApi && !dataApiDefaultPrivileges`. Dropped
the now-unused `useDataApiGrantTogglesEnabled` import.
- `pages/integrations/vercel/[slug]/deploy-button/new-project.tsx`: this
flow was **never rolled back** — it still ran revoke whenever
`tableEditorApiAccessToggle` was on for a user. Now correctly gated on
the new flag + checkbox state.
- `packages/common/telemetry-constants.ts`: added the two new properties
and corrected the `tableEditorApiAccessToggleEnabled` docstring (it no
longer claims to control project-creation revoke behaviour).

## Kill switch

Flipping `dataApiRevokeOnCreateDefault` to off in PostHog fully disables
the revoke SQL for new projects without needing a redeploy — the
checkbox just defaults to checked again.

## Follow-ups (not blockers)

- joshenlim's review comments on PR 43704: (1) Auth Policies table row
incorrectly showing "exposed via Data API" based on schema-level check
instead of table-level at
`apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/index.tsx:64`;
(2) Data API integrations page showing zero exposed tables even after
exposing one. Both unrelated to this PR but will be more visible once
the checkbox lands.
- Once this flag fully rolls out, the old `tableEditorApiAccessToggle`
docstring/comments elsewhere should stop claiming it controls project
creation.

## To test

- **Flag off (default state, simulates post-merge):** create a project
with and without "Enable Data API" checked. The new "Default privileges
for new entities" checkbox should default to **checked**. Submitting
should produce an identical result to today — new tables in `public` are
reachable via the Data API.
- **Flag on (simulate rollout):** override the flag locally. The
checkbox should default to **unchecked**. Creating a project with it
unchecked should run the revoke SQL; create a new table in `public`
afterwards and confirm it's not reachable via the Data API until grants
are added.
- **Enable Data API off:** the new checkbox should render disabled +
dimmed with a tooltip reading "Enable the Data API to configure default
privileges." The revoke SQL should not run in this case regardless of
checkbox state.
- **Vercel flow:** repeat at
`/integrations/vercel/<slug>/deploy-button/new-project` — verify both
checkbox states.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added an "Automatically expose new tables and functions" checkbox to
project creation and Vercel deploy flow; enabled only when Data API is
available (disabled with tooltip otherwise) and affects initial project
provisioning.

* **Telemetry**
* Tracks exposure of the default-privileges control and includes
checkbox state and feature-flag status on project-creation submissions.

* **Tests**
* Added tests for flag behavior, exposure tracking, deduplication, and
submission telemetry.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Sean Oliver <882952+seanoliver@users.noreply.github.com>
2026-04-21 13:15:40 +08:00
Alaister Young 19027e73f8 [FE-3036] feat(studio): runtime env var overrides for enabled features (#45049)
Lets self-hosted Studio toggle flags in `enabled-features.json` at
container start time via `ENABLED_FEATURES_*` env vars, without
rebuilding the prebuilt image. Addresses
[FE-3036](https://linear.app/supabase/issue/FE-3036/allow-enabled-featuresjson-flags-to-be-overridden-via-env-vars)
and is a prerequisite for
[COM-205](https://linear.app/supabase/issue/COM-205/add-feature-flag-to-disable-all-logs-in-studio).

**Added:**
- `packages/common/enabled-features/overrides.ts` — pure parser that
maps `ENABLED_FEATURES_*` env vars to a disabled-features list
(forward-only key mapping, boolean validation, typo warnings) + 10
vitest tests
- `apps/studio/pages/api/enabled-features-overrides.ts` — Next.js API
route reading `process.env` at request time; no-op (`{
disabled_features: [] }`) when `IS_PLATFORM`
- `apps/studio/data/misc/enabled-features-override-query.ts` — React
Query hook with `staleTime: Infinity`, `enabled: !IS_PLATFORM`
- `packages/common/enabled-features/README.md` — docs the env var
convention, resolution order, `IS_PLATFORM` gating, and the
`Support.constants.ts` build-time caveat

**Changed:**
- `apps/studio/hooks/misc/useIsFeatureEnabled.ts` — merges the
override's `disabled_features` with `profile.disabled_features`

### Env var shape

One var per flag, prefixed `ENABLED_FEATURES_`. Feature key → env name:
uppercase with every non-alphanumeric char replaced by `_`.

```bash
ENABLED_FEATURES_LOGS_ALL=false
ENABLED_FEATURES_BRANDING_LARGE_LOGO=true
```

Values are `true`/`false` case-insensitively. Other values and prefixed
vars that don't match a known feature are logged and ignored.

### Resolution order (runtime, Studio only)

1. `ENABLED_FEATURES_*` (self-hosted, via API route → React Query →
hook)
2. `profile.disabled_features` (hosted, from `/platform/profile`)
3. `enabled-features.json` static value
4. Default (enabled)

`ENABLED_FEATURES_OVERRIDE_DISABLE_ALL` still short-circuits everything.

### Known limitation

`apps/studio/components/interfaces/Support/Support.constants.ts:4` calls
`isFeatureEnabled('billing:all')` at module load to build
`CATEGORY_OPTIONS`, which is spread into Zod form schemas. That call
site stays resolved from the JSON — documented in the package README.
`billing:all` isn't on the radar for self-hosted runtime toggling.

## To test

- `cd packages/common && pnpm exec vitest run enabled-features` — 10 new
tests pass
- `pnpm --filter studio run typecheck` clean
- Spin Studio locally with `NEXT_PUBLIC_IS_PLATFORM=false` and
`ENABLED_FEATURES_LOGS_TEMPLATES=false`;
`/project/[ref]/logs/explorer/templates` should reflect the flag after
the override fetch resolves
- Confirm the API route returns `{ disabled_features: [] }` when
`NEXT_PUBLIC_IS_PLATFORM=true`
- Set a typo like `ENABLED_FEATURES_LOGS_TMEPLATES=false` and check the
warning in container logs; flag stays enabled

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Runtime feature-flag overrides for self-hosted deployments (env var
driven), new API endpoint and client-side hook to fetch overrides, and
client logic now merges profile and runtime overrides.

* **Documentation**
* Added comprehensive README describing the feature-flag system and
override configuration.

* **Tests**
* Added unit tests for override parsing and E2E tests covering runtime
override behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-04-20 22:28:56 +08:00
Danny White 2349f76e18 fix(studio): guard no-op advisor dismissal localStorage updates (#45031)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Bug fix.

## What is the current behavior?

Advisor dismissals use `useLocalStorageQuery`. When advisor signals
pruning ran, it sometimes invoked `setDismissedKeys` even when nothing
needed to change (no-op updater returning the same array reference).

Separately, `useLocalStorageQuery` would still persist +
`invalidateQueries` even when the computed next value was
reference-equal to the current cached value.

When `useAdvisorSignals` is mounted in two places at once
(`AdvisorSection` + `AdvisorPanel`), those redundant invalidations /
subscriber churn could occasionally cascade into React’s “Maximum update
depth exceeded” error (often surfaced via Radix `composeRefs` in stack
traces). CI saw this as an unhandled error during
`AdvisorSignals.integration.test.tsx`.

## What is the new behavior?

- `useLocalStorageQuery` now **early-returns** when `Object.is(next,
current)` so no-op updates don’t write localStorage or invalidate the
query.
- `useAdvisorSignals` pruning effect now **short-circuits** unless there
is actually a stale banned-IP dismissal to remove.

## Additional context

Follow-up from #44372 (advisor signal items for banned IPs).

Tests run locally:

- `pnpm --filter studio exec vitest run
components/ui/AdvisorPanel/useAdvisorSignals.test.tsx
components/ui/AdvisorPanel/AdvisorSignals.integration.test.tsx
hooks/misc/__tests__/useLocalStorageQuery.test.ts`


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Enhanced handling of dismissed security alerts by preventing
unnecessary state updates for stale dismissals, significantly reducing
overhead and improving overall application performance.
* Optimized local storage operations to skip redundant writes to storage
and prevent triggering unnecessary cache updates and query invalidations
when stored data values remain unchanged from the previous operation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-20 18:41:32 +10:00
Danny White b721a2d780 feat(studio): advisor signal items for banned IPs (#44372)
## What kind of change does this PR introduce?

Feature. Resolves DEPR-430.

## What is the current behaviour?

The homepage Advisor summary, shared Advisor panel, and top-nav Advisor
indicator only surface lints and notifications. Banned IPs are not
represented as dismissible Advisor items, so network bans are easy to
miss unless a user visits Database Settings directly.

The `public bucket allows listing` warning is no longer part of this PR.
That warning will move to a follow-up Splinter `WARN` lint so it can
flow through the standard lint surfaces instead of a bespoke Studio
signal path.

## What is the new behaviour?

- adds a new Advisor `signal` source for banned IPs on the platform
homepage, in the shared Advisor panel, and in the top-nav Advisor
indicator
- keeps dismissals client-side only for now, scoped by project and exact
IP fingerprint
- keeps banned IP signals at `warning` severity because they still
indicate suspicious traffic and remain actionable if a user wants to
review or remove a ban
- leaves `/project/[ref]/advisors/security` as follow-up work because
that surface is still lint-native, and banned IPs are management-plane
signals rather than Splinter lints

| After |
| --- |
| <img width="1728" height="997" alt="Mallet Toolshed
Supabase-65A60B4A-107E-4D79-B9A8-23F754BEAB08"
src="https://github.com/user-attachments/assets/c08ecbbb-c302-43bd-81bb-6ba7eb18b7b3"
/> |

## Reviewer testing notes

1. Use a throwaway project.
2. Get the database connection string for that project.
3. Attempt to connect with the wrong password 3-4 times until you hit an
`ECONNREFUSED`-style error, which should mean your IP has been banned.
4. Refresh Studio and confirm the project overview shows the new `Banned
IP address` signal.
5. Open the Advisor Center and confirm:
   - the top-nav Advisor dot turns warning yellow
   - the signal detail shows `Entity`, `Issue`, and `Resolve`
   - `Edit network bans`, `Dismiss`, and `Learn more` are present
6. Open Database Settings > Network bans and confirm your banned IP
appears there and can be unbanned.
7. Note that `/project/[ref]/advisors/security` will not show this item.
That page is still lint-only, and this banned IP work is a short-term
client-side signal rather than a true lint.

Longer term, we likely want a more durable event model here so banned
IPs can power notifications, webhooks, emails, and other project-level
alerts.

---------

Co-authored-by: kemal <hello@kemal.earth>
Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-04-20 10:33:56 +10:00
Alaister Young dd41a34706 [FE-2478] feat(studio): simplify Connect modal for HA projects (#44695)
Simplify the Connect modal for Multigres/High Availability projects.
Pooling is always on for these projects, so the connection method
distinction doesn't apply.

**Removed:**
- Connection Method selector (Direct/Transaction/Session) for HA
projects
- IPv4 add-on panel for HA projects
- Pooler badge (Shared/Dedicated) for HA projects

**Changed:**
- "Type" label renamed to "Connection Type" for HA projects
- Default connection method set to `transaction` (instead of `direct`)
for HA projects

Non-HA projects are completely unaffected.

## To test

- Open Connect sheet → Direct tab on a **non-HA project** — verify
everything looks the same as before
- Open Connect sheet → Direct tab on an **HA project** — verify:
  - No Connection Method radio selector
  - Label reads "Connection Type" instead of "Type"
  - No IPv4 status panel
  - No pooler badge
  - Connection string displays correctly

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Improvements**
* Connection UI now adapts for high-availability projects: hides pooler
options and IPv4 status, and updates the connection type label for
clarity.

* **Tests**
* Added tests covering connection configuration behavior when a project
is high-availability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-04-10 17:16:29 +09:00
Danny White 73692b0a4d feat(studio): add stuck pausing and restoring escalations (#43368)
## What kind of change does this PR introduce?

Bug fix / UX improvement for long-running project transitions. Resolves
DEPR-362.

## What is the current behaviour?

- `PausingState` does not preserve elapsed time across refreshes, so the
stuck escalation can disappear for the same user.
- `RestoringState` relies on weaker frontend heuristics and always
showed a support CTA in the footer even before the restore was clearly
long-running.

## What is the new behaviour?

- `PausingState`
- Persists a per-project pause start time in local storage so the stuck
CTA survives refreshes in the same browser.
  - Escalates after 10 minutes.
  - Clears the stored timer when pausing succeeds or fails.

- `RestoringState`
- Persists a per-project restore start time in local storage so the
stuck CTA survives refreshes in the same browser.
- Removes the always-visible footer CTA and only escalates once
restoration is genuinely long-running.
- Computes the long-running threshold from volume size using a shared
restore estimate: `max(10, ceil(estimateRestoreTime(sizeGb) * 1.5))`.
  - Clears the stored timer when restoration succeeds or fails.

- Shared changes
- Extracts reusable transition timing helpers and restore estimate
helpers with unit tests.
- Reuses the same restore estimate formula for branch restore timing and
restore escalation, so the two do not drift.

| `PausingState` | `RestoringState` |
| --- | --- |
| <img width="1570" height="906" alt="Krosno Toolshed
Supabase-C6D7E29F-C38D-43E1-8AF9-C612B6A2FD8D"
src="https://github.com/user-attachments/assets/e0bd9434-09b6-4cf6-bffa-07a0ddcdf5db"
/> | <img width="1570" height="906" alt="Krosno Toolshed
Supabase-51F4763D-B798-4B41-A92D-43B3CF8ECDAF"
src="https://github.com/user-attachments/assets/d0e47356-dcc3-42aa-b602-802a35249a16"
/> |

## Additional context

- This PR intentionally stays frontend-only.
- We are not exposing backend lifecycle timestamps here; local storage
is the stopgap to improve the same-browser experience now.
- If you need to test the frontend blocker states locally, use
[`dnywh/chore/depr-362-blocker-preview-mocks`](https://github.com/supabase/supabase/tree/dnywh/chore/depr-362-blocker-preview-mocks)
and append one of the following query params to a project URL:
  - `?mockProjectBlockingState=pausing`
  - `?mockProjectBlockingState=pausing-long-running`
  - `?mockProjectBlockingState=restoring`
  - `?mockProjectBlockingState=restoring-long-running`
- I know these two views are quite differently stylistically, and will
consolidate later
  - References DEPR-434
2026-04-02 11:09:18 +11:00
Charis 180ce515f6 style: require @ imports and sort imports for studio/hooks (#44444)
* **Chores**
* Updated internal module import paths across hook files to use
standardized path aliases for improved code consistency and
maintainability.
2026-04-01 11:48:02 -04:00
Ali Waseem dcab88059b fix: minor sentry issues (#44148)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

fixes: 

-
[SUPABASE-APP-ER2](https://supabase.sentry.io/issues/7360649020/?project=5459134)

-
[SUPABASE-APP-ERM](https://supabase.sentry.io/issues/7361072759/?project=5459134)

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-03-25 16:07:49 +08:00
Jordi Enric 2e1795dfa0 feat(studio): add pagination to query performance page FE-2774 (#43697)
## Problem

The Query Performance page loaded all results in a single query with a
fixed limit of 20 rows, giving users no way to browse beyond the first
page. There was also no way to control how many rows were shown at once.

## Fix

adds pagination 

## How to test

- Navigate to `/observability/query-performance` in Studio
- scroll to bottom
- should automatically load more results

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 15:27:43 +01:00
Jordi Enric 4336c8cf5a fix(observability): use 30m step for 7-day dashboard to preserve spikes FE-2813 (#43998)
## Problem

The database observability dashboard flattens critical spikes when
viewing the 7-day window. A spike clearly visible at the 3-hour view
(2-minute resolution) disappears completely at the 7-day view because
the Prometheus query step was 1 hour, averaging each spike into a
60-minute bucket and reducing its apparent magnitude to near zero.

## Fix

Increase the granularity in the 7 day window to prevent spikes from
being flattened.
Data point counts: 7-day view goes from ~168 to ~336 points per series,
more consistent with the existing 12-hour view (~360 points).

## How to test

- Open the observability database dashboard for a project that has had a
recent CPU, RAM, or connection spike
- Select the "Last 3 hours" time window and confirm the spike is visible
- Switch to "Last 7 days" and confirm the same spike is now visible
(previously it would disappear)
- Confirm all other time windows (10m, 30m, 1h, 24h) still load and
display correctly

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 09:04:28 +01:00
Ivan Vasilov 9fa96977be chore: Minor prettier fixes (#43849)
This PR fixes some prettier issues:
- Bump and unify all prettier versions to 3.7.3 across teh whole repo
- Bump the SQL prettier plugin
- When running `test:prettier`, check `mdx` files also
- Run the new prettier format on all files

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-03-17 11:17:42 +01:00
Kanishk Dudeja 83592b1932 feat(billing): show billing address modal for paid orgs with missing address (#43480)
### Summary

This PR adds a dismissable modal that prompts paid org users to fill in
their billing address. We need billing addresses for tax compliance and
the existing banner hasn't been as effective (~10k orgs still missing).

The modal shows on page load when all of these are true:

- ConfigCat flag `enableBillingAddressModal` is on
- Org is on a paid plan (not free)
- Org does not have billing address set
- Org is not partner-managed
- User has BILLING_WRITE permission on stripe.customer

The modal can be dismissed via the close button, but re-opens on every
page navigation.

Once the user saves a valid address, the organizations query is
invalidated and organization_missing_address flips to false - the modal
stops appearing permanently.

<img width="1256" height="703" alt="Screenshot 2026-03-05 at 4 22 11 PM"
src="https://github.com/user-attachments/assets/57e7d1b8-b3b6-4366-ad23-60910a0defe8"
/>

### Testing

#### Automated Tests

I've added unit tests in this PR

#### Manual testing

Manual test cases:

- Free org - modal does not appear
- Partner-managed org - modal does not appear
- User with "developer role" modal does not appear
- Configcat Flag disabled - modal does not appear
- Dismiss modal, navigate to another page - modal re-opens
- Fill form and save - modal closes and does not reappear
- API failure loading billing data - shows error state with Retry button

---------

Co-authored-by: Ignacio Dobronich <ignacio@dobronich.com>
2026-03-13 09:33:09 -03:00
Jeremias Menichelli b2fdc7687f feat: Implement telemetry on Search commands (#43563) 2026-03-12 14:34:55 +01:00
Sean Oliver 0aa23980bb remove tableCreateGeneratePolicies experiment (failed variant) (#43498)
## Problem

The `tableCreateGeneratePolicies` A/B experiment tested an AI-assisted
policy generator (`RLSManagement`) as a variation in the table creation
side panel. The variation didn't pass — control wins, so the standard
RLS checkbox should be the permanent behavior.

## Changes

- Deleted `useTableCreateGeneratePolicies` hook (PostHog flag + exposure
tracking)
- Deleted the entire `RLSManagement/` component directory (variation UI
— `RLSManagement`, `PolicyList`, `PolicyListEmptyState`,
`ToggleRLSButton`)
- Removed experiment flag checks from `TableEditor.tsx` — RLS checkbox
is now always rendered (was already the control)
- Removed experiment conversion tracking from `SidePanelEditor.tsx`

## Testing

Verified `pnpm typecheck` passes clean. Table creation side panel
renders the RLS checkbox unconditionally as it did in the control.

GROWTH-653
2026-03-09 09:23:50 -07:00
Ignacio Dobronich ebec20f542 chore: prevention of used leaked passwords entitlement (#43410)
### Changes
- Replaces the isPaid plan-based check on the "Prevent use of leaked
passwords" (PASSWORD_HIBP_ENABLED) setting with a proper entitlement
check using the `password_hibp` entitlement key
- Adds a new `useHasEntitlementAccess` hook that returns a reusable
checker function for any entitlement key, backed by the same cached
entitlements query


### Testing
- Head to `/project/_/auth/providers?provider=Email` with an Org on the
Free Plan
- Assert that the "Prevent use of leaked passwords" toggle is disabled.
- Head to `/project/_/auth/providers?provider=Email` with an Org on the
Pro Plan
- Assert that the "Prevent use of leaked passwords" toggle is enabled
and can be toggled and saved.

<img width="612" height="496" alt="image"
src="https://github.com/user-attachments/assets/fc1ccc79-016c-4265-96ac-bdb458d2a8de"
/>
2026-03-06 11:17:57 -03:00
Ignacio Dobronich 9f8536584c chore: remove maybeShowUpgradePrompt for entitlement-based gate (#43457)
### Changes
- Remove maybeShowUpgradePrompt (plan-based) in favor of
maybeShowUpgradePromptIfNotEntitled (entitlement-based)
- Replaced the `maybeShowUpgradePrompt` with a `hasAccessToHelper`
callback to default the date selection to a safe default so pages don't
load with an out-of-range date.

### Testing

- With an Org on the Free Plan, head to
`/project/_/observability/api-overview?its=2026-03-04T15:06:50.704Z&ite=2026-03-20T15:06:50.704Z`.
Notice that the end date in the URL is 16 days after the start date.
- Assert that the actual range defaults to the entitled range of 1 day.

<img width="467" height="483" alt="image"
src="https://github.com/user-attachments/assets/e17c6957-3ece-4956-87aa-30cf62c84acd"
/>
2026-03-05 19:25:47 -03:00
Joshen Lim ddd94a9c24 Joshen/fe 2660 clean up stale feature flags enabled for 2 months part 2 (#43331)
## Context

Follow up from https://github.com/supabase/supabase/pull/43329, but
mutually exclusive

Just cleaning up feature flags that have been toggled on for all users
and unchanged for the past 2 months

- edgefunctionreport
- storagereport
- realtimeReport
- postgrestreport
- authreportv2
- newEdgeFunctionOverviewCharts
- apiReportCountries (Already not used)
- SentryLogDrain
- reportGranularityV2
- storageAnalyticsVector
- ShowIndexAdvisorOnTableEditor
2026-03-04 13:25:01 +08:00
Danny White 22ff9b2d81 chore(studio): session expired dialog (#43122)
## What kind of change does this PR introduce?

UI improvement

## What is the current behavior?

The session expired dialog is quite hard to parse when, for most people,
the ask is simple.

## What is the new behavior?

Improved session expired dialog:

- Refactored to use AlertDialog
- Clarified copywriting
- Uses the new AlertCollapsible to hide all the complicated debugging
steps under a toggle
	- This component is documented in the design-system

| Before | After |
| --- | --- |
| <img width="1024" height="563"
alt="Supabase-B1728A05-DDD2-4A50-AED4-D62EAA2E7D7C"
src="https://github.com/user-attachments/assets/771f85d8-21ea-42b5-99f5-b9b05f5617dd"
/> | <img width="1024" height="563" alt="Storage Supabase"
src="https://github.com/user-attachments/assets/b2fcab68-fb29-4cb9-bd42-aecc57b9fa32"
/> |
| <img width="1024" height="563"
alt="Supabase-B1728A05-DDD2-4A50-AED4-D62EAA2E7D7C"
src="https://github.com/user-attachments/assets/771f85d8-21ea-42b5-99f5-b9b05f5617dd"
/> | <img width="1024" height="563" alt="Storage Supabase"
src="https://github.com/user-attachments/assets/babd3711-5fdf-43b9-be06-d96268a191fd"
/> |

## To test

In apps/studio/hooks/misc/withAuth.tsx:

```diff
- const [isSessionTimeoutModalOpen, setIsSessionTimeoutModalOpen] = useState(false)
+ const [isSessionTimeoutModalOpen, setIsSessionTimeoutModalOpen] = useState(true) // Mocked as true for UI testing
```

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-02-25 16:27:48 +08:00
Joshen Lim 31a85bcb97 Final clean up for useQueryStateWithSelect (#43008)
## Context

Final clean up of `useQueryStateWithSelect` - removes the hook
2026-02-19 15:22:07 +08:00
Ignacio Dobronich 2f0197ac38 chore: realtime max message size entitlement (#41409)
Adds the Realtime max message size entitlement

### Testing
- Head to `project/_/realtime/settings` with an Org on the Pro with the
Spend Cap disabled
- Assert that the `Max payload size in KB` cannot exceed 3000
- Repeat the steps for max concurrent users and max presense events per
second

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Realtime settings now automatically reflect your subscription
entitlements with dynamic maximums for payload size, concurrent user
limits, and event rates.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-16 21:22:20 +01:00
Charis c7dcda5644 feat(studio): move data api settings to integrations (#42711)
Feature

## What is the current behavior?

Data API settings live under Project Settings.

## What is the new behavior?

Data API settings are moved to the Integrations page, treating Data API
as a platform integration. Includes security checks when toggling on the
Data API to prevent unintended exposure of project data.

## Additional context

Towards FE-2517

## Summary by CodeRabbit

* **New Features**
* Added a Data API integration with Overview and Settings pages,
endpoint display, and enable/disable toggle with safety checks and
confirmation flow.
* **Navigation Changes**
* Data API moved from Project Settings into the Integrations area and
routes now redirect to the new Overview page.
* **Documentation**
* Added an overview doc describing Data API endpoints and configuration.
* **Tests**
* Added unit tests for endpoint resolution and schema parsing utilities.
2026-02-12 15:18:39 +00:00
Charis 6b805289c7 chore(studio): remove feature flag for dataApiExposedBadge (#42563)
Cleanup / chore — removing a feature flag that has been at 100% rollout
with no issues.

## What is the current behavior?

The `dataApiExposedBadge` feature flag is checked at runtime via
ConfigCat, even though it has been set to 100% for a while with no
issues.

## What is the new behavior?

The feature flag check is removed and the gated behavior is now
unconditionally enabled. A reminder has been set to delete the flag from
ConfigCat in a month.

## Summary by CodeRabbit

**Refactor**
* Simplified API access status indicators in the studio editor, ensuring
security-related tooltips now display consistently based on actual
access conditions.
* Updated component interfaces and consolidated internal hook
dependencies for improved code maintainability and organization.
2026-02-10 21:18:53 +00:00
Jordi Enric 3f6843a6b1 bug: fix refetch loop (#42613)
Problem:
- new filters are creating an infinite fetch loop of ph.supabase.io 

#  Before:
  snap.filters change → effect → setParams() → router.push()
  → URL updates → filters/sorts recalc → setParams recreated
  → effect re-runs → INFINITE LOOP 🔄

 # After:
snap.filters change → effect → comparison shows change → timeout
scheduled
  → setParams() → router.push(shallow: true) → URL updates
  → filters/sorts recalc → setParams recreated → effect runs
  → comparison check: no content change → early return → LOOP BROKEN ✓

The deep comparison prevents the effect from re-executing when only the
dependency references change
(due to URL updates), not the actual filter content. Test it out and the
PostHog spam should stop!

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Bug Fixes

* **Prevented unnecessary URL updates** when filter state remains
unchanged, improving application responsiveness.
* **Optimized filter and sort parameter handling** with enhanced
callback efficiency and routing behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-09 16:58:11 +01:00