Commit Graph

1381 Commits

Author SHA1 Message Date
Charis
27e6259a39 chore(studio): remove legacy status banner and incidentIoStatusPage flag (#51852)
## Summary

The incident.io status page is now the only status banner for everyone,
so the legacy status banner path is removed:

- Removed the `incidentIoStatusPage` ConfigCat flag. The incident.io
path is unconditional.
- Deleted the legacy status banner code (`StatusPageBanner` and its
utils/visibility hook) and its tests.
- Deleted the legacy API endpoints `/api/incident-banner`,
`/api/incident-status`, and `/api/status-override` (pages, app, and
routes variants), along with their data hooks, query keys, and lib
helpers.
- Removed `STATUSPAGE_*` env vars from the Turbo config and the
`INCIDENT_BANNER_DISMISSED_IDS` local storage key from
`packages/common`.
- Updated the AI tools and SQL generation endpoint that read the flag.

`NEXT_PUBLIC_ONGOING_INCIDENT` / the `ongoingIncident` override is kept.

The `incident_status_cache` table and its migration are intentionally
untouched. Studio no longer reads it, and dropping it is a separate
cleanup.

## Testing

- Studio typecheck passes.
- Related vitest suites pass (414 tests).
2026-10-16 14:18:32 -04:00
Jordi Enric
4e1c6b5907 fix(logs): preserve pagination cursor precision DEBUG-229 (#51597)
## Problem

Rhe dashboard used only the last log's time to decide where to continue,
and shortened that time to milliseconds. This could skip logs with the
same recorded time, or times less than a millisecond apart, between one
page and the next. This could happen even with Live turned off.

## Fix

Use both the last log's full recorded time and its unique ID to decide
where the next page starts. This lets the dashboard continue from the
right log, even when several logs have the same time. The fix works with
both supported log services.

This PR fixes missing logs when loading older results. It does not
change how Live fetches new logs; that improvement is handled separately
in [#51599](https://github.com/supabase/supabase/pull/51599).

Part 1/9 of the replacement stack for #51090, tracked by
[DEBUG-229](https://linear.app/supabase/issue/DEBUG-229/make-live-mode-incremental).
Targets master; review and merge the stack in order. This diff contains
389 changed lines, including tests.

Stack: [#51597](https://github.com/supabase/supabase/pull/51597) →
[#51598](https://github.com/supabase/supabase/pull/51598) →
[#51599](https://github.com/supabase/supabase/pull/51599) →
[#51600](https://github.com/supabase/supabase/pull/51600) →
[#51601](https://github.com/supabase/supabase/pull/51601) →
[#51602](https://github.com/supabase/supabase/pull/51602) →
[#51603](https://github.com/supabase/supabase/pull/51603) →
[#51604](https://github.com/supabase/supabase/pull/51604) →
[#51605](https://github.com/supabase/supabase/pull/51605).

## How to test

- `pnpm --filter studio exec vitest run
data/logs/unified-logs-pagination.test.ts
data/logs/unified-logs.utils.test.ts`
- Check both log services: logs with the same recorded time, or times
less than a millisecond apart, should appear once when loading older
results.
- Validation: focused tests, full Studio typecheck, changed-file lint,
and formatting pass.
2026-10-16 16:22:13 +02:00
Monica Khoury
d0cf8dbc50 fix: align webhook FE with updated API changes (#51800)
## What
Aligns the webhooks FE with backend changes confirmed by Pawel
(FE-4621):

1. `custom_headers` is optional but never null, matches the updated
contract.
2. Removed the client-only `name` field (never persisted by the API).
Display name is now the endpoint's URL plus its subscribed event types.
3. The deliveries list endpoint now returns the full `event` object, so
`eventType`/`eventPayload` are always populated. Added an Event column
to the deliveries table.

Also regenerates `packages/api-types` from production to pick up these
changes.

While testing, found and fixed two more related issues:

4. A delivery can briefly exist before the backend finishes attaching
its event data, regardless of what triggered it (test, retry, or real
traffic). The deliveries list now polls every 5s while open, so new or
still-settling deliveries fill in automatically instead of requiring a
manual refresh.
5. "Send test event" always defaulted to an unrelated sample event type.
The test endpoint actually accepts a specific `event_type`, so this now
sends the endpoint's own subscribed type automatically, or shows a
picker when there's more than one to choose from.

## Testing
All webhooks component/unit tests pass (30/30), typecheck and lint
clean. Manually verified on localhost against a live backend.

## Note
This may clash with #51614 (`custom_headers: null` in a test fixture, no
longer a valid value once this merges). Will follow up there after this
lands.
2026-10-15 20:17:56 +03:00
Gildas Garcia
c829b26bd5 (feat) Allow to filter organization users by role (#51653)
## Problem

It can be hard to verify users roles in organizations with many members

## Solution

Add a filter on the team pages for organization roles.
<img width="1174" height="310" alt="image"
src="https://github.com/user-attachments/assets/dfc2ccdc-b83e-45c5-9a6c-d50417a3ff3e"
/>

## Review instructions

- Open the organization team page
- Select a role and verify only members who have this role are displayed
- Ensure other filters still work

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-10-15 11:31:46 +02:00
Anthony Lio
c3fd259904 fix(ai): assistant sql row cap (#51608)
## Problem

attempt to [fix this
ticket](https://supabase.frontapp.com/inboxes/teams/folders/27650590/unassigned/116845868830):
when the studio ai assistant runs a query with previously set database
opt-in, `execute_sql` returns every row while the query cell's footer
says "Limit 100 rows" causing in case of large amount of returned rows
browser to freeze

+ the chat fails with "Sorry, I'm having trouble responding right now"
until the user clears it

## Solution

- `execute_sql` now keeps the first 100 rows using the cell's existing
`DEFAULT_CELL_ROW_LIMIT`
- uses in history sanitizer the same `toModelRows` helper
- chats saved before this change have no `totalRows` so the helper falls
back to `rows.length` and cuts them to 100 too

<!--
## Preview links

If relevant, include links to changed pages for easy review access.

Copy the preview base URL from the Vercel bot comment on this PR. Use
the following table as an example template.

| Site | Live | Preview | Search for |
| -------------- |
-------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------
| ----------------------------- |
| WWW | [/blog/your-post](https://supabase.com/blog/your-post) |
[/blog/your-post](https://zone-www-dot-com-git-branch-name-supabase.vercel.app/blog/your-post)
| unique phrase from the change |
| Docs |
[/docs/guides/your-page](https://supabase.com/docs/guides/your-page) |
[/docs/guides/your-page](https://docs-git-branch-name-supabase.vercel.app/docs/guides/your-page)
| unique phrase from the change |
| Studio | [/dashboard](https://supabase.com/dashboard) |
[/dashboard](https://studio-git-branch-name-supabase.vercel.app/dashboard)
| unique phrase from the change |
| Design system | [/design-system](https://supabase.com/design-system) |
[/design-system](https://design-system-git-branch-name-supabase.vercel.app/design-system)
| unique phrase from the change |
| UI library | [/library](https://supabase.com/library) |
[/library](https://ui-library-git-branch-name-supabase.vercel.app/library)
| unique phrase from the change |
| Knowledge base |
[/kb/guides/your-page](https://supabase.com/kb/guides/your-page) |
[/kb/guides/your-page](https://kb-git-branch-name-supabase.vercel.app/kb/guides/your-page)
| unique phrase from the change |
-->

<!-- ## Additional context

Optionally add any other context or screenshots.

-->

## Review instructions

1. In a test project, run this in the SQL editor:
   ```sql
create table "emailSubscriber" (id bigint generated always as identity
primary key, email text);
create table "stripeCustomer" (id bigint generated always as identity
primary key, email text);
insert into "emailSubscriber" (email) select md5(g::text) ||
'@example.com' from generate_series(1, 50000) g;
insert into "stripeCustomer" (email) select md5(g::text) ||
'@example.com' from generate_series(1, 1000) g;
2. on the live dashboard, open the assistant in a new chat and send "i
want all the emails in emailSubscriber where the email is not in the
stripeCustomer table"
3. in the opt in requested settings choose "Schema, Logs & Database
Data"
4. then click run query, the cell should show 100 rows (vs 50000 rows in
prod)

## Checklist

Check all before review:

- [x] I have read
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
- [x] If I wrote a new docs topic or edited an existing topic, I used
the `/write-the-docs` or `/edit-the-docs` skill, which applies the docs
[style
guide](https://github.com/supabase/supabase/tree/master/apps/docs/style-guide)

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-10-15 12:22:16 +03:00
barcofourie
c8c12a87b4 feat(studio): add support satisfaction survey page (#51648)
## Problem

After a support ticket is resolved, customers receive an email with a
link to a satisfaction survey. That survey page is currently served from
a standalone function outside this repo. We are consolidating it into
the dashboard so it is deployed, monitored and tested with everything
else.

Linear:
[TOOLING-1425](https://linear.app/supabase/issue/TOOLING-1425/build-csat-in-supase-studio)

## Solution

Adds a public page at `/support/csat` that collects the survey answer
and posts it to a new Platform endpoint, `POST /platform/support/csat`,
which records the answer on the support conversation.

Key choices:

- **Pre-auth page**, modelled on `/verify-email`. Customers arrive from
an email and may not have a dashboard session. Hosted platform only;
self-hosted routes to 404.
- **URL shape** `?conversation_id=cnv_…&helpful=yes|no` matches the
links already sent in survey emails, so the email template only needs
its host changed. `helpful` preselects the answer, defaulting to Yes.
- **Copy and behaviour match the existing survey page**: same title,
question, labels, button text, and result messages.
- **Form** uses react-hook-form + zod; Yes/No are toggle buttons, the
comment is optional.
- **States**: missing or malformed ticket reference, already submitted
(409), ticket mismatch (404), and a generic error that keeps the form so
the customer can retry.
- The mutation uses `fetchHandler` directly, like the email-verification
mutation, because the endpoint is not in the generated API types yet.

Screenshot:

<img width="977" height="801" alt="image"
src="https://github.com/user-attachments/assets/2331861e-e8e9-43e1-84fc-3bf5786c145e"
/>


Depends on the Platform endpoint
https://github.com/supabase/platform/pull/40027. Until it is deployed,
submissions fail with the generic error state.

## Review instructions

1. Run Studio against a Platform stack that has the `POST
/platform/support/csat` endpoint.
2. Open `/support/csat?conversation_id=<a support conversation
id>&helpful=yes` while logged out. The page renders without redirecting
to sign in, with Yes preselected.
3. Pick an answer, optionally add a comment, and submit. The success
message appears and the answer is recorded on the conversation.
4. Submit again for the same conversation: the page reports that the
survey has already been submitted.
5. Open the page with no `conversation_id`: the page reports an invalid
ticket.
6. `pnpm --filter studio exec vitest --run
components/interfaces/Support/CsatSurvey` passes (18 tests).

## Checklist

Check all before review:

- [x] I have read
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
- [x] If I wrote a new docs topic or edited an existing topic, I used
the `/write-the-docs` or `/edit-the-docs` skill, which applies the docs
[style
guide](https://github.com/supabase/supabase/tree/master/apps/docs/style-guide)

---------

Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
2026-10-15 10:03:47 +02:00
Sahil Jagtap
135d8f00c3 fix(studio): match composite primary keys as tuples when deleting rows (#51575)
## 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?

Fixes #51574

Deleting several selected rows from a table with a composite primary key
builds one `IN` list per key column:

```sql
delete from public.user_roles where user_id in (1,2) and role_id in ('admin','viewer');
```

That matches the cartesian product of the selected values, so rows the
user never selected are deleted too. In the example above, selecting
`(1, 'admin')` and `(2, 'viewer')` also deletes `(1, 'viewer')` and `(2,
'admin')`.

## What is the new behavior?

When there is more than one primary-key column, the delete uses the
tuple `IN` filter that pg-meta already supports:

```sql
delete from public.user_roles where (user_id, role_id) in ((1, 'admin'), (2, 'viewer'));
```

Single-column primary keys keep the same SQL as before. The batched
operation queue uses the same helper for its delete operations, so it is
covered as well.

Added unit tests for both the single and composite cases.

## Additional context

This is silent data loss on join tables, which are the most common place
for composite keys and for multi-row deletes.
2026-10-14 19:24:36 +00:00
Monica Khoury
eaad809abf fix: webhook retry error handling (nested error envelope + unhandled rejections) (#51591)
## What
Fixes two bugs found while writing component tests for the platform
webhooks page (follow-up to FE-3749):

1. The webhooks API nests error details under an `error` key (`{ error:
{ code, message } }`), but the shared `handleError` only reads a
top-level `message`. This meant the friendly rate-limit message ("wait a
minute and try again") never actually fired, it always fell back to a
generic error. Fixed with a local unwrapping `handleError` in
`platform-webhooks-fetchers.ts`.
2. Every mutation handler on the page (`mutateAsync` for
create/update/delete/regenerate-secret/send-test-event/retry) left the
re-thrown error from React Query uncaught, producing an unhandled
promise rejection on every failure, even though the error toast itself
was already correct. Fixed by wrapping each call in try/catch.

## Why
Found while writing the stacked test PR for FE-3749; filed as
[FE-4620](https://linear.app/supabase/issue/FE-4620/two-webhook-error-handling-bugs-found-while-writing-retryrate-limit)
since it's a correctness fix independent of the test work.

## Testing
Manually verified both fixes on localhost: rate-limit retry now shows
the friendly message, and no `Uncaught (in promise)` errors appear in
the console on any mutation failure.
2026-10-13 19:44:21 +03:00
Gildas Garcia
4bf7b16473 feat(studio): scoped oauth apps reconsent UI (#51078)
## Problem

When users must grant access to an app they already added because its
scopes changed, they should have a clear understanding of the changes

## Solution

Show only the scopes differences by default

<img width="844" height="962" alt="image"
src="https://github.com/user-attachments/assets/6289f4cf-200f-4660-b9a1-aedbaaa963e3"
/>

## Review instructions

Try this UI with
[`authorize?mock_scenario=reconsent`](https://studio-staging-git-gildasgarcia-oauth-apps-inte-6106b6-supabase.vercel.app/dashboard/authorize?mock_scenario=reconsent)

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-10-13 17:25:50 +02:00
Francesco Sansalvadore
25708ed67a chore(studio): storage versioning override conflict (#51593)
## Problem

When uploading a file with same name of already existing file, the ui
automatically creates a new file with incremental number and doesn't
consider the scenario of giving the possibility of storing the new
upload as a version of the already existing file.

## Solution

Provide modal to chose the behaviour when name conflict happens when
uploading a file:
- Replace existing file (same file with version history)
- Keep both (new file with incremental numbering)


https://github.com/user-attachments/assets/ee192be9-4087-4e14-89f1-1c82acf550cd

Manage edge case of clashes with files created when bucket had
versioning enabled (so with `is_versioned` flag to true) and clashing
upload happens when bucket is in SUSPENDED state.


https://github.com/user-attachments/assets/00694c77-07c1-405e-bd54-bdf0bf99d274

Unrelated fix:
- add "Delete permanently" action when selecting multiple files with
versioning enabled

<img width="510" height="203" alt="Screenshot 2026-10-13 at 15 59 27"
src="https://github.com/user-attachments/assets/5692fc23-2fd3-4259-9de2-3932aecbccd0"
/>
2026-10-13 17:14:30 +02:00
Joshen Lim
fe8b4df66d Chore/tiny refactor org limit (#51550)
## Context

Tiny refactor that I happened to pass by as I was reviewing other PRs

`useOrgProjectsInfiniteQuery` has a default `limit` value at 96 set in
the hook, 96 mainly for the home page to render a full row of cards
since cards are rendered in rows of 3

However, we have a couple of callsites for `useOrgProjectsInfiniteQuery`
that were passing a different `limit` value, hence these would be
triggered as a separate API request.

Am opting to remove the `limit` parameter from
`useOrgProjectsInfiniteQuery` so that the limit is standardized to 96
- So that data can be cached without having to invoke another API
request wherever `useOrgProjectsInfiniteQuery` is called
- I doubt that there'll be a need in a UI that will require calling
`useOrgProjectsInfiniteQuery` with a separate value for `limit` but
please do let me know otherwise if I might be overlooking anything!
2026-10-13 11:06:49 +08:00
Gildas Garcia
88bc1ac384 feat(studio): oauth apps users own grant list in account settings (#50903)
## Purpose

Users now have an _apps_ page in their account settings allowing them to
see their own grants, the projects they affect and to disconnect an app.

This PR only uses mock data. Besides, the page and menu item are behind
a feature flag enabled on staging

<!--
## Preview links

If relevant, include links to changed pages for easy review access.

Copy the preview base URL from the Vercel bot comment on this PR. Use
the following table as an example template.

| Site | Live | Preview | Search for |
| -------------- |
-------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------
| ----------------------------- |
| WWW | [/blog/your-post](https://supabase.com/blog/your-post) |
[/blog/your-post](https://zone-www-dot-com-git-branch-name-supabase.vercel.app/blog/your-post)
| unique phrase from the change |
| Docs |
[/docs/guides/your-page](https://supabase.com/docs/guides/your-page) |
[/docs/guides/your-page](https://docs-git-branch-name-supabase.vercel.app/docs/guides/your-page)
| unique phrase from the change |
| Studio | [/dashboard](https://supabase.com/dashboard) |
[/dashboard](https://studio-git-branch-name-supabase.vercel.app/dashboard)
| unique phrase from the change |
| Design system | [/design-system](https://supabase.com/design-system) |
[/design-system](https://design-system-git-branch-name-supabase.vercel.app/design-system)
| unique phrase from the change |
| UI library | [/library](https://supabase.com/library) |
[/library](https://ui-library-git-branch-name-supabase.vercel.app/library)
| unique phrase from the change |
| Knowledge base |
[/kb/guides/your-page](https://supabase.com/kb/guides/your-page) |
[/kb/guides/your-page](https://kb-git-branch-name-supabase.vercel.app/kb/guides/your-page)
| unique phrase from the change |
-->

<!-- ## Additional context

Optionally add any other context or screenshots.

-->

## Review instructions

- In _Account/OAuth Apps_, you should see a list of apps
<img width="748" height="359" alt="image"
src="https://github.com/user-attachments/assets/8c50a467-e2c1-4000-aecf-09d5db1591d3"
/>
- Each app should have a menu entry allowing to disconnect it (fake for
now)
<img width="587" height="278" alt="image"
src="https://github.com/user-attachments/assets/6221fbd6-3b61-4d93-903e-9aedaf94de3f"
/>
- Each app but the last should have a menu entry that opens a dialog to
see the connected projects
<img width="657" height="651" alt="image"
src="https://github.com/user-attachments/assets/e985f933-fdfb-4d28-93c3-b3678d7d8a53"
/>

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-10-12 10:15:33 +02:00
Francesco Sansalvadore
876bb8cf9e feat(storage): archived objects data layer (#49677)
## This PR

On a versioned bucket a file or a version can be "soft deleted/archived"
or "permanently deleted".

- `archived-objects-query.ts` — `ArchivedObject` /
`ArchivedObjectVersion` types + `archivedObjectsQueryOptions`
- `archived-object-restore-mutation.ts` — bring an archived object back
into the live tree
- `archived-object-purge-mutation.ts` — delete it and every version,
permanently
- `archived-object-version-delete-mutation.ts` — remove one retained
version
- `archivedOverlay.utils.ts` — synthesizes the explorer rows for one
folder from the archived list
- `archivedVersions.utils.ts` — an archived object's history as one
flat, newest-first list

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-12 09:57:39 +02:00
Joshen Lim
369927892f Harden profile creation logic from dashboard (#51483)
## Context

When signing up a new account on the dashboard, the dashboard's the one
making the request to create a new profile for the user (ideally not,
but the proper fix on the BE is currently blocked). We do so by making
an initial request to GET `/profile`, and if it returns a 404, it's
implied that the account doesn't exist and we fire `createProfile`

Because of this, a race condition could exist (due to replica lag for
example):
- GET `/profile` returns 404, treat user as new
- POST `/profile` returns 200
- Profile query is still in "error" state (`isError` is `true), and post
sign-in tries to redirect to the new org page which triggers the
`useEfect`
[here](https://github.com/supabase/supabase/blob/master/apps/studio/lib/profile.tsx#L82-L96)
- Which prompts another POST `/profile`, and it returns a 409 because
the account's already created
- This then keeps going in a loop which keeps calling `createProfile`
and we didn't have a way to handle this, leading to users in a stuck
loading state until the browser's refreshed

## Changes involved
- Opt to invalidate the profile, permissions, and organizations if the
user runs into a 409
- This should refresh the profile and we'll no longer be stuck in a
create loop since `isError` should no longer be `true` then
- Tighten the dependency array for where `createProfile` is triggered
- Add exponential backoff up to 3 times for profile creation for
transient failures (5xx, network, 429)
- Never retry profile creation for 409, since there's no point doing so
2026-10-12 11:28:12 +08:00
Monica Khoury
2d5768d3c1 feat(studio): wire Platform Webhooks UI to real backend API (#51352)
## What
Wires the existing (mocked) Platform Webhooks UI to the real Management
API backend, per FE-3749.

- New `data/platform-webhooks/` query/mutation hooks, calling the real
`/v2/organizations/{slug}/webhooks/...` and
`/v2/projects/{ref}/webhooks/...` endpoints
- Updated `PlatformWebhooks.types.ts` to match the real API contract
(field names, shapes)
- Added a signing secret field to the create-endpoint form (API requires
a user-provided secret, not server-generated like the mock assumed)
- Removed the event-type column from the deliveries table (the real
list-deliveries endpoint doesn't return event type, only the
single-delivery endpoint does)
- Removed `PlatformWebhooks.mock.ts` / `.store.ts` and their tests

## Why
UI was built ~80% against mock data months ago; this closes the gap to a
real, working feature.

## Known open items (not blocking, tracked separately)
- `name` field has no backend storage yet — client-only for now, open
question with Ali/Paweł
- Deliveries table only fetches the backend's default single page — real
server-side pagination not yet wired (see FE-3750)

## Follow-up PR (stacked)
Tests for the new `data/platform-webhooks/` hooks (MSW-based), per the
ticket's own scope split.

## Testing
Manually tested end-to-end against local backend: created/edited/deleted
an endpoint, verified the real signature using webhook.site,
independently recomputed the HMAC and confirmed it matches the
`webhook-signature` header.

Linear: FE-3749

---------

Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
2026-10-09 22:41:09 +03:00
Joshen Lim
2b393377c6 Show connection settings if already configured despite no GH auth (#51427)
## Context

A project could already have a GitHub integration set up by another
member, which will show up in the branch management side navigation as
such:
<img width="259" height="255" alt="image"
src="https://github.com/user-attachments/assets/8bc12ef2-5f25-4245-9c89-4563b08a42a8"
/>

However if the user hasn't authenticated with GitHub, the project
settings -> integrations page will obfuscate the integration details
with a "Connect GitHub" CTA, which is a confusing UX as it hints that
there's no integration set up + conflicts with what's on the branch
management page
<img width="768" height="318" alt="image"
src="https://github.com/user-attachments/assets/a68409c0-f2db-407d-9bac-c109a0d14214"
/>

## Changes involved

Opting to show the integration details if there's one set up
irregardless of whether the user has authenticated with GH, but we'll
require the user to complete the authentication to manage the
integration settings as such (all input fields will also be disabled
until the auth is complete):
<img width="1031" height="511" alt="image"
src="https://github.com/user-attachments/assets/6fad387b-6e76-475e-b4e6-76972d8f76b6"
/>

Note that you can still disable the integration nonetheless irregardless
of the GH connection status

Also fixes the "Remove connection" CTA from Account Preferences - we
were invalidating the GH authorization query cache but the GH
authorization requests normally fails with a 404 if there's no auth set
up, so the query cache would remain stale. Opting to clear the query
cache instead of invalidating

## To test
- [ ] Set up a GH integration for your project under project settings ->
integrations
- [ ] Head to account preferences to remove your GH connection
- [ ] Go back to the project settings -> integrations page, should still
see the GH integration details, just unable to edit
- [ ] Connect with GH, and you should be able to edit the integration
details thereafter
2026-10-09 16:28:49 +08:00
Gildas Garcia
690ef5e7f7 feat(studio): scoped oauth apps, admins can see an app grants (#50979)
## Problem

Admins need to see the grants associated to an approved OAuth
application that uses scoped tokens.

## Solution

- Add a menu to the org settings oauth approved apps rows to see the
grant list
- Update the react query hook to use infinite query for the grant list

<img width="1149" height="356" alt="image"
src="https://github.com/user-attachments/assets/2e6cfc76-5584-4447-aa19-a0bf103e2218"
/>

<img width="429" height="395" alt="image"
src="https://github.com/user-attachments/assets/dd811d33-2c0a-46df-b9e9-3cbf8ad2fa7f"
/>

<img width="434" height="267" alt="image"
src="https://github.com/user-attachments/assets/108905ba-4dcb-4dca-abe2-1a4e1fc3dbd2"
/>

## Review instructions

In Org Settings/OAuth apps, you should see a menu button for each app
that contains a _View grants_ item. Clicking this item should open a
dialog with the grants

---------

Co-authored-by: kemal <hello@kemal.earth>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-08 15:48:51 +02:00
kemal.earth
12ab771e86 feat(studio): authorized apps table in org settings (#50529)
<img width="1150" height="669" alt="image"
src="https://github.com/user-attachments/assets/0b324577-bed5-4272-a7e0-f4444a0c1230"
/>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
2026-10-08 11:25:07 +02:00
Julian Domke
af3e397e7f feat(credit-codes): show that credit codes were reduced by partner deals (#51173) 2026-10-08 07:38:53 +00:00
Francesco Sansalvadore
2d0bd7af69 feat(storage): add object versions data layer (#49207)
| # | Branch | Base |
| - | ------ | ---- |
| 1 | `feat/storage-versioning-private-alpha` — merged | `master` |
| 2 | `feat/storage-versioning/002-bucket-form-fields` | `master` |
| 3 | `feat/storage-versioning/003-bucket-modals` | 2 |
| 4 | `feat/storage-versioning/004-object-versions-data` ◀ | 3 |
| 5 | `feat/storage-versioning/005-file-preview-versions` | 4 |
| 6 | `feat/storage-versioning/006-billing-storage-retention` | 5 |
| 7 | `feat/storage-versioning/007-archived-objects-data` | 6 |
| 8 | `feat/storage-versioning/008-archived-rows` | 7 |
| 9 | `feat/storage-versioning/009-archived-preview-pane` | 8 |
| 10 | `feat/storage-versioning/010-replace-file` | 9 |

## [4/10] Storage object versioning: object versions data layer

**Base:** `feat/storage-versioning/003-bucket-modals` (PR 3)

### This PR

The query and mutation hooks for the version history UI, written to
`queryOptions` using the real Storage endpoints.

- `object-versions-query.ts` — the version list, plus `ObjectVersion`
and `LifecyclePolicy`
- `object-version-restore-mutation.ts` — promote a noncurrent version to
current
- `object-version-delete-mutation.ts` — remove one specific version
- `object-purge-mutation.ts` — delete an object and every version,
bypassing versioning
- `VersionHistory.utils.ts` — `computeVersionFate`, the pure rule
deciding what removal outlook each version row shows
- `BroomSparklesIcon.tsx` — inline SVG for a glyph absent from
lucide-react 0.436

Easier to test directly from next PR in the stack #49208 which wires the
queries to the real file preview panel ui.

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-07 22:12:19 +02:00
Francesco Sansalvadore
6ef729cb5c feat(storage): versioning bucket modals (FE-4161) (#49205)
| # | Branch | Base |
| - | ------ | ---- |
| 1 | `feat/storage-versioning-private-alpha` — merged | `master` |
| 2 | `feat/storage-versioning/002-bucket-form-fields` | `master` |
| 3 | `feat/storage-versioning/003-bucket-modals` ◀ | 2 |
| 4 | `feat/storage-versioning/004-object-versions-data` | 3 |
| 5 | `feat/storage-versioning/005-file-preview-versions` | 4 |
| 6 | `feat/storage-versioning/006-billing-storage-retention` | 5 |
| 7 | `feat/storage-versioning/007-archived-objects-data` | 6 |
| 8 | `feat/storage-versioning/008-archived-rows` | 7 |
| 9 | `feat/storage-versioning/009-archived-preview-pane` | 8 |
| 10 | `feat/storage-versioning/010-replace-file` | 9 |

## [3/10] Storage object versioning: wire into the bucket modals

**Base:** `feat/storage-versioning/002-bucket-form-fields` (PR 2)

### This PR

Mounts the object-versioning form section in the create and edit bucket
modals behind the feature preview, and saves it.

- create and edit bucket modals spread `bucketVersioningFormFields` into
their existing form schema
- lifecycle defaults  to 30 days / 10 versions
- edit adds a confirmation before suspending an actively versioned
bucket

## Enabling object versioning on a new bucket and setting lifecycle
policies


https://github.com/user-attachments/assets/194f8319-4929-432e-8a50-206f180a77a8

## Edit and suspend object-versioning


https://github.com/user-attachments/assets/f31e1d34-9840-4f5a-a269-6a911214742d

## To reproduce

1. Make sure storage versioning is enabled under feature previews >
Storage Versioning
2. Open Storage Bucket File explorer
3. create new bucket and enable Object Versioning
4. set lifecycle policy
- Noncurrent version expiration: can be either empty or >1
- Retained noncurrent versions: can be either empty or between 1 and 100
and can't exist without "Noncurrent version expiration"
5. Open new bucket with object versioning and test changing lifecycle
policies
6. Disabling object-versioning shows proper warning and updates
`versioning_status` to SUSPENDED (it can never go back to DISABLED once
it has been enabled on a bucket)

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
2026-10-07 16:38:35 +02:00
claude[bot]
6c6b19c6c6 chore(studio): report empty-body GET 200s to Sentry with a no-store probe (#51123)
<!-- ccr-slack-attribution -->
_Requested by **Ivan Vasilov** · [Slack
thread](https://supabase.slack.com/archives/C063LNYJJKS/p1790710416069689?thread_ts=1790710416.069689&cid=C063LNYJJKS)_

**Before:** When a Studio API GET comes back as a 200 with an empty
body, openapi-fetch hands the caller `{}` and we only see the downstream
crash, with no record of the response that caused it.

**After:** The first time this happens for an endpoint in a page
session, Studio sends one Sentry warning, `Empty response body on
successful API request`. It carries the response metadata, browser
state, resource timing, and the result of a single `cache: 'no-store'`
refetch. What the caller receives is unchanged.

## Problem

Studio crashes trace back to GET requests that return 200 with an empty
body, which openapi-fetch turns into `{}`. They are heavily skewed to
Firefox and Safari. The leading hypothesis is browser cache revalidation
(Express weak ETags, no `Cache-Control` on api.supabase.com), but
nothing confirms it yet. The `no-store` probe tells the two cases apart:
if the refetch has a body, the browser cache is the likely culprit; if
it is also empty, the server or the edge is sending empty bodies. This
data should show whether the fix belongs on the API side or the
Cloudflare side.

Context: #51041 (closed) tried to guard the crashing call sites instead.

## Needs API-side change to be fully useful

Cross-origin, Studio can only read CORS-safelisted response headers, and
resource timing sizes read as zero. If api.supabase.com sends
`Access-Control-Expose-Headers: ETag, cf-ray, cf-cache-status,
x-request-id` and `Timing-Allow-Origin: <studio origin>`, this event
will also carry the ETag, cf-ray, and cache status, plus the real
transfer and body sizes and the negotiated protocol. Until then, those
fields read as `null` or `0`.

## Solution

- `data/empty-body-diagnostics.ts` (new): `reportEmptyBodyResponse({
request, response, schemaPath })`.
- Runs only for `GET` and only when `IS_PLATFORM`. Empty POST/201 bodies
are legitimate.
- Reports at most once per templated endpoint per page session
(module-level `Set`).
- Endpoint: openapi-fetch's `schemaPath` (e.g.
`/platform/projects/{ref}/settings`), passed through
`templateEndpointPath`. That function drops the query string and hash,
replaces the segment after `projects`/`organizations`/`branches` with
`{ref}`/`{slug}`/`{branch}`, and replaces UUIDs, numeric IDs, and 20+
character alphanumeric IDs with `{id}`. I used `schemaPath` rather than
the request URL so user-chosen names (bucket names, function slugs)
never end up in tags or fingerprints.
- Probe: one plain `fetch(new Request(request, { cache: 'no-store', ...
}))` with a fresh `X-Request-Id` and a 10s `AbortController` timeout.
`AbortSignal.timeout` isn't available in older Safari. The probe
bypasses the openapi-fetch middleware, so it can't recurse. Only the
body's byte length is recorded, never its contents.
- Event: `level: 'warning'`, `fingerprint: ['empty-body-response',
endpoint]`, `tags: { endpoint, probe_has_body, empty_body_diagnostic:
'true' }`, where `probe_has_body` is `true` / `false` / `error`. `extra`
holds:
- the request: method, status, `response.type`, `redirected`, and the
original `X-Request-Id` (for API log lookup)
- response headers: `content-type`, `cache-control`, `last-modified`,
`expires`, `content-length`, `etag`, `cf-ray`, `cf-cache-status`,
`x-request-id`
- browser state: `visibilityState`, `navigator.onLine`, the navigation
type, ms since navigation start, and whether the page was restored from
bfcache
- the latest `PerformanceResourceTiming` for the URL (transfer, encoded,
and decoded size, `nextHopProtocol`, `responseStatus`)
- the probe: status, request ID, body length, `content-length`,
`content-type`, or the error name
- Fire-and-forget: everything is wrapped in a `try`/`catch`, and the
caller does not await it.
- `data/fetchers.ts`: the `onResponse` middleware passes `{ request,
schemaPath }` to `normalizeEmptyBodyResponse`, which calls the reporter
in its empty-body branch and also for a 200 that carries
`Content-Length: 0`. openapi-fetch short-circuits that case to `{}` the
same way, so it is the same symptom. The return value is unchanged in
every branch.
- `packages/common/sentry.ts`: `filterSentryEvent` normally keeps only
1% of events that aren't page crashes. It now sends events tagged
`empty_body_diagnostic` unsampled, with `codeSampleRate: '1'`. A
once-per-session warning would barely show up at 1%. Consent and
platform gating and the third-party filter still apply. www and docs
also use `filterSentryEvent`, but only Studio's reporter sets this tag,
so sampling for them and for every other Studio event is unchanged.

Sentry config: Studio's `beforeSend` doesn't otherwise drop this
message. It has no exception values, so the no-stack-trace filter
doesn't apply, and it matches no `ignoreErrors` entry.

## Review instructions

1. Check `normalizeEmptyBodyResponse` in `data/fetchers.ts`: the
reporter is `void`-called and its return value is untouched.
2. Check `probe()` in `data/empty-body-diagnostics.ts`: only
`byteLength` is read from the body. The probe reuses the original
request's headers and credentials (same auth as the original GET).
3. Check `filterSentryEvent` in `packages/common/sentry.ts`: only the
`empty_body_diagnostic` tag skips sampling.
4. Tests: `data/empty-body-diagnostics.test.ts` and
`packages/common/sentry.test.ts`.

## Verification

- Unit tests (`data/empty-body-diagnostics.test.ts`, new):
  - path templating cases
  - `probe_has_body` `true` / `false` / `error`
  - the secret body content never appears in the Sentry call
  - one report per endpoint
  - non-GET and non-platform requests are skipped
  - no throw when `fetch` or Sentry throws
- end-to-end through `client.GET`: still resolves `{}` and reports the
`schemaPath`, for both a missing `Content-Length` and `Content-Length:
0`
- `packages/common/sentry.test.ts`: tagged diagnostics are sent
unsampled, untagged or false-tagged ones are still sampled, and they're
still dropped without consent.

These tests, plus the existing `normalizeEmptyBodyResponse.test.ts`,
`handleError.test.ts`, and the rest of `sentry.test.ts`, pass (67 tests)
under vitest 5 + jsdom. I ran them in a minimal harness, not the full
`pnpm install` workspace, because the local checkout is sparse.
- I ran TypeScript 7.0.2 (`--strict`) on the five touched files against
the real `api-types`, with stubbed `common`/Sentry types. No errors in
the touched files.
- Prettier `--check` with the repo config passes, with and without
`SORT_IMPORTS=false`.
- Not run locally: the full studio typecheck, `lint:ratchet`, and knip.
CI covers them. The change adds no `any`, no default exports, and no
deps.

## Checklist

- [x] I have read
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01UefDak8XYLMi9aiEjDPXc5

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-07 16:15:57 +02:00
Charis
22886fd304 feat(studio): add flag-gated general region selection (#51274)
## Problem

We want to be able to show free-plan organizations a simplified region
selector that only lists general regions (Americas, Europe,
Asia-Pacific), controlled per organization through ConfigCat.

## Solution

- ConfigCat flags are now evaluated with `organization_slug` and
`organization_created_at` (Unix seconds) custom attributes, so flags can
target and bucket by organization.
- `organization_created_at` is read from `GET
/platform/organizations/{slug}`, fetched only for free-plan
organizations, since the organization list response doesn't include it.
- Two flags:
- `freeTierGeneralRegionEnrollment`: the organization is enrolled
(control or test).
- `freeTierGeneralRegionSelection`: the organization sees only general
regions.
- For enrolled free organizations, the region selector stays in its
loading state until flags have been evaluated with the organization's
creation time, so specific regions aren't shown and then removed.
- In the test variant, the selector hides specific regions and shows a
footer linking to the plan upgrade panel. High Availability keeps its
own region list.
- Telemetry: new `free_tier_general_region_experiment_exposed` and
`free_tier_general_region_upgrade_clicked` events, and
`freeTierGeneralRegionExperiment` / `regionSelectionType` properties on
`project_creation_simple_version_submitted`.
- `created_at` is added to `OrganizationSlugResponse` in the generated
platform types, matching the API.

## Review instructions

1. With both flags off, open `/new/[slug]` for a free organization and
confirm the region selector is unchanged.
2. Using the dev toolbar, set `freeTierGeneralRegionEnrollment` and
`freeTierGeneralRegionSelection` to `true`. Confirm only general regions
are listed and the footer links to the billing plan panel.
3. Set `freeTierGeneralRegionSelection` to `false` and confirm the full
selector is shown.
4. Repeat with a paid organization and confirm the full selector is
always shown.
2026-10-07 09:43:28 -04:00
Alaister Young
16bd06dfb8 fix(studio): silence status page errors when incident.io isn't configured (#51315)
Running Studio locally without the incident.io env vars produces a 500
from `/api/status-page` on every fetch, plus a server-side log and a
client `console.error`. Retries and the 5-minute refetch keep repeating
them, so the dev console stays noisy.

**Changed:**
- `lib/api/status-page.ts` – when `INCIDENT_IO_WIDGET_URL` is unset
outside production, return an empty (degraded, short-cached) status page
instead of throwing. The missing API key / status page ID log is also
limited to production. Production behavior is unchanged.
- `data/platform/status-page-query.ts` – remove the client-side
`console.error`, which repeated the error that React Query already
exposes

**Added:**
- Tests for the missing widget URL in dev (empty payload, no error log)
and in production (still throws)

## To test

- Run Studio locally in platform mode without `INCIDENT_IO_*` set: no
status page errors in the terminal or the browser console, and
`/api/status-page` returns 200 with empty arrays
- Support form and project creation still render normally (no status
banner, status page link points to status.supabase.com)

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-10-07 14:58:43 +02:00
kemal.earth
454a232947 feat(studio): scoped oauth interstitial ui (#50090)
## 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?

The scoped OAuth consent interstitial: scope display, org/project
selection,
consent screen assembly, success screen, and post-submit role-validation
error state. Consolidates the former stacked PRs #49481, #49484, #49486,
#49489, #49951 into one reviewable unit (each contained the last; no
code
was dropped).

- Entirely behind `useFlag('oauthAppScopedGrants')` — no reachable UI
with
  the flag off.
- Runs on the mock data layer from #49476 (`USE_MOCKS`-gated); no real
  endpoints are called.
- Covers PROD-626, PROD-627, PROD-628, PROD-629, PROD-653.

Base is #49476 (data contracts + mocks); will retarget to master once it
merges.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
2026-10-07 10:56:24 +02:00
Jordi Enric
d2ffd76395 perf(logs): load pathname facet counts on demand DEBUG-230 (#51112)
## Problem

Unified Logs included a pathname aggregation in every initial sidebar
count query, even when the pathname filter was closed. This issue is
tracked in
[DEBUG-230](https://linear.app/supabase/issue/DEBUG-230/fetch-sidebar-counts-only-when-needed).

## Fix

Remove pathname aggregation from the initial ClickHouse and BigQuery
count queries while keeping the existing shared count scans. Fetch
scoped pathname options through the existing facet query when the filter
opens or its search changes. Order limited pathname results by count,
validate response rows with Zod, and retain selected paths during
loading and validation errors. Use live sidebar filters while their URL
update is pending and URL filters after navigation. Cache results by
project and filter scope, and wait for feature flags before requesting
options.

## How to test

- Open Unified Logs, then open Pathname and search. Confirm options load
on demand.
- Change the time range, another filter, or navigate through browser
history. Confirm the options reflect the current scope.
- Close and reopen Pathname without changing the scope. Confirm cached
options return.
- Run the pathname filter component tests and Studio typecheck.
2026-10-06 16:38:30 +02:00
Joshen Lim
eb20a4674d getTableDefinitionSql to escape SQL identifiers (#51258)
## Context

Similar to domain to https://github.com/supabase/supabase/pull/51256 -
`getTableDefinitionSql` doesn't escape SQL identifiers, which generates
invalid SQL on the dashboard's table editor for the "Copy table schema"
CTA, or the table definition tab.

Also fixes the "Copy table schema" CTA which was missing the `scoped`
parameter when calling `getTableDefinition`

Changes here addresses this issue, can test with a table named like
`test"table`
2026-10-06 21:34:36 +08:00
Francesco Sansalvadore
089133cc2c feat(storage): add bucket object versioning form fields (FE-4161) (#49203)
| # | Branch | Base |
| - | ------ | ---- |
| 1 | `feat/storage-versioning-private-alpha` — merged | `master` |
| 2 | `feat/storage-versioning/002-bucket-form-fields` ◀ | `master` |
| 3 | `feat/storage-versioning/003-bucket-modals` | 2 |
| 4 | `feat/storage-versioning/004-object-versions-data` | 3 |
| 5 | `feat/storage-versioning/005-file-preview-versions` | 4 |
| 6 | `feat/storage-versioning/006-billing-storage-retention` | 5 |
| 7 | `feat/storage-versioning/007-archived-objects-data` | 6 |
| 8 | `feat/storage-versioning/008-archived-rows` | 7 |
| 9 | `feat/storage-versioning/009-archived-preview-pane` | 8 |
| 10 | `feat/storage-versioning/010-replace-file` | 9 |

## [2/10] Storage object versioning: bucket form fields

The object versioning + lifecycle policy form section for the create and
edit bucket modals.
Mounted onto the ui in PR 3 #49205 

- `BucketVersioningFields` — the versioning switch and the suspension /
public-bucket / retention-tightening warnings
- `LifecyclePolicySection` — the retention window and version cap inputs
- `ExpirationModeToggle` — how the two conditions combine (and / or)
- `BucketVersioningFields.schema.ts` — zod fields the parent modals
spread into their own schema, plus `superRefineBucketVersioning`
- `BucketVersioningFields.utils.ts` — retention-tightening detection
- `StorageVersioning.constants.ts` — versioning state and expiration
mode types, the prefill defaults, and `getBucketVersioningState`

Note: a single s3 lifecycle policy expects both `version_expiry_days`
and `max_noncurrent_versions` and always evaluate the two fields within
the same policy with an AND logic. To enable both AND and OR/EITHER
logic, we save two distinct s3 policies so we can enforce the OR logic.

See demos and how to reproduce in #49205 

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

## Summary

* **New Features**
* Eligible projects with the preview enabled can configure object
versioning for storage buckets, including version expiration,
retained-version limits, and “and/or” lifecycle conditions.
* Settings default to 30 days and 10 retained versions, with validation
for retention values and requirements for setting a version limit.
* Notices highlight public buckets, missing lifecycle conditions,
suspending existing versioning, and changes that tighten retention
limits.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
2026-10-06 14:24:50 +02:00
Jordi Enric
7d04c43082 fix(logs): default unified logs to otel DEBUG-228 (#51089)
## Problem

Unified Logs could start legacy BigQuery requests while ConfigCat
loaded, then switch to OTEL when the flag resolved.

## Fix

Default Unified Logs to OTEL unless otelUnifiedLogs is explicitly false.
Use that selection for list, count, chart, facet, detail, download, and
manual refresh requests. Keep BigQuery as an explicit opt-out until the
legacy backend is removed.

## Validation

- Studio typecheck passed locally.
- Existing Unified Logs utility tests passed (21 tests).
- The focused Unified Logs query test file was removed as requested;
backend-selection and manual-refresh regressions are no longer covered
by that suite.
- CI checks are running on the current head.

Tracks
[DEBUG-228](https://linear.app/supabase/issue/DEBUG-228/prevent-bq-queries-before-the-feature-flag-loads).
2026-10-05 17:43:15 +02:00
kemal.earth
0c2257fb3d feat(studio): scoped oauth data layer (#49476)
## 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?

~~This is the first part (and ultimately the final part of the stacked
PR). PR 1 introduces mock data for us while we build the requirements of
the scoped oauth interstitial, all following PR's will be stacked on top
of this one.~~

This is the first part, the data layer side. We began with mock data,
but as backend support arrived we've used this PR to help us shape the
UI as well as the frontend data layer. This now acts as the frontend
data layer.


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

* **New Features**
  * Added OAuth app authorization request handling.
* Added visibility into application details, requested scopes, and
existing authorizations.
  * Added organization and project selection during authorization.
  * Added organization roles and project access details.
  * Added approval and denial options with secure redirect handling.
* Added validation for required authorization details and project
selections.
  * Added support for role validation feedback during approval.
* Added representative authorization scenarios for approved, denied, and
re-consent flows.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
Co-authored-by: Samir Ketema <6003000+samirketema@users.noreply.github.com>
2026-10-05 15:20:21 +02:00
Tanun Turbo Chalermsinsuwan
77e3b4382f feat(role): Allow eligible organizations to invite users as 'No-access' base role (#50922)
## Problem

As the API has allow inviting users into `None / No-access` role for
team, enterprise, and platform tier organization, we need to update the
documentation and descriptions for this new role on the invitation form.

## Solution

1. Updated `apps/docs/content/guides/platform/access-control.mdx` to
include the role
2. Added the role description on
`apps/studio/components/interfaces/Organization/TeamSettings/Roles.constants.tsx`
3. Add the roles into the proper sorting order at
`apps/studio/data/organization-members/organization-roles-query.ts`
4. Add logic to invitation components to disable the role when inviting
user into project(s), as the backend does not allow it.

## Testing and verification steps
The UI:
https://studio-staging-aa8is1m07-supabase.vercel.app/dashboard/org
Documentation:
https://docs-kht98bi78-supabase.vercel.app/docs/guides/platform/access-control

<!--
## Preview links

If relevant, include links to changed pages for easy review access.

Copy the preview base URL from the Vercel bot comment on this PR. Use
the following table as an example template.

| Site | Live | Preview | Search for |
| -------------- |
-------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------
| ----------------------------- |
| WWW | [/blog/your-post](https://supabase.com/blog/your-post) |
[/blog/your-post](https://zone-www-dot-com-git-branch-name-supabase.vercel.app/blog/your-post)
| unique phrase from the change |
| Docs |
[/docs/guides/your-page](https://supabase.com/docs/guides/your-page) |
[/docs/guides/your-page](https://docs-git-branch-name-supabase.vercel.app/docs/guides/your-page)
| unique phrase from the change |
| Studio | [/dashboard](https://supabase.com/dashboard) |
[/dashboard](https://studio-git-branch-name-supabase.vercel.app/dashboard)
| unique phrase from the change |
| Design system | [/design-system](https://supabase.com/design-system) |
[/design-system](https://design-system-git-branch-name-supabase.vercel.app/design-system)
| unique phrase from the change |
| UI library | [/library](https://supabase.com/library) |
[/library](https://ui-library-git-branch-name-supabase.vercel.app/library)
| unique phrase from the change |
| Knowledge base |
[/kb/guides/your-page](https://supabase.com/kb/guides/your-page) |
[/kb/guides/your-page](https://kb-git-branch-name-supabase.vercel.app/kb/guides/your-page)
| unique phrase from the change |
-->

<!-- ## Additional context

Optionally add any other context or screenshots.

-->


## Checklist

Check all before review:

- [x] I have read
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
- [x] If I wrote a new docs topic or edited an existing topic, I used
the `/write-the-docs` or `/edit-the-docs` skill, which references
[WORD_LIST](https://github.com/supabase/supabase/blob/master/apps/docs/WORD_LIST.md)
and the docs
[CONTRIBUTING](https://github.com/supabase/supabase/blob/master/apps/docs/CONTRIBUTING.md)
guide


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

## Summary

* **Updates**
* The **None** role is labeled **No-access** and describes the lack of
organization and project resource access.
* **None** is included after **Read-only** in the role list. When
inviting a member with project-only access, **None** is disabled with an
explanation.
* **Documentation**
* Clarified plan coverage for **Read-Only** and **No access**, and added
guidance on assigning **No access** at the organization level before
granting project-specific roles.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-10-05 19:54:55 +07:00
Joshen Lim
838fcaaa89 Joshenlim/fe 4509 fdw general UI consolidation and refactor (#51079)
## Context

Stacks on top of https://github.com/supabase/supabase/pull/51074

PR's just mainly refactoring, no visual differences:
- `CreateWrapperSheet` + `EditWrapperSheet` use the same UI components
for the foreign tables section
  - Can be consolidated into one reusable component
- `WrapperTableEditor` is still using `SidePanel` component
  - Can be swapped to use new `Sheet` component
- Refactor `WrapperTableEditor`'s layout a little - added separators for
clarity between sections
<img width="400" alt="image"
src="https://github.com/user-attachments/assets/b1983bf2-cff5-43eb-8b31-40a7abb65038"
/>
- Update `getCreateFDWSql` to just use the Foreign Data Wrapper's name
from `wrapperMeta` since its now standardized

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

* **New Features**
* Added a shared foreign-table selector for wrapper setup and editing,
with options to view columns, add or edit table definitions, and remove
tables.
  * Updated the table editor to use a sheet layout with a fixed footer.
* **Bug Fixes**
* Wrapper creation now uses the wrapper’s configured name when creating
the server.
* Foreign-table targets display the table name when other target details
are unavailable.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-10-05 16:20:50 +08:00
Joshen Lim
521881a899 Joshenlim/fe 4480 fdw create wrapper to only init fdw once users to name the (#51074)
## Context

PR here refactors the way we manage Foreign Data Wrappers in the
dashboard (Under Project -> Integrations), as there's some DX problems
with the current behaviour.

Currently whenever a user creates a new wrapper, the dashboard is
creating both the Foreign Data Wrapper (`create foreign data
wrapper...`) + server (`create server ...`). The former is
**_redundant_** to create multiples of given that it just handles the
`handler` and `validator`, whereas what matters more is the server which
holds the connection credentials. Hence standard practice is usually one
Foreign Data Wrapper with multiple servers. (The former just needs to be
created once if not done yet)

This also led to some problems as well when users created their own
wrappers via SQL and tried to manage them through the dashboard GUI,
leading to us having to add some guard rails to prevent managing
wrappers sharing the same Foreign Data Wrapper
([ref](https://github.com/supabase/supabase/pull/50785))

## Changes involved
- When creating a wrapper, if the Foreign Data Wrapper has yet to be set
up for the wrapper type, the dashboard will initialize one and
subsequently use that same Foreign Data Wrapper for any new wrappers
- When creating / editing a wrapper, users will name the **server**
instead of the **wrapper**
<img width="500" alt="image"
src="https://github.com/user-attachments/assets/b3e61204-0e16-4599-84ac-af2aab5b93c2"
/>
- When deleting a wrapper, the clean up for vault secrets are now
deterministic by referencing the wrapper's server options
- RE backwards compatibility: Existing wrappers will _not_ be affected
by the changes here - they can be edited / deleted as per normal

## Unrelated fixes + UI refactors added
- Fix Iceberg Wrapper not showing the right form when adding new wrapper
- Adjust form layouts in side panel to be horizontal instead of vertical
(Follows Database -> Pipelines)
- Clean up to use newer UI components like `ButtonTooltip`
- Opt to hide Docs + Create CTA under `WrappersTab` if marketplace
feature preview is enabled (Since these actions are already in the
header, will be duplicates)
- Consolidate foreign tables configuration for create + edit wrapper
sheet into one component `ForeignTablesSelector`

## To test
- [ ] Verify that existing wrappers with their own Foreign Data Wrapper
can be edited correctly
- [ ] Verify that existing wrappers with their own Foreign Data Wrapper
can be deleted
- [ ] Verify that existing wrappers with shared Foreign Data Wrapper can
be edited correctly
- [ ] Verify that existing wrappers with shared Foreign Data Wrapper can
be deleted
- [ ] Verify that new wrappers can be created
- [ ] Verify that newly created wrappers can be edited correctly
- [ ] Verify that newly created wrappers can be deleted
2026-10-05 16:00:37 +08:00
Ali Waseem
7353782724 fix(studio): show compute waitlist notice when project is not enrolled (#51224)
Resolves FUNC-941

## What

When a project isn't enrolled in Compute, show a short notice with a
link to the waitlist (https://supabase.com/compute) instead of a generic
error.

## Why

The compute API returns its 404 as `{ "error": { "code", "message" } }`.
`handleError` only reads a top-level `message`, so it dropped the status
code, `isComputeUnavailable` never matched, and users saw "API error
happened while trying to communicate with the server." The query now
checks `response.status === 404` directly.

## Testing

- [ ] Project not enrolled in Compute: the waitlist notice shows
- [ ] Enrolled project: the instance list loads as before
2026-10-03 20:34:14 +00:00
Artur Zakirov
4b2d163a1d fix(orioledb): use alpha and beta conditionally based on AMI version (#51162)
## Problem

- Older orioledb projects show "Public Beta" instead of "Public Alpha"
in UI.
- List of backups in the "Scheduled backups" tab hangs.

## Solution

- show in the UI "Public Alpha" for projects older than
17.11.0.001-orioledb
- show in the UI "Public Beta" for new projects
- enable scheduled-backup query for "Public Beta"


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

## Summary by CodeRabbit

* **Bug Fixes**
* Backup availability messages now reflect OrioleDB’s current release
stage rather than always describing it as public beta.
* AWS backup queries are no longer disabled for every OrioleDB project;
they remain disabled during the alpha stage.
* **New Features**
* Added an informational notice and documentation link for scheduled
backups on AWS OrioleDB projects in alpha.
  * Added release-stage details to the PITR availability notice.

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

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>
2026-10-02 09:43:32 -04:00
Monica Khoury
123c768de1 Warn when authenticator role overrides exposed schemas (FE-4472) (#50982)
## What

Adds a warning in Project Settings > API when the `authenticator` role's
`pgrst.db_schemas` setting overrides the Dashboard's "Exposed schemas"
configuration, plus an inline "Reset override" button to fix it in one
click.

## Why

`ALTER ROLE authenticator SET pgrst.db_schemas = ...` silently overrides
what PostgREST actually exposes, regardless of what's selected in the
Dashboard. Users hit a confusing PGRST106 error with no indication that
a role-level override is the cause.

## How

- New query (`authenticatorRoleConfigQueryOptions`) reads
`pg_roles.rolconfig`
for the `authenticator` role and parses out any `pgrst.db_schemas`
value.
Configured to always refetch on mount and window focus, since the fix is
often applied outside the Dashboard (SQL editor, another client) with no
  cache-invalidation event for the app to react to.
- `PostgrestConfig.tsx` compares that value against the currently
selected
  schemas and shows an `Admonition` warning naming the actual overriding
  schemas, with a link to the PGRST106 troubleshooting guide, when they
  differ.
- The warning includes a "Reset override" button that runs
  `alter role authenticator reset pgrst.db_schemas` after a confirmation
  step (showing the exact SQL that will run, with a copy button), then
  refetches so the warning clears immediately without a page reload.

## Testing

1. In the SQL Editor of a test project, run:
   ```sql
   alter role authenticator set pgrst.db_schemas = 'public';
   ```
2. Go to Project Settings > API, and select a schema other than (or in
   addition to) `public` in "Exposed schemas" (e.g. add `api`).
3. The new warning should appear, naming `public` as the schema actually
   in effect, with a link to the PGRST106 troubleshooting guide.
4. Click "Reset override" in the warning, confirm in the modal, and
check
   that the warning clears immediately without a page reload.
5. Alternatively, clear the override manually from the SQL editor:
   ```sql
   alter role authenticator reset pgrst.db_schemas;
   ```
then navigate away from the API settings page and back (or refocus the
   browser tab) — the warning should clear without a hard refresh.

Fixes
[FE-4472](https://linear.app/supabase/issue/FE-4472/warn-when-authenticator-role-overrides-exposed-schemas)


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

## Summary by CodeRabbit

* **New Features**
* The API settings page now warns when the authenticator role’s exposed
schemas differ from the saved Dashboard configuration.
* You can reset the override to restore the saved schema configuration.
The reset requires permission and provides success or error feedback.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-10-01 16:02:00 +03:00
Tanun Turbo Chalermsinsuwan
cd305313e4 fix(roles): Show only document-defined roles (#51087)
## Problem

As part of having `None / No Access` available to customers, we need to
start providing this role entry in `/platform/organization/:ref/roles`
endpoint. However, when making it available, the role will show up
prematurely on all the components that relies on
`useOrganizationRolesV2Query` function.

## Solution

This change is to allow us to test the behavior of the new role without
having to turn the API on/off. The UI will show only the "predefined"
entries and ignore the "extras" sent by API.

After this is merged, we will do the following

1. Unhide the None role from the API
https://github.com/supabase/platform/pull/39137 -- this will not have
any effect on the frontend as we already ignore it in this PR
2. Work and continue testing on
https://github.com/supabase/supabase/pull/50922 -- which will be easier
to verify as we no longer need to change the API side

## Review instructions

1. Modify the items in the `FIXED_ROLE_ORDER` list, remove some roles
from there
2. You will see that the role will disappear from the components like
the invitation form or managed access form.



## Checklist

Check all before review:

- [x] I have read
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
- [x] If I wrote a new docs topic or edited an existing topic, I used
the `/write-the-docs` or `/edit-the-docs` skill, which applies the docs
[style
guide](https://github.com/supabase/supabase/tree/master/apps/docs/style-guide)


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

## Summary by CodeRabbit

* **Bug Fixes**
* Organization role lists now show only supported roles, in the expected
order. Roles outside the supported set are no longer displayed. This
keeps the list consistent and focused on recognized roles, making
available organization roles easier to review.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-30 20:40:42 +07:00
Kamil Ogórek
c5b4fbfa11 fix: Handle NO_PROJECT_MARKER for projectRef (#51083)
Skip `NO_PROJECT_MARKER` values for projectRef in API validation.
2026-09-30 10:34:26 +00:00
Pamela Chia
38b74af3f1 fix(studio): fall back for framework icons without an asset (#51065)
I made the connected-project framework icons fall back when no shipped
SVG exists for a framework. The three icon sites built
`/img/icons/frameworks/<framework>.svg` straight from the integration's
framework preset, which is an open-ended string. They only fell back
when the value was empty, so any preset without an asset (`express`,
`hono`, `fastapi`, `tanstack-start` and others) showed a broken image
and logged a 404.

**Changed:**
- **Broken framework icons**: `getFrameworkIconUrl` returns the asset
URL only for slugs in a set that mirrors `public/img/icons/frameworks/`.
The integration connection row, the org project linker and the
marketplace project picker now show their existing fallback icon for any
other slug. A test keeps the set equal to the directory listing.
- **Framework type**: I deleted the hand-kept `VercelFramework` union.
It listed exactly the shipped icon slugs, while the API types the field
as `string | null`, and that mismatch is what made the old empty-only
check look safe.

**Note:** I rejected an `onError` fallback because the browser still
sends the 404 request. Adding logos for common presets is left for
design.

## To test

Tested on Vercel preview (staging): no real connection there uses these
presets, so I rewrote the org integrations response in the browser to
give one integration four connections.
- [x] Open an org's Integrations page with connections whose framework
has no shipped icon (`express`, `eve`, `tanstack-start-lovable`). Expect
the fallback badge and no request under
`/dashboard/img/icons/frameworks/` for those slugs. Observed: all three
rows showed the badge and the network log had no request for their SVGs.
- [x] Same page with a `nextjs` connection. Expect its framework logo.
Observed: `nextjs.svg` loaded with a 200.
- [x] Same page with the real, unmodified response (one connection with
`framework: null`). Expect the badge, no frameworks requests, and no new
console errors. Observed: as expected.

## Linear
- fixes GROWTH-1309


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

## Summary by CodeRabbit

* **Bug Fixes**
* Vercel integration and project views now display framework icons when
available and fall back to the Vercel icon when no matching icon exists.
* Framework metadata now supports values beyond a fixed list, while
unsupported frameworks continue to use the fallback icon.

* **Tests**
* Added coverage for supported and unsupported framework icons,
including base-path handling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-30 12:59:36 +08:00
Charis
d22702e907 refactor(studio): extract user project regions + emergency override hooks (#51033)
## Summary
- Extracts `useUserProjectRegions` (org + project region aggregation,
fail-open on fetch errors) and `useEmergencyIncidentOverride` (the
`ongoingIncident` flag / env var check) out of
`useStatusPageBannerVisibility`, so the upcoming incident.io status-page
banner can reuse both without duplicating the org/project fan-out logic.
- No behavior change for the legacy banner except one intentional fix:
`StatusPageBanner.utils.ts` compared the incident's affected regions
(lowercased) against the user's regions (not normalized), so a
mixed-case region on either side could silently fail to match. Both
sides now go through the same `normalizeRegion` helper.
- Part of the Linear FE-4057 stack (PR 5a of 6). Base branch is PR 4
(`charis/fe-4057-pr4-project-creation-status-admonition`), not master.

Linear: FE-4057

## Test plan
- [x] `pnpm --filter studio run typecheck`
- [x] `pnpm --filter studio run lint:ratchet`
- [x] `pnpm knip --workspace apps/studio`
- [x] `pnpm test:prettier`
- [x] `pnpm --filter studio exec vitest run` on the touched test files
and the `hooks/misc/` and `components/layouts/AppLayout/` directories
(all passing, no regressions)

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

## Summary by CodeRabbit

* **Bug Fixes**
* Improved status banner targeting by matching incidents against
normalized regions across the user’s projects.
* Updated banner visibility checks to handle incomplete project or
region data, including when project information fails to load.
* Improved loading behavior so the banner can be evaluated based on
user-region data rather than waiting for separate organization and
project requests.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-29 17:49:06 -04:00
Pamela Chia
4a941518e3 feat(studio): track Explorer runs and saves (#51004)
I added outcome events for Explorer query runs and successful manual
notebook saves. Existing page visits and preview toggles do not show
whether users complete queries or persist notebooks.

**Changed:**
- **Query usage:** Accepted runs from query tabs and notebook cells emit
submitted and terminal outcome events with a shared run ID. Canceled
confirmations emit no run events.
- **Notebook adoption:** Successful manual saves emit created or updated
events. Recreated notebooks count as creations. Unsaved drafts and
failed saves emit neither.
- **Event metadata:** Explorer action events use `Explorer` as their
page title.

**Note:** Assistant-generated saves are outside this PR. Custom
properties omit SQL and notebook content. Page visits still carry the
browser title, which can include a notebook name.

## To test

Tested on the staging preview:
- [x] Run valid and invalid SQL from an Explorer query tab. Each run
emits one submitted event and one matching completed or failed event
with the same run ID.
- [x] Run database and Logs notebook query cells, then add a markdown
cell. The query cells emit matching event pairs; the markdown cell emits
no query event.
- [x] Save a new notebook, then edit and save it again. The successful
saves emit created and updated events.
- [x] Cancel a guarded query. It emits no query run event.
- [ ] Recreate a notebook deleted on the server after local edits. A
successful save emits created, not updated.
- [x] Inspect an Explorer action event request. Its page title is
`Explorer`; page visits still use the browser title.
- [ ] Force a notebook save failure. It should emit no save event. This
case was not tested manually.

## Linear
- fixes GROWTH-1298


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

* **Analytics**
* Explorer query runs are tracked for database and log queries,
including whether they complete or fail.
* Query activity is associated with its location in Explorer, such as a
query tab or notebook cell.
  * Successful notebook saves are tracked as creations or updates.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-09-29 13:54:13 -07:00
Alaister Young
995f6f65c7 [FE-4483] fix(studio): disable network bans for v3 projects (#50997)
Disables network bans for v3 (`AWS_K8S`) projects and shows a specific
unsupported notice. The shared banned-IP query waits for project details
and skips unsupported projects, covering both Database Settings and
Advisor for v3 and High Availability projects.

The hook returns the standard query result and uses `skipToken` to
prevent unsupported requests, including manual refetches. Database
Settings handles project-detail errors at the call site. Open unban
confirmations are cleared when the section becomes disabled, and
submission checks eligibility.

Addresses
[FE-4483](https://linear.app/supabase/issue/FE-4483/disable-network-bans-for-v3-aws-k8s-projects).

## To test

- Open Database Settings on a v3 project. Check that Network bans shows
the v3 notice, hides the IP list and unban controls, and makes no
network-bans retrieval request on initial load or reload, including
while Advisor is mounted.
- Check that an HA project still shows its existing notice and makes no
network-bans retrieval request on initial load or reload.
- Navigate from a supported project to a v3 or HA project and check that
no banned-IP request is sent for the unsupported project and no
banned-IP signals from the previous project appear in Advisor.
- If project details fail without cached data, check that Network bans
shows an error after retries finish and does not retrieve bans. A
successful retry should restore normal behavior.
- Open an unban confirmation on a supported project, then navigate to a
v3 or HA project. Check that the dialog closes without sending an unban
request and stays closed when returning. A newly opened confirmation
should still work.
- On a supported project, check the empty state and banned IP list.
Confirm that users with permission can unban an IP and users without
permission see a disabled button with the permissions tooltip.

Validation: 17 focused tests passed, covering automatic and manual
request suppression, project-detail error display and recovery, and
navigation between supported and unsupported projects. Changed-file
ESLint, Prettier, and full Studio typecheck (without the incremental
cache) passed. Earlier local browser checks on `9912c6c` confirmed no
retrieval requests for an HA project on AWS_K8S across reloads and
Advisor, and a successful empty state on a supported project. The local
failed-project case redirected to the organization after retries, so the
inline error remains verified by the component test only. The latest
preview, standalone v3 notice, populated bans/unban, and no-permission
tooltip still need browser verification.

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

* **Bug Fixes**
* Banned IP settings now show an unsupported-project notice for AWS
Kubernetes projects and hide ban lists and unban actions for AWS
Kubernetes and High Availability projects.
* Banned IP data loads only after project details are available and only
for supported projects; unsupported projects do not display cached ban
data.
  * Project-detail errors are shown separately from ban-list errors.
* Unban confirmations close when a project becomes unsupported or an
unban succeeds. Unbanning is unavailable when you lack update permission
or the project is unsupported.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-09-29 17:51:14 +00:00
Manan Gupta
6a0518dd86 fix(studio): forward HA flag to project-creation pre-flight checks (#50902)
## Summary

- Fixes MUL-1678: toggling High Availability on in the project-creation
wizard 400'd for orgs that are HA-entitled but not enrolled in the "V3
rollout ramp" feature flag on the backend, because two pre-flight
endpoints Studio calls before project creation didn't know about HA and
hit the ramp check the real create-project call already bypasses.
- Threads `highAvailability` through
`useOrganizationAvailableRegionsQuery` (`GET
/platform/projects/available-regions`, sent as
`high_availability=true|false` on the query string) and
`useProjectCreationPostgresVersionsQuery` /
`useAvailableOrioleImageVersion` (`POST
/platform/organizations/:slug/available-versions`, sent as
`high_availability` in the body), including their query-key cache keys
so HA and non-HA responses for the same org/provider/size don't collide.
- Wires the (already form-tracked) `highAvailability` value into every
call site: `ProjectCreationForm.tsx`, `RegionSelector.tsx`, and a new
`highAvailability` prop on `PostgresVersionSelector.tsx` passed from
`InternalOnlyConfiguration.tsx`.

## Problem

The project-creation wizard's HA toggle is wired into the actual
project-create request, but two pre-flight calls Studio makes before
that (available regions, available Postgres versions) had no way to
signal HA, so the backend's ramp-flag gate rejected them for HA-entitled
orgs outside the ramp.

## Solution

Add an optional `highAvailability` field end-to-end on the Studio side:
query hook variables, cache keys, request serialization, and the
components that already track the toggle via `useWatch`.


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

* **Bug Fixes**
* Available regions and database versions in project creation now
reflect the selected high-availability setting.
* The Create button remains disabled while available regions are
loading.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: GuptaManan100 <guptamanan100@gmail.com>
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-09-29 20:39:01 +05:30
Charis
8b8569bd1a feat(studio): status page client data layer + support form (#50984)
## Summary

* Adds the client query layer for `/api/status-page`
(`statusPageQueryOptions` in `data/platform/status-page-query.ts`) and a
shared normalization module (`lib/status-page/status-page.utils.ts`)
that maps the endpoint response into region- and project-creation-aware
`StatusItem`s — later PRs in this stack (assistant tool,
project-creation admonition, global banner) build on this same module.
* Wires the support form's status pill and incident admonition to the
new data behind the `incidentIoStatusPage` ConfigCat flag.
`useSupportStatus` branches between the new endpoint and the existing
`useIncidentStatusQuery`/`processIncidentData` path, both mapped to the
same `SupportStatus` shape.
* `IncidentAdmonition` becomes purely presentational; the status link
now points at the `pageUrl` returned by the endpoint instead of a
hardcoded URL.

Part of
[FE-4057](https://linear.app/supabase/issue/FE-4057/frontend-bannerbot-reconfigured)
— see Linear for full design context.

## Test plan

- [X] `pnpm --filter studio run typecheck`
- [X] `pnpm --filter studio run lint:ratchet`
- [X] `pnpm knip --workspace apps/studio`
- [X] `pnpm test:prettier`
- [X] `pnpm --filter studio exec vitest run` (touched files) — 70 tests
passing, including a flag-on case for `SupportFormPage`

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

## Summary by CodeRabbit

* **New Features**
* Support pages now display current incident and maintenance
information, including relevant status descriptions and links to the
status page.
* Status details can reflect items affecting a user’s region or
project-creation services. Upcoming maintenance is excluded from active
alerts.
* **Bug Fixes**
* Status labels and alerts now account for loading, errors, incidents,
and maintenance consistently across support pages.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-29 07:53:28 -04:00
Joshen Lim
e3fec137fe Joshenlim/fe 4466 audit logs update organization logs as well (#50935)
## Context

Follows up from [this
PR](https://github.com/supabase/supabase/pull/50799) - updates the Audit
Logs UI for organization audit logs. Just differs from Account audit
logs slightly with added "Actor" + "Target" column

Reuses the same UI components from account audit logs so quite a bit of
code clean up 🙂
<img width="1451" height="955" alt="image"
src="https://github.com/user-attachments/assets/a1002cee-917f-4d9a-b977-3fab8ecd2d13"
/>


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

* **New Features**
* Organization audit logs now use a sortable table with row selection
and a resizable details panel.
* Actor details show a member’s username when available, otherwise the
actor’s email; a dash appears when neither is available.
* Logs can be filtered by users and projects, with separate messages for
no logs and no matching results.
* A refresh control and loading indicators help show audit-log updates.
* **Bug Fixes**
* Organization project lists stop loading when pagination totals are
unavailable.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-29 17:41:54 +08:00
Sean Geoghegan
f2ff4ec0e9 fix(realtime): display banner when realtime has been suspended by admin (#50497)
## 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?

If Realtime's admin_suspended_at is set we display a banner.

## What is the current behavior?

REAL-1095

## What is the new behavior?

<img width="1160" height="442" alt="Screenshot 2026-09-17 at 12 06
30 pm"
src="https://github.com/user-attachments/assets/f5abe900-a163-48c9-ab55-945fc62df0d1"
/>


## Additional context

Depends on https://github.com/supabase/platform/pull/38476


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

## Summary by CodeRabbit

- **New Features**
- Added a notice to Realtime settings when the service is suspended,
with instructions to contact support.
- **Bug Fixes**
- Improved invitation resending and role updates for roles without a
linked base role.
- **Tests**
- Added coverage to verify the suspension notice appears only when
applicable.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-09-28 15:17:24 +08:00
Chris Opland
509afd0bf0 fix(o11y): support partial metric loading (#50867) 2026-09-25 12:20:23 -05:00
Jordi Enric
f0952fdef8 fix(studio): delete only the selected foreign server FE-4462 (#50785)
## Problem

The dashboard lists one row per foreign server, but deleting a row
dropped its foreign data wrapper with CASCADE. When multiple servers
shared a wrapper, deleting one removed all of them.

## Fix

Drop the selected server and its foreign tables. Remove the underlying
wrapper and Vault secret only when no servers still use it. Edits to a
shared wrapper now stop before making changes because the existing edit
flow recreates the underlying wrapper.

## How to test

1. Configure two BigQuery foreign servers that use the same foreign data
wrapper. Delete one from the dashboard.
2. Confirm the other server and its foreign tables still exist and work.
3. Delete the remaining server. Confirm the foreign data wrapper and its
Vault secret are removed.
4. Attempt to edit one of two servers sharing a wrapper. Confirm the
edit fails without removing either server.

Focused pg-meta tests and typecheck pass.

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

* **New Features**
* Shared connections are identified in the integrations list, with
guidance for editing them in the SQL Editor. Editing is disabled when a
wrapper is shared, with an explanation shown.
* Deleting a connection removes its foreign tables and removes the
wrapper and Vault secret only when no other connection uses them.
* **Bug Fixes**
* Connection deletion verifies that the selected server still belongs to
the wrapper and reports failures using connection-focused wording.
* Attempts to edit a wrapper used by another connection are blocked with
a clear explanation.
* Connection deletion and confirmation messages now consistently refer
to deleting a connection.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-25 16:49:01 +02:00
Ivan Vasilov
12894ddd2a feat(studio): migrate storage infinite-query hook to list-v2 (#50730)
## Problem

Storage's `list` (v1) endpoint is being deprecated in favor of
`list-v2`, which uses cursor pagination instead of numeric offset (which
degrades on large buckets) and fixes folders that differ only by case
not both being listable. This is PR 1 of the migration (parent:
FE-4423); it covers the shared infinite-query hook and its two
consumers.

## Solution

Added `listBucketObjectsV2` alongside the existing v1
`listBucketObjects` (still used elsewhere, migrated in a later PR), and
replaced the `useBucketObjectsInfiniteQuery` hook with
`bucketObjectsInfiniteQueryOptions` built on `infiniteQueryOptions`,
following the repo's preferred data-fetching pattern. Pagination now
uses `hasNext`/`nextCursor` instead of an offset multiplier, and
`queryFn` rejects a response that claims `hasNext` without advancing the
cursor so a misbehaving backend can't send `fetchNextPage` into an
infinite loop. v2 splits results into separate `folders`/`objects`
arrays and has no `search` field, so the two consumers
(`BucketFilePickerColumn`, `MoveItemsFolderPicker`) merge/sort those
arrays themselves, and search is folded into a `prefix` match instead.
Also removed "Time last accessed" from the picker's sort dropdown since
v2's `sortBy.column` doesn't support it, with a defensive fallback to
`name` in case the shared sort preference (still used by the v1 main
file explorer) carries that value over. Added the missing self-hosted
`list-v2` API proxy route (`pages/api` + the TanStack `routes/api`
wrapper) using storage-js's `listV2()`, since self-hosted Studio only
had a v1 route and every v2 request was 404ing there.

## Review instructions

1. Open the bucket file picker (e.g. via an OAuth app logo upload),
confirm folders and files both render and paginate correctly, and that
searching still filters as expected.
2. Open the "Move items" modal's folder picker, confirm you can navigate
into and back out of subfolders, and that folder search still works.
3. Run `pnpm test:studio -- MoveItemsModal`.

## Checklist

- [x] I have read
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
- [ ] If I wrote a new docs topic or edited an existing topic, I used
the `/write-the-docs` or `/edit-the-docs` skill, which references
[WORD_LIST](https://github.com/supabase/supabase/blob/master/apps/docs/WORD_LIST.md)
and the docs
[CONTRIBUTING](https://github.com/supabase/supabase/blob/master/apps/docs/CONTRIBUTING.md)
guide

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* **New Features**
* Storage browsing loads large bucket listings in pages, helping keep
navigation responsive.
* Folder pickers display folders and files together across paginated
results.
* Moving items between folders uses the same paginated browsing
experience.
* Search remains available in the final folder level, and folder
navigation shows the correct contents.

* **Updates**
* “Time last accessed” is no longer available as a sorting option in
storage pickers. Sorting is available by name, creation time, or update
time.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 16:11:24 +02:00
Samir Ketema
ad5c4bb879 fix: gracefully handle 403s on org invites for project-scoped members (#50876)
## Problem

Gracefully handles 403s when getting org invitations as a project-scoped
org member. The backend currently returns an empty list with a 200
status, but that will be changing soon - so this PR aims to fix the
issue in advance.

## Solution

Pretty self explanatory - but here is a before/after (with backend
changes)

### Before
<img width="2480" height="688" alt="CleanShot 2026-09-24 at 11 02 34
AM@2x"
src="https://github.com/user-attachments/assets/13c6ed9e-7580-4962-9920-f49ede9c4592"
/>

### After
<img width="2466" height="820" alt="CleanShot 2026-09-24 at 11 07 13
AM@2x"
src="https://github.com/user-attachments/assets/248f7bb5-1743-41c9-823f-f776a608dd17"
/>


<!--
## Preview links

If relevant, include links to changed pages for easy review access.

Copy the preview base URL from the Vercel bot comment on this PR. Use
the following table as an example template.

| Site | Live | Preview | Search for |
| -------------- |
-------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------
| ----------------------------- |
| WWW | [/blog/your-post](https://supabase.com/blog/your-post) |
[/blog/your-post](https://zone-www-dot-com-git-branch-name-supabase.vercel.app/blog/your-post)
| unique phrase from the change |
| Docs |
[/docs/guides/your-page](https://supabase.com/docs/guides/your-page) |
[/docs/guides/your-page](https://docs-git-branch-name-supabase.vercel.app/docs/guides/your-page)
| unique phrase from the change |
| Studio | [/dashboard](https://supabase.com/dashboard) |
[/dashboard](https://studio-git-branch-name-supabase.vercel.app/dashboard)
| unique phrase from the change |
| Design system | [/design-system](https://supabase.com/design-system) |
[/design-system](https://design-system-git-branch-name-supabase.vercel.app/design-system)
| unique phrase from the change |
| UI library | [/library](https://supabase.com/library) |
[/library](https://ui-library-git-branch-name-supabase.vercel.app/library)
| unique phrase from the change |
| Knowledge base |
[/kb/guides/your-page](https://supabase.com/kb/guides/your-page) |
[/kb/guides/your-page](https://kb-git-branch-name-supabase.vercel.app/kb/guides/your-page)
| unique phrase from the change |
-->

<!-- ## Additional context

Optionally add any other context or screenshots.

-->

## Review instructions

1. Open the preview
2. Navigate to the `Team` tab in `Organization`
3. Invite a project-scoped member
4. Accept the project-scoped member invite in another browser
5. Navigate to the same `Team` tab as that project-scoped member.


## Checklist

Check all before review:

- [x] I have read
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
- [x] If I wrote a new docs topic or edited an existing topic, I used
the `/write-the-docs` or `/edit-the-docs` skill, which references
[WORD_LIST](https://github.com/supabase/supabase/blob/master/apps/docs/WORD_LIST.md)
and the docs
[CONTRIBUTING](https://github.com/supabase/supabase/blob/master/apps/docs/CONTRIBUTING.md)
guide


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

* **Bug Fixes**
* Organization member lists now load even when invitation details aren’t
accessible.
* Missing invitation data no longer prevents member lists from loading.
* Invitation errors other than access-denied errors, and errors loading
members, continue to be reported.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-24 12:33:23 -07:00