This PR moves the client-side "Charge Today" calculation to the backend
- relying on the `preview` endpoint data to show the `Charge Today`,
`Prorated Credits` and `Customer Balance` in the Subscription Upgrade
Preview.
It also includes fields for displaying Tax information in the preview,
only for enabled orgs. Do note that at the moment the Tax Preview will
not change if the address in the Subscription Preview changes, that will
be tackled in a follow-up PR.
## Changes
- Replace client-side charge calculation with backend data: The upgrade
dialog previously computed the prorated credit and total charge locally
(using subscription period timestamps and plan prices). This PR uses the
`upfront_charge` object returned by the subscription preview API
instead.
- Display itemized tax breakdown: When the backend returns tax data, the
dialog now shows a line-by-line breakdown: plan cost → subtotal (if
different) → tax (with rate %) → total charged today.
- Use `tax_status` from the subscription preview to conditionally show
tax details, and display a warning when tax calculation fails.
## Testing
### No taxes - Upgrade from Free to Paid Plan
- With a Free Org with a billing address in Canada or any other
non-enabled jurisdiction, start the upgrade to the Pro Plan
- Assert that only the Charge Today field is shown in the summary
<img width="410" height="298" alt="image"
src="https://github.com/user-attachments/assets/e8c7e12e-833d-41d5-aec3-00092b12782f"
/>
### Taxes - Upgrade Plan
- Update an Org's Orb Customer on the Free or Pro Plan with the
`automatic_tax_enabled: true` flag.
```
curl --location --request PUT 'https://api.withorb.com/v1/customers/external_customer_id/{ORG_SLUG}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: ••••••' \
--data '{
"tax_configuration": {
"tax_exempt": false,
"tax_provider": "numeral",
"automatic_tax_enabled": true
}
}'
```
- Update the Org address to a valid taxable address, like:
```
"address": {
"country": "US",
"line1": "100 Congress Ave",
"city": "Austin",
"state": "TX",
"postal_code": "78701"
}
```
- Assert that the tax information is shown in the preview, including Tax
Rate, Prorated credits (if applicable), Customer balance (if applicable)
and the price of the intended plan.
<img width="465" height="470" alt="image"
src="https://github.com/user-attachments/assets/dd6a7e27-1708-48a8-bbf3-5435e6d582c2"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added itemized breakdown of subscription charges, including plan cost,
unused time credits, subtotal, and applicable taxes.
* Enhanced billing estimates with detailed tax information display.
* **Improvements**
* Updated "Charge today" calculations to reflect real-time preview data
for greater accuracy.
* Improved billing estimate UI layout and clarity with better
organization of charge details.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Bug fix & feature
## What is the current behavior?
Customers with large schemas have trouble running:
pg-meta/{ref}/tables?include_columns=false
## What is the new behavior?
In the webhooks view some users with large schemas could not click a
table name as the underlying query times out. This just adds a light
weight query and fetches the table name
## Additional context
Add any other context or screenshots.
## Summary by CodeRabbit
* **Refactor**
* Optimized table name fetching in the database interface by introducing
an enhanced query mechanism that streams table metadata more efficiently
from the database.
Follow-up to #44451 which added `literal()` escaping to 4 queue message
files. The remaining 5 files in the same directory still use raw string
interpolation.
The create mutation was the biggest gap -- no `literal()` and no
`isQueueNameValid` at all. It could also interpolate `undefined` into
SQL when partition config is missing.
Applied the same pattern from #44451 to all 5 files: import `literal`,
wrap interpolated values. For the metrics query and create mutation,
also used `ident()` for table name references.
## Summary by CodeRabbit
* **Refactor**
* Improved internal SQL query construction for database queue operations
to enhance code reliability and maintainability.
Don't fire the `available-versions` request when `dbRegion` is falsy
(undefined or empty string). Fixes race condition where the request
fires before a region is selected.
## To test
- Confirm no invalid `available-versions` request in the network tab
- Confirm create new project still works
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved database region validation during project creation to
consistently handle empty or undefined values.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
INDATA-193
BACKEND: <https://github.com/supabase/platform/pull/30575>
<img width="1199" height="1005" alt="Screenshot 2026-04-03 at 11 54 29"
src="https://github.com/user-attachments/assets/38e9d676-449f-45c0-9e07-f273312a812f"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Consolidated read replica limit configuration to provide more
consistent behavior across different compute tiers.
* **Tests**
* Added comprehensive test coverage for read replica eligibility checks
and replica limit calculations based on compute tier.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Ever since the update to TypeScript 6, IDE auto-imports are suggesting
"node_modules/package_name/...." rather than the correct "package_name".
This is due to our deprecated bare specifier wildcard in paths,
replacing this with a listing of all bare specifiers we currently
support (while migrating away) to restore auto-import suggestions.
## What
Escapes user-controlled string values before interpolating them into SQL
in `apps/studio/data/database-queues/`.
## Why
Several queue message queries were constructing SQL via direct string
interpolation without sanitization:
| File | Value | Risk |
|------|-------|------|
| `database-queue-messages-send-mutation.ts` | `payload` | **High** —
arbitrary user-provided JSON; a single quote breaks the query and a
crafted payload could execute arbitrary SQL |
| `database-queue-messages-infinite-query.ts` | `afterTimestamp` |
Medium — sourced from a previous DB result, but still unsafe to
interpolate |
| `database-queue-messages-delete-mutation.ts` | `messageId` | Low —
typed `number`, but truncated for safety |
| `database-queue-messages-archive-mutation.ts` | `messageId` | Low —
same as above |
## Fix
- Escape string literals with the standard PostgreSQL approach (doubling
single quotes `'` → `''`) before interpolation
- Wrap numeric `messageId` values with `Math.trunc()` to prevent
floating-point edge cases
- `queueName` was already validated via `isQueueNameValid` regex
(alphanumeric/underscore/hyphen only) — no change needed
Fixes#44375
## Test plan
- [x] Open Queue Messages panel in Studio
- [x] Send a message with a payload containing single quotes (e.g.
`{"key": "it's a value"}`) — verify it sends without error
- [x] Verify pagination still works correctly after fix
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved safety of queue operations by ensuring message IDs, payloads,
timestamps, and queue names are handled securely to prevent injection
and formatting issues.
* Normalized numeric message fields (IDs/delays) for consistent
processing.
* Increased stability and correctness of archive, delete, query, and
send operations; no public APIs were changed.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Context
For database extensions, previously dashboard would fire a separate call
just to retrieve the "default schema" for an extension via
`useDatabaseExtensionDefaultSchemaQuery` from the
`pg_available_extension_versions` table (the `schema` from this table
implies where the extension will be installed in)
## Changes involved
Am updating the `useDatabaseExtensionsQuery` to use a custom studio SQL
that will fetch this data in one request via a `LEFT JOIN`, so dashboard
no longer needs to fire a request to `pg_available_extension_versions`
each time we open the `EnableExtensionModal` since all the info we need
is loaded up front.
Have also validated that the cost of the custom studio SQL is low (6.8,
via explain analyze) so performance wise on the project's DB should be
okay.
This will then also allow us to correctly render the "default schema" of
the extensions in the new Install Integration Sheet now that we have
that information up front.
## Misc fix
Also fixed a small issue on the database extensions page whereby if you
searched for an extension that's hidden (e.g pg_tle), there's no "No
results" UI state showing up
<img width="1112" height="319" alt="image"
src="https://github.com/user-attachments/assets/eb488117-2a24-4317-ad73-1d636f9b1bc8"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Per-extension default schema detection surfaced across install flows;
default schema options added to selectors when applicable.
* **Bug Fixes**
* Hidden extensions filtered out earlier so they no longer appear in
lists.
* Install button now correctly disables when required extensions are
missing.
* **Refactor**
* Consolidated extensions metadata retrieval and simplified schema
selection/validation logic; UI text formatting standardized.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
The Fly login/auth endpoints were removed from the management API
(supabase/platform#30987). This cleans up the associated studio code and
regenerates the API types.
Note: existing Fly projects are still running, so all `cloud_provider`
guards and Fly-specific UI (disk management, billing, pg_cron warnings,
etc.) are intentionally kept in place.
**Removed:**
- `sign-in-fly-tos.tsx` page
- `organization-by-fly-organization-id-mutation.ts`
- `project-by-fly-extension-id-mutation.ts`
**Other:**
- Regenerated API types to reflect removed endpoints
- Removed stale Fly-related comments in `InstanceConfiguration`,
`ObservabilityMenu`, `ReportsMenu`
- Fixed unrelated optional chaining bug in `SSOConfig.tsx`
## To test
- Check project creation flow still works
- Verify `/sign-in-fly-tos` no longer resolves
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
`useOrgSSOConfigQuery` had an internal plan-based gate
(`canSetupSSOConfig`) that permanently disabled the query for
non-team/enterprise orgs.
The fix removes the redundant plan gate from the query hook, plan-based
access is already controlled upstream via the entitlement check in the
component.
## 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?
The `getNextPageParam` function in
`database-queue-messages-infinite-query.ts` uses `<=` instead of `>=`,
which means pagination never stops. Since the result length is always
less than or equal to the page size, `hasNextPage` is always `true`,
causing infinite API requests when viewing queue messages in Studio.
Resolves#44291
## What is the new behavior?
Uses `>=` to correctly detect when there are more pages, consistent with
every other infinite query in the codebase:
- `database-cron-jobs-infinite-query.ts` uses `>=`
- `users-infinite-query.ts` uses `>=`
- `database-cron-jobs-runs-infinite-query.ts` uses `< PAGE_SIZE` to
return `undefined` (equivalent logic)
## Additional context
One character change: `<=` to `>=` on line 112.
## Context
Resolves https://github.com/supabase/supabase/issues/43548
There's currently an issue with the Table Editor where if you have, for
example, a nullable `text` column with a default value, inserting a new
row and selecting "Set to NULL" doesn't do anything, and saving will
insert the row with the default value
<img width="700" height="258" alt="image"
src="https://github.com/user-attachments/assets/6a284ebb-c346-40a6-9a30-793118844084"
/>
This stems from a legacy logic in the Table Editor whereby we treat
`null` values as "no input" - which is incorrect as `null` values are
also valid values. So the PR here changes a few things to resolve this
properly:
## Changes involved
Main fix:
- `undefined` will be the "no input" value instead, and it'll be the
default value when generating the row object for inserting a new row
- `NULL` or even empty string like `''` will be treated as they are
(valid inputs)
Secondary adjustments:
- (Queue operations) Queueing an insert with no value but default value
is NULL, will show the placeholder as `DEFAULT` instead of `NULL` for
better accuracy in representation
<img width="892" height="96" alt="image"
src="https://github.com/user-attachments/assets/02cf86bf-c17b-4e25-9a8f-17960b1d2575"
/>
- Added a `Set to Default` CTA here, but will only show up if adding a
new row or updating a queued insert row operation, which will set the
value of the input field back to `undefined` for PG to handle it as the
default value
<img width="734" height="208" alt="image"
src="https://github.com/user-attachments/assets/23887c0c-533e-4494-acbe-61309ff5d7c5"
/>
## To test
Verify within the Table Editor (along with queue operation feature
preview)
- For inserting a new row, setting value to NULL and setting value to
Default works
- For updating a row, setting value to NULL works
## Summary
The `connectSection` A/B experiment concluded as a true null (no effect
on activation or any downstream metric after 13 days at 50/50, ~153K
mature orgs). Saxon decided to ship the Connect section as the permanent
experience. This PR removes the Getting Started control variant, the old
Connect modal, all experiment flag gating, and related telemetry types.
## Changes
- Delete `GettingStarted/` directory (5 files: section component, types,
utils, progress hook)
- Delete old `Connect.tsx` dialog modal (replaced by ConnectSheet)
- Remove `connectSection` PostHog flag reads from `Home.tsx` and
`LayoutHeader.tsx`
- Remove `getSectionVisibility()` experiment logic and
`ConnectSectionVariant` type
- Remove `getting-started` from `DEFAULT_SECTION_ORDER`
- Always render `<ConnectSheet />` in header (no more conditional with
old `<Connect />` modal)
- Remove `variant` prop from `ConnectSection` component
- Remove 4 getting-started telemetry event interfaces from
`telemetry-constants.ts`
- Update `mergeSectionOrder` tests to reflect new section order
## Testing
Tested on Vercel preview:
- [x] Project homepage shows Connect section for new projects (< 10 days
old)
- [x] Connect section hidden for mature projects (> 10 days old)
- [x] Header Connect button opens ConnectSheet (not old modal)
- [x] Connect tiles open ConnectSheet with correct tab
- [x] Section drag-and-drop still works without getting-started in the
order
- [x] Existing users with `getting-started` in localStorage order don't
break (mergeSectionOrder strips it)
## Linear
- fixes GROWTH-730
---------
Co-authored-by: Alaister Young <alaister@users.noreply.github.com>
## Context
Related to marketplace related work, just moves the Queues integration
to the new UI (Changes are feature flagged)
<img width="1145" height="584" alt="image"
src="https://github.com/user-attachments/assets/d3245889-597d-44e2-9850-f20907e42056"
/>
Installation is now in a side panel with the intention that it'll just
be a single click to install integrations that involve multiple parts
<img width="400" height="955" alt="image"
src="https://github.com/user-attachments/assets/71903b61-6bd2-486c-903e-b48ae2133887"
/>
## To test
- Verify that you can install the integration and everything else should
be status quo
- Verify that everything should be status quo if the flag is off
## Context
Shifts all remaining dashboard queries into pg-meta so that we
centralize all manually written queries in one place
Having them in packages/pg-meta also allows us to write tests for them
## To test
Just needs a smoke test on
- Role Impersonation
- Lints
- Data API
- Database
- Enumerated Types
- Integrations
- Foreign Data Wrappers
- Vault
## 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 a prototype for private apps UI. There are no endpoints at the
minute, just wanted to see what a potential flow could look like.
## 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?
show the "enable" button if the `GET /auth/v1/admin/custom-providers`
returns 404 (without a json body). this is temporary as I want to enable
the rollout of this feature now, and there could be projects which
didn't get the latest auth server release(should be completed by next
week).
## What is the current behavior?
We only show a generic error message.
## What is the new behavior?
Show custom provider specific message and add CTA to enable the custom
providers (simply trigger a PATCH config request to trigger auth config
updates)
## Additional context
<img width="1454" height="390" alt="image-IPleA6ze@2x"
src="https://github.com/user-attachments/assets/b0cb4df8-2499-4749-900c-b78543a72800"
/>
This error is shown after 2 retries of the `GET
/auth/v1/admin/custom-providers`, would be nice to have if we show this
error message without retries.
## Context
Shifting more dashboard queries into pg-meta so that we centralize all
manually written queries in one place
Having them in packages/pg-meta also allows us to write tests for them
## To test
Just needs a smoke test on
- Table Editor
- Fetching entities
- Viewing definition
- SQL Editor
- View ongoing queries
- Abort queries
- Integrations
- Queues
- Database
- Migrations
-Triggers (Updating)
This PR:
* Adds an upgrade flow to the stripe sync engine, allowing users to
upgrade to the latest version when it becomes available.
* When a new version of sync engine becomes available, users will see an
upgrade button instead of install button.
* Bumps `supabase-management-js` to version 2.0.2 and
`stripe-experiment-sync` to version 1.0.27.
* Uses `parseSchemaComment` and related logic from the
`stripe-experiment-sync` package in order to avoid writing duplicate
code in supabase ui.
* Allows installation/uninstallation to timeout after 5 minutes to avoid
these operations from getting stuck in case an error occurs in their
processing. This allows users to retry the operation, as opposed to the
older behaviour where the users always see a spinner on the
install/uninstall button and couldn't do anything.
* Remove the SSL enforcement admonition as it is no longer required.
Sync engine can now be installed with or without SSL enforcement
enabled.
---------
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
When the `tableEditorApiAccessToggle` feature flag is enabled, project
creation now appends SQL to revoke default privileges for `anon`,
`authenticated`, and `service_role` on the `public` schema. This runs
after the base image init script's default grants. This is temporary
while we're still using a feature flag. Eventually it'll be moved into
the base image.
Applies to both the main project creation flow and the Vercel deploy
button flow.
Part of the "Secure by Default" initiative – new projects created under
this flag won't automatically expose tables/functions/sequences to the
Data API via default privileges. Users can still opt in at a table
level.
## Notes
Reusing the existing `useDataApiGrantTogglesEnabled()` flag here rather
than creating a new one – it's the same feature surface area and avoids
unnecessary flag proliferation.
## To test
1. **With flag enabled:**
- Enable the `tableEditorApiAccessToggle` flag in PostHog for your user
- Create a new project via the dashboard
- Create a new table
- Confirm in `/project/_/integrations/data_api/settings` that the new
table is not exposed by default
2. **With flag disabled:**
- Disable the flag (or use a different user without it)
- Create a new project
- Verify default privileges are intact and tables are accessible via the
Data API as usual
3. **With RLS event trigger enabled too:**
- Enable both the feature flag and the "enable RLS event trigger"
checkbox during project creation
- Verify both SQL statements run correctly on the new project
---------
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
## Context
Just a nit change to float the status code from status page API into
incident-status endpoint so its clearer what the error is from the
network tab
---------
Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
## 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?
When un-pausing the dashboard, the project home page on platform shows
undefined rather than the default state of "URL not available"
## Ways to test
You can pause and then unpause a project to see if this works correctly
## feat(sso): improve SSO management UX (safe deletion + invitation type
selection)
This PR improves the SSO management experience by introducing a safer
deletion flow for SSO providers and allowing explicit control over
invitation authentication type.
## SSO Provider Deletion Improvements
The SSO provider deletion flow has been redesigned to better communicate
the impact of the action and prevent accidental destructive operations.
### UX Improvements
* Replace `ConfirmationModal` with `TextConfirmModal` in `SSOConfig`
* Require typing the SSO domain to confirm deletion
* Display the number of organization members authenticating via SSO who
will be removed
* Add destructive visual styling and clear warnings about irreversible
consequences
* Update confirmation button label to emphasize impact:
* `I understand, delete SSO provider and members`
### Warning Content
The modal now clearly communicates:
* The domain being deleted
* That SSO authentication will be disabled
* That SSO-authenticated members will be permanently removed
* That those members must be re-invited to regain access
If SSO members exist, a highlighted destructive warning box shows:
```
X organization member(s) who authenticate via SSO will be permanently removed
```
### Implementation Details
* Add `useOrganizationMembersQuery` to fetch organization members
* Calculate SSO members by filtering `is_sso_user === true`
* Only display the member warning when the count > 0
* Modal uses `variant="destructive"` and `size="small"`
This pattern follows the existing **Delete organization** confirmation
flow.
### Initial Delete Support
This PR also introduces the underlying deletion functionality:
* Add `useSSOConfigDeleteMutation`
* Add delete button (trash icon, danger styling) in the SSO config
footer
* Layout mirrors `CustomDomainDelete` pattern:
* delete button on the left
* save/cancel actions on the right
* Success toast shown after deletion
* Form resets to explicit default values after deletion
## Invitation Type Selection
Organizations with SSO configured can now explicitly choose the
authentication method when inviting new members.
Previously, invitations always inherited the inviter's authentication
method. This made it difficult to support mixed authentication
organizations.
### New Invitation Options
When SSO is enabled, the invite dialog now shows an **Invitation type**
dropdown:
* **Automatic (based on your account)**
Default behavior; inherits authentication method from the inviter.
* **Require SSO authentication**
Sends an SSO invitation.
* **Email/password authentication**
Sends a non-SSO invitation.
### Implementation Details
* Add `useOrgSSOConfigQuery` to detect if SSO is configured
* Add `requireSso` field to the form schema with enum:
* `auto`
* `sso`
* `non-sso`
* Only display the dropdown when the organization has an SSO provider
* Transform form values before sending to the backend:
```
sso -> { requireSso: true }
non-sso -> { requireSso: false }
auto -> {} (omit parameter)
```
* Update `OrganizationCreateInvitationVariables` to include optional
`requireSso`
* Preserve backward compatibility by only sending the field when
explicitly set
## Bug Fixes
* Attribute mapping preset buttons (Azure, GSuite, Okta) now properly
mark the form as dirty so the save button becomes enabled
* Form reset after deletion now uses explicit default values instead of
the last saved state
## Problems Solved
This PR addresses several UX issues:
1. Deleting an SSO provider previously used a simple confirmation with
no explanation of impact
2. Users could not see how many members would be affected by deletion
3. The destructive and irreversible nature of the action was not
visually emphasized
4. Invitations always inherited the inviter's auth method
5. Organizations could not intentionally mix SSO and non-SSO users
## Types
TypeScript types in `api-types` were updated to support the new
`require_sso` parameter.
---------
Co-authored-by: Chris Stockton <chris.stockton@supabase.io>
Co-authored-by: Ali Waseem <waseema393@gmail.com>
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
When the dashboard hits a DB connection timeout, users currently see a
raw error message with no
path forward. This PR adds an inline troubleshooting system that detects
known error types and
surfaces contextual next steps — restart the DB, read the docs, or debug
with AI.
## Changes
- New ErrorDisplay component (packages/ui-patterns) — styled error card
with a title, monospace error
block, optional troubleshooting slot, and a "Contact support" link that
always renders. Accepts
typed supportFormParams to pre-fill the support form.
- Error classification in handleError (data/fetchers.ts) — on every API
error, the message is tested
against ERROR_PATTERNS. If matched, handleError throws a typed subclass
(ConnectionTimeoutError
extends ResponseError) instead of a plain ResponseError. Stack traces
now show the exact error
class. All existing instanceof ResponseError checks continue to work.
- ErrorMatcher component — reads errorType from the thrown class
instance, does an O(1) lookup into
ERROR_MAPPINGS, and renders the matching troubleshooting accordion as
children of ErrorDisplay.
Falls back to plain ErrorDisplay for unclassified errors.
- Connection timeout mapping — first error type wired up, with three
troubleshooting steps: restart
the database, link to the docs, and "Debug with AI" (opens the AI
assistant sidebar with a
pre-filled prompt).
- Telemetry — three new typed events track when the troubleshooter is
shown, when accordion steps are
toggled, and which CTAs are clicked.
## Adding a new error type
1. Add a class to types/api-errors.ts
2. Add { pattern, ErrorClass } to data/error-patterns.ts
3. Create a troubleshooting component in errorMappings/
4. Add an entry to error-mappings.tsx
## Context
Related to FE-2557
Part of shifting manually written dashboard queries into
packages/pg-meta where
- pg-meta can be code owners of
- we can write tests for the queries
This PR just shifts all the `.sql.ts` files that we previously created
into packages/pg-meta
There's still other areas where we need to shift over as well which I'll
address in subsequent PRs
## Notable changes
- `getTableRowsCountSql` -> Opted to shift `formatFilterValue` logic out
before calling this method (ref `table-rows-count-query`)
- `getDeleteOldCronJobRunDetailsByCtidSql` -> Opted to shift
`validatePageNumber` logic out before calling this method (ref
`CronJobsTab.useCleanupActions`)
`/incident-status` and `/incident-banner` are not cached because they
include auth cookies which busts Vercel cache. This PR add `credentials:
omit` since they calls don't need auth cookies and they're same for all
users.
The incident queries have been hammering statuspage and incident.io API
endpoints which has resulted in 429 and 75% of all requests failing.
This PR sets the retry on fail to 4s, 16s, 64s, 256s and 300s.
Previously it was set to 2s, 4s, 8s, 16s and 32s.
## 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 introduces Query Insights. It's the first edition of possible
future updates. This takes our old prototype and builds upon it for a
more action driven insights view.
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Ali Waseem <waseema393@gmail.com>
Feature
## What is the current behavior?
Incident banner logic depends on StatusPage and Supabase project for
metadata.
## What is the new behavior?
New incident banner logic that depends only on incident.io. Displays in
non-production environments for now because I haven't wired up the rest
of the workflow. This is just to allow a total end-to-end
testing/playground for test incidents <-> Slack <-> preview dashboard
for people to try out the UX.
## Additional context
You can test using my [test
incident](https://app.incident.io/supabase/incidents/405). This has
severity minor, so the preview site should have a banner. Toggle to
informative, hard refresh dashboard with cache off, and banner should
disappear. Toggle back to minor, hard refresh without cache again, and
banner should reappear. Same thing if you edit the "Banner shown" field
from 1 to -1 and back.
## Problem
In local/self-hosted mode, tables incorrectly show "API disabled" even
when they have valid RLS policies.
This happens because:
1. `project.connectionString` is `null` for local/self-hosted (defaults
to null per API types)
2. `useTablesRolesAccessQuery` has `!!connectionString` in its enabled
condition
3. The query never runs, so the UI can't determine actual API access
status
## Solution
Removed `!!connectionString` check from `useTablesRolesAccessQuery`'s
enabled condition.
This is safe cause:
- likewise `executeSql` already handles null/empty connectionString via
`connectionString ?? ''`
For local/self-hosted, the query works without connectionString (pg-meta
uses direct database connection)
The query now runs and correctly works
Before:
<img width="1577" alt="Before fix - API disabled shown incorrectly"
src="https://github.com/user-attachments/assets/0510fe38-a4ff-4898-aacb-b2ec8f1a2182"
/>
After:
<img width="1128" alt="After fix - API status displays correctly"
src="https://github.com/user-attachments/assets/5784b76b-f7e7-4281-ac40-57408a17a294"
/>
- Closes#43081
Co-authored-by: Andrey A. <56412611+aantti@users.noreply.github.com>
Adds a new toggle in:
<img width="1161" height="356" alt="Screenshot 2026-03-10 at 17 17 06"
src="https://github.com/user-attachments/assets/b09ac1aa-a8f5-4fb4-8771-f113b140eac8"
/>
Other changes:
- form submissions with no table/function changes were failing because
an empty string got passed to executeSql. Added an early return when
there's nothing to execute
To test:
- Ensure the form is still in working order
- Create some tables and functions with the toggle on add off and make
sure your selected default applies
## Context
Related to dashboard scalability
Previous PR: https://github.com/supabase/supabase/pull/42856
Note: Changes are all feature flagged still and I'm still not entirely
convinced with the current UX
Will iterate as as go along, and only make this publicly available when
we're satisfied with the behaviour
Adds a "Dashboard preference" section to the project settings
<img width="265" height="740" alt="image"
src="https://github.com/user-attachments/assets/6ce1aa19-26c2-47c6-a9c4-595137266631"
/>
In which users can then select which database they'd like to use for
read queries run from the dashboard
Note: Everything is local storage for now, but we'd need middleware
support if we want to make this setting persist for all users on the
project
<img width="791" height="434" alt="image"
src="https://github.com/user-attachments/assets/e651d6d9-fed4-4da4-b552-c9f93f8d46d3"
/>
Added a dialog as well to further explain what this implies
<img width="610" height="312" alt="image"
src="https://github.com/user-attachments/assets/0aa957af-cb51-476f-aa79-8948a7cbe5ae"
/>
## To test
- Choosing a replica in dashboard preferences will only affect the table
editor as thats the only place that's set up so far to use a replica for
read queries (I'll need to follow up for other parts of the dashboard in
subsequent PRs)
### Changes
- Adds a dismissible banner prompting paid org users to add a Tax ID to
their billing settings
- Only shown to users with billing read permissions on orgs with a paid
plan and no Tax ID set
- Dismissal is persisted per-org via localStorage; banner also
auto-hides when a Tax ID is added
### Testing
- Log in as a user with no billing permissions into a Free Plan Org with
no tax id: no banner is shown
- Log in as a user with billing permissions into a Free Plan Org with no
tax id: no banner is shown
- Log in as a user with billing permissions into a Paid Plan Org with no
tax id
- Assert banner appears at the top
- Head to `/org/_/billing` with a paid Org. Change your billing country
to a not support one (like Paraguay) and click save. Assert that the
banner disappears. Change it back to continue testing.
- Click dismiss: banner disappears and stays dismissed across
navigation/refresh
- Log in as a user with billing permissions into a different Paid Plan
Org with no tax id
- Add a Tax ID via billing settings, assert that the banner disappears
immediately
<img width="1911" height="50" alt="image"
src="https://github.com/user-attachments/assets/d6208d6d-0939-4ff6-9613-5c687e7c622e"
/>