Commit Graph
371 Commits
Author SHA1 Message Date
Joshen Lim d6c81b66c9 Apply scrollBeyondLastLine for CodeEditor in QueryEditor and Logs Explorer (#51082)
## Context

As per PR title - this was the behaviour for the SQL Editor and figured
it makes sense to also have this behaviour in the Explorer QueryEditor +
Logs Explorer where the main UX is writing queries, and lets the user
bring the active section of the code closer to the middle of the
viewport (rather than right at the bottom)
<img width="790" height="305" alt="image"
src="https://github.com/user-attachments/assets/07eb63fa-1bb9-4abe-859e-2968a73e7ca5"
/>


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

## Summary by CodeRabbit

* **Editor Improvements**
* Query editors now allow scrolling beyond the final line, providing
more room to position the last lines on screen.
* The SQL editor no longer forces the decoration area to zero width; it
now uses Monaco’s default width behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-10-01 11:20:41 +08:00
Danny White d067e81a69 fix(ui): align primary colours across text, buttons, and controls (#50697)
## Problem

Primary colour serves readable text and selected controls, but those
uses need different shades. Light mode needs darker text, while dark
mode needs a deeper button fill. Fixed brand green on interactive chrome
also prevents a custom primary hue from carrying through the interface.
Some slider tracks and selected text are hard to read.

## Solution

- Keep `--primary` for accessible text and small selected indicators.
Use `--primary-solid` for button fills, which need a deeper shade in
dark mode.
- Add `--primary-bright` for focus rings, selected control chrome, chart
accents, and other interactive highlights. It follows `--primary-hue`;
`brand-*` stays fixed for Supabase identity.
- Make slider troughs clearer and text selection translucent with theme
foreground text.
- Document the split in the design-system colour guide.

| Before | After |
| --- | --- |
| <img width="980" height="244" alt="Before: light mode primary
controls"
src="https://github.com/user-attachments/assets/dfae325d-0dfe-4231-8bcd-3f89c4b9d793"
/> | <img width="982" height="204" alt="After: light mode primary
controls"
src="https://github.com/user-attachments/assets/5fdcb531-a6e3-4549-8a13-9d9a5ebe6e20"
/> |
| <img width="610" height="120" alt="Before: slider track"
src="https://github.com/user-attachments/assets/04f768e0-51e8-4d06-9b97-c52f4a34f122"
/> | <img width="622" height="126" alt="After: slider track"
src="https://github.com/user-attachments/assets/95127f4e-13dc-4f0f-b63c-cf5d70a28b42"
/> |
| <img width="652" height="512" alt="Before: dark mode controls"
src="https://github.com/user-attachments/assets/3f88de66-90cc-40ee-8cf1-b5f4eb87b09a"
/> | <img width="658" height="498" alt="After: dark mode controls"
src="https://github.com/user-attachments/assets/906bec30-6ca1-4614-9fb3-6cf5e5feec22"
/> |

## Review instructions

1. Compare light and dark mode in the [colour usage
guide](https://design-system-git-dnywh-fix-bright-brand-chrome-supabase.vercel.app/design-system/docs/color-usage#primary-and-brand-colors).
Check primary ink, primary-solid, primary-bright, and fixed brand
swatches.
2. In Studio, open the ‘new table’ sheet in [Table
Editor](https://studio-staging-git-dnywh-fix-bright-brand-chrome-supabase.vercel.app/dashboard/project/_/editor).
Tab through the new table sheet's fields and toggles. Check the focus
rings, selected controls, and the sheet's edges in both themes. You do
not need to save a table.
3. Select text in Studio in both themes, including a link or
primary-coloured label. The selection and text should remain legible.
4. Check the
[Field](https://design-system-git-dnywh-fix-bright-brand-chrome-supabase.vercel.app/design-system/docs/components/field)
Price Range slider: the unused track should remain visible in both
themes. The selected field card border should follow primary-bright.
5. Check the
[Button](https://design-system-git-dnywh-fix-bright-brand-chrome-supabase.vercel.app/design-system/docs/components/button)
and [Radio
Group](https://design-system-git-dnywh-fix-bright-brand-chrome-supabase.vercel.app/design-system/docs/components/radio-group)
previews. In dark mode, `primary` button fill should be deeper than
primary
[text](https://design-system-git-dnywh-fix-bright-brand-chrome-supabase.vercel.app/design-system/docs/color-usage#text);
selected radios should remain readable.
2026-09-24 09:56:31 +10:00
Danny White ec53175b8a refactor(ui): rename text-brand to text-primary (#50564)
## What kind of change does this PR introduce?

Refactor. Follow-up to #49871.

## What is the current behavior?

Branded (green) text still uses the `text-brand` classname while the
colour comes from `--primary`.

## What is the new behavior?

**Rename-only:** `text-brand` → `text-primary` across callsites and
docs. Leftover `bg-brand` / `border-brand` alias to `brand-default`. No
intentional colour changes in this PR.

This better matches how we treat our green in other components and
props, like `variant="primary"` for green buttons.

## To test

On light mode: smoke-test that branded text still looks like #49871
(readable green, not the bright fill).

-
[Homepage](https://zone-www-dot-com-git-dnywh-depr-316-text-brand-de2380-supabase.vercel.app/):
“Scale to millions” uses `text-primary`
- [Docs
homepage](https://docs-git-dnywh-depr-316-text-brand-to-primary-supabase.vercel.app/docs):
branded links like “More on self-hosting” are still readable
- [Typography
docs](https://design-system-git-dnywh-depr-316-text-brand-to-primary-supabase.vercel.app/design-system/docs/typography):
documents `text-primary`
- [Colour
usage](https://design-system-git-dnywh-depr-316-text-brand-to-primary-supabase.vercel.app/design-system/docs/color-usage):
`text-primary` is visibly darker than `bg-brand-default` _on light mode_
- [Studio auth
providers](https://studio-staging-git-dnywh-depr-316-text-brand-to-60fa6c-supabase.vercel.app/dashboard/project/_/auth/providers):
enabled provider badge text readable; status dot stays bright green

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

* **Style**
* Updated branded text, link hover states, icons, badges, indicators,
and highlighted content across the Design System, Docs, Studio, Learn,
UI Library, and marketing experiences to use the primary theme color.
* Updated syntax highlighting and table-of-contents styling for
consistent primary-color presentation.
  * Refined brand color fallback behavior for bright fills and borders.

* **Documentation**
* Updated color-usage and typography guidance to recommend the primary
text utility.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-22 16:19:03 +10:00
Danny WhiteandJoshen Lim a31ca2bad0 fix(ui): make brand text readable across themes (#49871)
## What kind of change does this PR introduce?

Bug fix and design-system update. Resolves DEPR-316.

Follow-up rename (`text-brand` → `text-primary`) is in a dedicated PR
(https://github.com/supabase/supabase/pull/50564) stacked on this one.

## What is the current behavior?

`text-brand` resolves to the canonical bright brand green in places that
need readable text, which fails WCAG AA on light surfaces. A separate
`text-brand-display` token adds another green for large type.

## What is the new behavior?

- `text-brand` maps to accessible `--primary` (light mode darkened to
meet ~4.5:1 AA)
- `--hue` / `--primary-hue` aligned to 157.5
- `text-brand-display` removed; former display callsites use
`text-brand`
- Bright fills/borders stay on `brand-default`
- Design-system colour and typography docs updated

| Before | After |
| --- | --- |
| <img width="514" height="112" alt="CleanShot 2026-09-02 at 11 13
09@2x"
src="https://github.com/user-attachments/assets/4e0138a9-a32d-4e4c-a426-90736706e1e7"
/> | <img width="512" height="138" alt="CleanShot 2026-09-21 at 11 42
05@2x"
src="https://github.com/user-attachments/assets/164cc5b1-a0c5-4e93-95f1-80016641a114"
/> |
| <img width="864" height="266" alt="CleanShot 2026-09-02 at 11 13
53@2x"
src="https://github.com/user-attachments/assets/3c1ca53f-bf9e-431e-bc15-816b4a275b8e"
/> | <img width="882" height="248" alt="CleanShot 2026-09-21 at 11 41
37@2x"
src="https://github.com/user-attachments/assets/24828e7b-ed6b-44cb-b9dc-becc3398bdfc"
/> |
| <img width="782" height="692" alt="CleanShot 2026-09-02 at 11 16
30@2x"
src="https://github.com/user-attachments/assets/fc871977-77bc-47fb-9e0e-9284e0ecd5cc"
/> | <img width="730" height="690" alt="CleanShot 2026-09-21 at 11 42
52@2x"
src="https://github.com/user-attachments/assets/bf479515-d5f9-471e-b82d-f097c0f4b56c"
/> |
| <img width="480" height="306" alt="CleanShot 2026-09-02 at 11 18
53@2x"
src="https://github.com/user-attachments/assets/03f341f4-f02e-44f8-a2b2-8c31670d0427"
/> | <img width="470" height="300" alt="CleanShot 2026-09-21 at 11 43
19@2x"
src="https://github.com/user-attachments/assets/9df18217-d5e6-48b8-ba0b-579d2664b94b"
/> |
| <img width="960" height="300" alt="CleanShot 2026-09-02 at 11 32
04@2x"
src="https://github.com/user-attachments/assets/6b1d9373-7a71-4247-81ff-26441604b09d"
/> | <img width="980" height="306" alt="CleanShot 2026-09-21 at 11 44
13@2x"
src="https://github.com/user-attachments/assets/41ad4784-02ec-4b29-b860-32af9fa79aa8"
/> |
| <img width="924" height="214" alt="CleanShot 2026-09-02 at 11 34
44@2x"
src="https://github.com/user-attachments/assets/1de661fe-c7b6-499b-a94f-e4737436ec79"
/> | <img width="752" height="162" alt="CleanShot 2026-09-21 at 11 44
56@2x"
src="https://github.com/user-attachments/assets/1811890f-0660-4445-84e9-447720954fa1"
/> |

## To test

Test each callsite **in light mode** (dark mode is largely unchanged).

### WWW

-
[Homepage](https://zone-www-dot-com-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/):
“Scale to millions” uses readable brand text (display token is gone)
-
[Careers](https://zone-www-dot-com-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/careers):
small “Careers” eyebrow readable; green dividers stay bright
`brand-default`
-
[Contact](https://zone-www-dot-com-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/contact-us):
email / policy links use readable brand text
-
[Regions](https://zone-www-dot-com-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/regions):
“Ask about early access to BYOC” readable

### Docs

- [Docs
homepage](https://docs-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs):
“DOCS” wordmark and resource links readable
- [Database
overview](https://docs-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs/guides/database/overview):
nav / footer brand links readable
- [JavaScript
reference](https://docs-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs/reference/javascript/introduction):
active sidebar treatment readable

### Design system

-
[Typography](https://design-system-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs/typography):
documents `text-brand` only (no display)
- [Colour
usage](https://design-system-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs/color-usage):
`text-brand` vs `bg-brand-default`
- [Design-system
homepage](https://design-system-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/):
brand text examples across themes

### Studio

- [Auth
providers](https://studio-staging-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/dashboard/project/_/auth/providers):
enabled provider badge text readable; status dot stays bright
- [Database
policies](https://studio-staging-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/dashboard/project/_/database/policies?new=true):
template hover text more legible
- [Database
connections](https://studio-staging-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/dashboard/project/_/observability/connections):
“Live” status readable; animated dot stays bright green

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-09-22 10:07:28 +10:00
Matt RossmanandJoshen Lim 4bb36b944f feat(studio): let High Compliance projects opt-in to Assistant data access (#50548)
Orgs with the HIPAA add-on had the Assistant's opt-in level forced to
`disabled` on any project marked High Compliance, regardless of what the
org picked in its AI settings. The restriction predated our AI provider
BAAs. The consequence is those users see the Assistant failing to answer
questions about their data w/ no clear path how to fix it, even though
the LLM provider supports this use case.

This PR removes these Assistant restrictions on the server and client so
those projects honor the org's chosen level. Braintrust conversation
tracing is unchanged and still blocked for these projects, see [this
test
case](https://github.com/supabase/supabase/blob/b9800ccf16/apps/studio/lib/ai/braintrust-logger.test.ts#L16-L20).
See
[comments](https://linear.app/supabase/issue/AI-1153/allow-hipaa-orgs-to-opt-in-to-assistant-data-access-for-high#comment-485a0d46)
for legal approval and conditions.

The client-side changes enable features like "Debug with AI" on SQL
query failures, “Generate/Rename with AI” for snippet titles, and
generated Assistant chat titles for these customers.

The AI opt-in copy now adds a reminder to obtain consent from data
subjects, linking the [shared responsibility
model](https://supabase.com/docs/guides/deployment/shared-responsibility-model)
based also on [this
comment](https://linear.app/supabase/issue/AI-1153/allow-hipaa-orgs-to-opt-in-to-assistant-data-access-for-high#comment-f81ee610).

<img width="400" alt="CleanShot 2026-09-17 at 5 01 02 PM@2x"
src="https://github.com/user-attachments/assets/d02123f2-3e32-4d83-9f98-7d15e59222ef"
/>

To test with a HIPAA-enabled project in staging, you can use this [Plan
Change
[Staging]](https://app.hex.tech/supabase/app/Plan-Change-Staging-032BD32jo1EaisCS85qunf/latest)
Hex to add the HIPAA add-on. Once the add-on is present, you can turn on
High Compliance from a project's settings. Also in org settings, crank
up the Assistant data opt-in level and verify the Assistant is able to
answer questions about the project's data.

My results testing with opt-in level "Schema, Logs & Database Data":

| High compliance setting | Data opt-in working |
|--------|--------|
| <img width="1302" height="422" alt="CleanShot 2026-09-17 at 5 03 36
PM@2x"
src="https://github.com/user-attachments/assets/c416371b-2eb8-49df-9c07-6d8eababb443"
/> | <img width="1566" height="1516" alt="CleanShot 2026-09-17 at 5 05
14 PM@2x"
src="https://github.com/user-attachments/assets/39624355-7f8f-46ce-9f08-a8acfb9da830"
/> |

Closes AI-1153


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

## New Features

- AI-assisted query renaming, snippet title generation, debugging, and
tools now follow organization AI opt-in settings rather than project
HIPAA status.
- Debugging assistance and AI actions remain available for eligible
users without additional HIPAA-based blocking.
- AI metadata warnings consistently show standard opt-in messaging and
permission settings.
- AI settings remind users to obtain consent before entering personal
data and link to shared responsibility guidance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-09-18 08:21:50 -04:00
Joshen Lim cdbe2963fa Add DownloadResultsButton to explorer query editor (#50563)
## Context

Adds the `DownloadResultsButton` component to the footer of the
explorer's query editor - will show up in notebook + query tab

<img width="1147" height="907" alt="image"
src="https://github.com/user-attachments/assets/141278a8-1e00-424e-84ec-8ddb7cf0a96b"
/>
<img width="1152" height="913" alt="image"
src="https://github.com/user-attachments/assets/0e4a48b0-ebc3-473e-8bc0-19ab633e1904"
/>


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

- **New Features**
- Added a results footer displaying row counts and optional row limits.
  - Added download and export actions when query results are available.
  - Standardized the results footer across query and notebook previews.
- Added keyboard shortcut hints to export options when shortcuts are
enabled.

- **Improvements**
- Export actions now support read-only result sets without changing
displayed output.
- Export menu sizing and shortcut labels adapt to the enabled shortcut
configuration.
  - Improved accessibility with a label for refreshing logs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-18 17:13:44 +08:00
Joshen Lim 71d58cba7f Joshenlim/fe 4401 re sql editor silently points to the primary instead of (#50513)
## Context

Fixes the following 2 issues with the database selection in the SQL
Editor
- An errant `useEffect` was resetting the `selectedDatabaseId` back to
the primary every time the `databases` list from `useReadReplicasQuery`
changed reference (not just on first load).
- `QuerySourceMenu` kept showing "Read Replica" even after selection had
reverted
- Was using local storage value as the `identifier` for
`DatabaseParametersSubMenu`, when it should use the valtio store as the
source of truth

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

- **Improvements**
- The SQL Editor now remembers the last selected database between
sessions.
- Your saved database selection is restored when available; otherwise,
the project’s primary database is selected automatically.
- Query source settings now stay synchronized with the database
currently selected in the SQL Editor.

- **Bug Fixes**
- Background database refreshes no longer unexpectedly reset your
selected read replica to the primary database.
- Database selection now waits for saved preferences to load, preventing
a brief incorrect selection.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-17 12:34:13 +00:00
Joshen Lim 558bee9ebf Improve SQL Editor auto completion for column names (#48734)
## Context

Currently with the SQL Editor, the auto-completion via intellisense only
works nicely with the `.` operator - e.g after keying in a schema and
trying to find a table as such:
<img width="500" alt="image"
src="https://github.com/user-attachments/assets/86ec8455-47b9-43d3-925a-c13d0fd6ac44"
/>

But lacks support for finding the columns of a table after a `where`
clause - so the changes here addresses that by mainly adjust the
`PgSQLCompletionProvider`

Also addresses a number of type fixes (replaces all the `any` types)

<img width="500" alt="image"
src="https://github.com/user-attachments/assets/e23672a6-2b48-4a98-b300-69f822d12b38"
/>

<img width="415" height="319" alt="image"
src="https://github.com/user-attachments/assets/e6ee64d2-90dd-47d6-9fd2-e8b07821ebb6"
/>



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

* **New Features**
* Improved PostgreSQL SQL editor suggestions with table, column, alias,
schema, and join-aware completions.
* Added context-aware support for statements, quoted identifiers,
subqueries, and qualified columns.
  * Enhanced PostgreSQL function signature assistance.
* Added safer behavior when database metadata is incomplete or
unavailable.

* **Bug Fixes**
  * Prioritized relevant columns and removed duplicate suggestions.

* **Tests**
* Added comprehensive coverage for SQL parsing, metadata handling, and
completion behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 12:34:20 +08:00
Danny White 476d4a5851 refactor(ui): drop redundant Button variant="default" props (#50161)
## What kind of change does this PR introduce?

Mechanical cleanup on top of the Button default-variant change (#50160).

## What is the current behavior?

Many callsites still pass `variant="default"` even though that is now
the component default.

## What is the new behavior?

Removes redundant static `variant="default"` from legacy `Button` and
`ButtonTooltip` callsites. Keeps explicit defaults where they document
the API:

- `button-default.tsx` and `button-sizes.tsx` demos
- `DocsButton`, which pins neutral styling at the wrapper boundary

## To test

Studio:

- [Auth → Rate
Limits](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/auth/rate-limits):
dirty the form so Cancel appears; Cancel stays neutral, Save stays green
- [Project Settings → API
Keys](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/settings/api-keys):
`DocsButton` in the header actions stays neutral

Design system:

- [Design system →
Button](https://design-system-git-dnywh-dc924ac1-supabase.vercel.app/design-system/docs/components/button):
`button-default` / `button-sizes` still show explicit default styling;
Primary (green) is restricted to the Primary section (and `asChild`)

WWW:

- [www → Brand
assets](https://zone-www-dot-com-git-dnywh-dc924ac1-supabase.vercel.app/brand-assets):
Download logo kit / Download button kit stay neutral
2026-09-11 17:05:26 +10:00
Gildas GarciaandAlaister Young 737b8595f2 Update API types (#50234)
## Problem

platform, v1 and v2 have been already completely migrated and introduced
some changes.

Some types have been renamed, some outputs and inputs updated.

## Solution

- Update the API types
- Fix the TS errors

## Update

Taking this over to unblock #50134, which needs the new scoped token
permission ids from the regenerated types.

- Merged `master`.
- Regenerated `api-v2.d.ts` from the production spec. The previous files
came from a local API that exposed a webhook events endpoint production
doesn't have yet. Production has since added standardized 400 error
responses on the v2 organization endpoints. `api-v1.d.ts` and
`platform.d.ts` already matched production.
- Fixed `verify-production-types`. It formatted the regenerated files in
a temp directory outside the repository, so Prettier fell back to its
defaults and the comparison could never match the committed files. It
now passes the repository config explicitly. `pnpm api:verify-types`
passes on this branch.
- Verified locally: `pnpm typecheck`, `pnpm api:verify-types`, Studio
unit tests.

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

* **Bug Fixes**
* Preserved descriptions when saving, sharing, moving, or unsharing
notebooks, reports, SQL snippets, and saved queries.
* Improved handling of empty or null values across notebook
descriptions, billing usage, pooler settings, and infrastructure fields.
* Improved read-replica connection handling, including read-only
connection strings.
* Updated storage configuration and capability handling to match current
settings.

* **API and Compatibility**
* Updated organization, project, storage, OAuth, billing, and
infrastructure data handling to match current API responses.
  * OAuth app creation and updates now require scopes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-09-11 12:17:49 +08:00
Joshen Lim 8ac64a4349 Add copy notebook as markdown action (#50200)
## Context

Adds a "Copy as Markdown" CTA for notebooks
<img width="265" height="198" alt="image"
src="https://github.com/user-attachments/assets/5eccf36e-24ea-4d2f-b1cf-72d5353b70a2"
/>

Query cell titles will be rendered as h3 tags and labelled either
Postgres or Logs - Clickhouse (with time range)
The query content will then be rendered as triple backticks with `sql`
e.g `
```sql...```
`

Query results will be copied to markdown if the query has been run, will otherwise be omitted
Also, if the query was updated (e.g content, source, etc) after it was run (as the result is hence stale), result will also be omitted
e.g:
| Notebook | Markdown |
| --- | --- |
| <img width="1291" height="630" alt="image" src="https://github.com/user-attachments/assets/c49f23e5-c70b-46dd-a298-6e1a90cd30d7" /> | <img width="731" height="536" alt="image" src="https://github.com/user-attachments/assets/4bbe3041-bd8e-42d3-86d2-1691e7a6bc7b" /> |
| <img width="1220" height="832" alt="image" src="https://github.com/user-attachments/assets/67de523a-18f7-4f1b-b764-7f0f3152f9e7" /> | <img width="757" height="803" alt="image" src="https://github.com/user-attachments/assets/d217504b-bee6-4088-9049-87ff647b9bc7" /> |



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

* **New Features**
  * Added Markdown export for notebook queries, results, errors, and time ranges.
  * Added error notifications when copying notebook content fails.

* **Bug Fixes**
  * Prevented stale query results after relevant source or time-range changes.
  * Improved Markdown export for queries containing backticks.
  * Escaped backslashes, pipes, and line breaks in Markdown tables.

* **Style**
  * Adjusted spacing for empty query-result messages.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-11 11:25:22 +08:00
Danny White 1131e3e2ce fix(ui): default Button variant to default instead of primary (#50160)
## What kind of change does this PR introduce?

Bug fix / design-system alignment for the legacy `Button` from `ui`.

## What is the current behavior?

Omitting `variant` on the legacy `Button` falls back to brand-green
`primary`. That makes accidental greens easy, and it is hard to spot the
real main action on busy pages.

## What is the new behavior?

- Legacy `Button` now defaults to neutral `default`
- Intentional primary CTAs (create, save, submit, marketing CTAs, and
matching `ButtonTooltip` usages) now set `variant="primary"` so their
appearance is unchanged
- Neutral actions that previously relied on the old fallback (cancel,
close, back, dashboard nav, and similar) become grey/white
- Design-system docs updated; regression tests cover the new default

`Button_Shadcn_` is unchanged. It already uses its own CVA default.

This is PR 1 of 2 in a stack. PR 2 drops now-redundant
`variant="default"` props.

## To test

Studio (http://localhost:8082):

- `/sign-in`: Sign in stays green
- Open a project → Database → Tables: New table stays green
- Auth → Users → Invite: Invite user stays green; Cancel / dismiss
controls stay neutral
- Project Settings → General: edit a field so Cancel and Save appear.
Cancel is neutral, Save is green

Design system (http://localhost:3003):

- Components → Button: default demo is neutral; primary demo is green;
featured preview is the default variant

Marketing (optional):

- www header: Start your project stays green; logged-in Dashboard is
neutral

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

- **Style**
- Buttons now default to a neutral style, while primary actions across
Studio, documentation, marketing pages, forms, dialogs, and error states
use prominent primary styling.
- Updated button examples and previews clarify the distinction between
default and primary variants.
  - Event registration now includes a directional arrow icon.

- **Tests**
- Added coverage confirming default button styling and explicit primary
styling behave as expected.
- Updated related test fixtures to use primary styling where
appropriate.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-10 11:23:17 +10:00
Joshen Lim c37e756983 Trigger update snippet when toggling favorite (#50121)
## Context

Currently in the SQL Editor, toggling "favourite" for a snippet doesn't
persist unless you manually save the snippet (which expects a change in
the snippet's content before allowing so) - which is a bit of an odd UX

This used to work before we introduced manual saving which is currently
the default behaviour for the SQL Editor - `addFavorite` and
`removeFavorite` would add to the `needsSaving` queue which the editor's
save scheduler will subscribe and trigger the save. However the save
scheduler doesn't subscribe to the queue for manual saving mode
([ref](https://github.com/supabase/supabase/blob/master/apps/studio/state/sql-editor/sql-editor-save-scheduler.ts#L90))
- hence toggling favourite on a snippet never triggers a PATCH request.

Am opting to immediately trigger a PATCH request when toggling
favourites which is a bit more of an expected UX imo

One thing to note is that favoriting a snippet essentially does a save
on the snippet - which means the contents will be persisted as well,
although i think this is alright

## To test
- [ ] Verify that toggling favourite for a SQL snippet persists
immediately
- Can verify by checking the context menu CTA to see if it's changed
from "Add to favourites" to "Remove from favourites" or vice versa

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

## Summary by CodeRabbit

- **Improvements**
  - Favoriting or unfavoriting SQL snippets now saves immediately.
- Favorite changes are handled consistently across the SQL Editor,
including the utility panel and snippet navigation.
- Pending content saves are coordinated to prevent favorite changes from
being overwritten.
- If saving a favorite fails, the previous favorite state is restored
and an error notification is shown.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-09 15:50:27 +08:00
Joshen Lim db0e6b761b Joshenlim/fe 4304 bring database connections out of feature preview (#50107)
## Context

As per PR title - we're bringing Database Connections out of feature
preview and it'll live on the dashboard by default 🙂
Also deprecating the existing Ongoing queries panel which Database
Connections now supercedes.

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

* **New Features**
* Database Connections is now available without feature-preview
activation.
* The SQL editor’s “View running queries” option now links directly to
Database Connections.

* **Bug Fixes**
* Query cancellation and session termination now refresh database
activity data.

* **Removed**
* Removed the in-editor ongoing queries panel and its termination
controls.
* Removed the Database Connections promotional banner, preview
messaging, settings, and related telemetry.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-08 17:26:24 +08:00
Gildas Garcia 3146650a5a Fix FormItemLayout usages for a11y (#49761)
Follow up of #49637. Usages that impacted tests were fixed in the
previous PR. This PR fixes the other usages so that label are correctly
linked to their inputs.

No visual changes

## How to test

1. Design system: [Form
examples](https://design-system-git-fix-form-item-layout-usages-supabase.vercel.app/design-system/docs/ui-patterns/forms):
moved `FormControl` around the `SelectTrigger` so that the label is
linked to the button (It's actually done like this in the [Select Form
example](https://design-system-git-fix-form-item-layout-usages-supabase.vercel.app/design-system/docs/components/select#form)
and Radix recommend targeting the button too in their
[documentation](https://www.radix-ui.com/primitives/docs/components/select#labelling))
2. [Access
tokens](https://studio-staging-463111oii-supabase.vercel.app/dashboard/account/tokens):
updated usage to fallback on generated ids and fixed the select just
like _1_
3. [New TOTP
factor](https://studio-staging-463111oii-supabase.vercel.app/dashboard/account/security):
updated usage to fallback on generated ids
4. _Studio/Database/Extensions_
(`https://studio-staging-463111oii-supabase.vercel.app/dashboard/project/[PROJECT]/database/extensions`):
updated the extension enabling modal to fallback on generated ids
5. _Studio/Integrations/Vault
(`https://studio-staging-463111oii-supabase.vercel.app/dashboard/project/[PROJECT]/integrations/vault/secrets`):
updated the secret edition modal to fallback on generated ids
6.
_Studio/Observability(`https://studio-staging-463111oii-supabase.vercel.app/dashboard/project/[PROJECT]/observability`):
updated the report creation and edition modals to fallback on generated
ids
7. _Studio/SQL
Editor(`https://studio-staging-463111oii-supabase.vercel.app/dashboard/project/[PROJECT]/sql/new`):
updated the query renaming modal to fallback on generated ids
8.
_Studio/Storage/Analytics(`https://studio-staging-463111oii-supabase.vercel.app/dashboard/project/[PROJECT]/storage/analytics`):
updated the table creation sheet to fallback on generated ids (you must
have a bucket first)
9.
_Studio/Workers(`https://studio-staging-463111oii-supabase.vercel.app/dashboard/project/[PROJECT]/workers`):
updated the worker creation modal to fallback on generated ids (you must
have a bucket first)
10. Updated
[Signup](https://studio-staging-463111oii-supabase.vercel.app/dashboard/sign-up?returnTo=%2Fnew),
[Signin](https://studio-staging-463111oii-supabase.vercel.app/dashboard/sign-in)
and [SSO
Signin](https://studio-staging-463111oii-supabase.vercel.app/dashboard/sign-in-sso)
forms to fallback on generated ids

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

- **Improvements**
- Standardized form field presentation across access tokens,
authentication, reports, integrations, database extensions, SQL editor,
storage, and worker deployment workflows.
- Updated password fields and visibility toggles for more consistent
input behavior.
- Refined token expiration selection, verification code entry, and
dropdown layouts.
- Preserved existing labels, validation, options, and form functionality
while simplifying the interface structure.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-01 15:22:55 +02:00
Gildas Garcia 4f92790587 fix: FormItemLayout does not apply item id correctly (#49637)
## Problem

`<FormItemLayout>` does not apply item id correctly. This can be seen on
https://supabase.com/design-system/docs/ui-patterns/forms: open the
devtool and check the form items labels. They have no `for` attribute.
This makes it harder to correctly test and is an accessibility issue.

Axe devtool actually report it

## Solution

When inside React Hook Form, `<FormItemLayout>` actually generate an
`id` (via `<FormItem>`). However, this `id` is overridden in
`<FormLayout>` and read from context by `<FormLabel>`. Ensure we use the
generated id unless one was provided.

Also updated the paths filters for the CI check so that any changes in
either `ui` or `ui-patterns` triggers the studio unit and e2e tests.

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

- **Bug Fixes**
- Improved form accessibility by ensuring labels consistently connect to
their corresponding input fields.
- React-based forms now correctly preserve field-specific identifiers
when associating labels with inputs.
- Added support for explicitly specifying a label’s input target,
improving compatibility with customized form layouts.
- Updated Studio forms to use consistent control identifiers and
labeling behavior.

- **Quality Improvements**
- Automated validation now also runs when shared UI components and
patterns are updated.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-31 10:32:45 +02:00
Saxon Fletcher 9718eea593 refine role impersonation popover (#49467)
**Old**
<img width="979" height="839" alt="image"
src="https://github.com/user-attachments/assets/7239604f-a37f-483c-84eb-dbafabdeb73c"
/>

**New**
<img width="1185" height="645" alt="image"
src="https://github.com/user-attachments/assets/e699d75f-fd04-47dc-a8da-97f880e39796"
/>


## 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?

Studio UI refinement. This is PR 2 of 2 and depends on #49466.

## What is the current behavior?

The Run SQL query as a role submenu uses the full role-impersonation
card layout, making the nested popover substantially larger than the
surrounding query controls.

## What is the new behavior?

- Adds a compact role-impersonation presentation used only by the query
submenu.
- Uses horizontal FormItemLayout rows and base ToggleGroup, InputGroup,
Input, and Button components.
- Keeps role choices stacked while using tiny controls for user source,
user lookup, external-user fields, and MFA level.
- Keeps authenticated-user controls visible but disabled for Postgres
and Anonymous roles.
- Preserves project-user search, external-user claims, impersonation,
and stop-impersonating behavior.
- Leaves existing role selectors in GraphQL, Table Editor, Realtime, and
other surfaces unchanged.

## Verification

- Focused compact role-selector test
- Studio, UI, and UI Patterns typechecks
- Existing focused Toggle and MultiSelector tests
- Studio ESLint
- Local visual and interaction verification against the supplied
prototype



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

## Summary by CodeRabbit

* **New Features**
* Redesigned role impersonation with role-specific summaries and native
role icons.
* Added native and external user impersonation, including user-source
switching and MFA controls.
* Added user search, external user ID entry, and clearer active-user
controls with accessible labels.

* **Bug Fixes**
* Improved role switching, impersonation clearing, pending selections,
and error recovery.

* **Tests**
* Expanded coverage for role selection, user impersonation, MFA updates,
state transitions, and error handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-08-26 16:28:02 +08:00
claude[bot]andClaude 235488e66b fix(studio): guard two undefined dereferences crashing the table editor and SQL editor (#49412)
<!-- ccr-slack-attribution -->
_Requested by **Ali Waseem** · [Slack
thread](https://supabase.slack.com/archives/C063LNYJJKS/p1787336596649619)_

**Before:** editing a cell in the table editor could throw, and the edit
was silently lost — the typed value vanished and nothing was saved.
Separately, opening the SQL editor could throw before the editor
rendered, and the global error boundary replaced the entire page, so
there was no editor at all until a reload.

**After:** a row change with no matching previous row is a no-op instead
of a throw, and the SQL editor shows its normal loading state instead of
taking down the page.

Two independent undefined guards for two confirmed Sentry crashes, one
per commit so either can be dropped on its own.

**How:** the first commit moves the existing previousRow guard in
`useOnRowsChange` above the `changedColumn` computation that
dereferences it, and drops the non-null assertion that hid the problem
from TypeScript. The second reads the snippet content in
`deriveSnippetIdentity` through optional chaining, so a missing
`snippets` map, or an entry without a `snippet`, resolves to
still-loading — the same answer the old code gave for an id that is not
in the map. Behaviour is unchanged in every case that did not crash.

## 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?

**[K7M, Cannot read properties of undefined (reading
'idx')](https://supabase.sentry.io/issues/7681899596/)** — 4 events / 1
user — in `apps/studio/components/grid/components/grid/Grid.utils.tsx`.
Inside `useOnRowsChange`, the callback passed to
`Object.keys(rowData).find(...)` reads the candidate column off
`previousRow` through a non-null assertion, three lines above the `if
(!previousRow || !changedColumn) return` that was meant to protect it.
`rows.find(...)` returns undefined whenever no row matches, and the
assertion is why TypeScript never flagged the dereference. The four
events came from one user inside about two minutes, so it is
deterministic rather than a one-off, and every throw is an edit the user
loses.

**[K7J, Cannot use 'in' operator to search for a snippet uuid in
undefined](https://supabase.sentry.io/issues/7680905437/)** — 1 event /
1 user, full-page crash — in
`apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts`, line
331. `deriveSnippetIdentity` applies the `in` operator to its `snippets`
argument and then reads `snippets[id].snippet.content`. The parameter is
declared required and non-optional, but `snippets` arrived undefined at
runtime, so `in` threw and the error reached the global error boundary,
which unmounted the whole SQL editor page. The `snippets[id].snippet`
read on the same line is a second unguarded dereference: an entry
without a `snippet` crashes identically.

## What is the new behavior?

Both crashes become no-ops.

- Grid: return early when `previousRow` is missing, then compute
`changedColumn`, with the assertion removed. When a previous row is
found, the code takes exactly the path it took before.
- SQL editor: `snippets?.[id]?.snippet?.content === undefined` replaces
the `in` check. A missing map, a missing entry, and an entry with no
`snippet` all read as still loading, which is what the surrounding code
already does while a snippet is being fetched. The parameter type is
left required, since the only caller (`useSnippetIdentity.ts`) passes
the store's `snippets` record, which is typed as always present — the
type is not the thing that was wrong.

Two test cases are added to the existing `deriveSnippetIdentity` block,
which previously only passed fully populated maps: one for an undefined
`snippets` map, and one for an entry missing its `snippet`.

## Additional context

**Why `snippets` was undefined is unexplained.** The store initialises
it to an empty object
(`apps/studio/state/sql-editor/sql-editor-state.ts:34`) and its only
reassignment writes an object, so there is no code path in studio that
sets it to undefined. This commit is a defensive guard against a crash,
not a root-cause fix, and nothing here should be read as an explanation.

**Verification:** no local checks were possible in the authoring
environment — the checkout has no `node_modules` and `pnpm install`
cannot complete there, so typecheck, lint and the studio unit tests
could not be run. CI on this PR is the only verification.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-24 10:11:44 -06:00
Joshen Lim 7d28bcc26b joshenlim/fe 4204 notebooks intellisense toggle (#49300)
## Context

Adds an intellisense toggle for explorer notebooks similar to SQL editor
+ have QueryEditor render definitions via `useAddDefinition`
<img width="259" height="162" alt="image"
src="https://github.com/user-attachments/assets/278fdabd-1a24-4769-972e-1bce29060463"
/>

So intellisense will be running in the QueryEditor if intellisense is
enabled + source selected is database, otherwise will not run.

<img width="982" height="411" alt="image"
src="https://github.com/user-attachments/assets/19497aa0-36fc-49ab-853d-cb938b5b18e7"
/>


Also updated `useAddDefinition` logic to flush the table columns +
functions cache in react query
- For context in the past we had users run into browser performance
issues when definitions were loaded if their database is really big
- Hence why we originally added this intellisense toggle
- But we previously also required users to refresh the browser after
disabling intellisense, as a manual way to flush the cache
- So this change should remove the need to refresh the browser after
disabling intellisense

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

* **New Features**
* Added PostgreSQL IntelliSense with definitions, formatting, and code
completions in SQL editors.
* Added a notebook option to enable or disable IntelliSense, with the
preference saved between sessions.
  * Improved the notebook’s empty-state appearance.

* **Bug Fixes**
* Improved IntelliSense cleanup and prevented duplicate registrations
when disabled.
* Improved query execution state handling while background IntelliSense
data loads.

* **Tests**
* Added coverage for shared registration, cleanup, preference
persistence, and IntelliSense-related query handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-21 01:47:39 +08:00
Charis 474bf5da4a fix(studio): reset rename form between same-named SQL snippets (#49275)
## 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?

In the SQL Editor, when two snippets are both named "Untitled query" and
one is renamed, the rename modal's state is not reset afterwards.
Opening the rename modal for the second snippet prefills the input with
the first snippet's new name, and the second snippet can't be renamed at
all because the "Rename query" button stays disabled.

`RenameQueryModal` fed the snippet to react-hook-form through the
`values` option, which only re-runs its reset when the values object
deep-changes. Two snippets with the same name (and no description)
produce a deep-equal object, so switching between them never resets the
form — it keeps the previously renamed name and stays non-dirty.

## What is the new behavior?

The form is mounted per snippet (`key={snippet.id}`) with plain
`defaultValues`, so no form state can carry over between snippets
regardless of name collisions. `SQLEditorNav` derives modal visibility
from the selected snippet and clears it on cancel/complete, matching
`SearchList`.

Covered by a new component test in `RenameQueryModal.test.tsx` that
renames one "Untitled query", reopens the modal for a second one, and
asserts the field resets and the second rename submits.

## Additional context

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

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed the rename dialog retaining input from a previously renamed
snippet.
* Ensured the rename form resets correctly after successful submission
and when switching between snippets.
* **Tests**
* Added regression coverage for renaming multiple untitled snippets with
the same original name.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-20 09:09:45 -04:00
Joshen Lim dde45ab06c Joshenlim/fe 4195 explorer queryeditor cmd k completion support (#49248)
## Context

Adds the inline AI completion functionality into Explorer QueryEditor,
similar to what we've got for the existing SQL editor
- Shifts the `ResizableAIWidget` and `InlineWidget` components out of
the SQL Editor folder into `components/ui/AiEditor` to be used by both
SQL Editor and Query Editor
- Consolidates the "proposal" logic that was initially set up for the
Clickhouse Migration functionality with this Inline AI stuff
- Also added the prompt into the proposal header (Refer to the
screenshots below)
- SQL Editor didn't have this - but figured this is useful as context
for the user

<img width="935" height="352" alt="image"
src="https://github.com/user-attachments/assets/3f71539a-dda1-4763-be08-a850bdc8aec6"
/>

Source selected: Database
<img width="922" height="357" alt="image"
src="https://github.com/user-attachments/assets/81e772e6-dcc9-440d-83db-49d0d487dd13"
/>

Source selected: Logs
<img width="920" height="345" alt="image"
src="https://github.com/user-attachments/assets/83f1dae3-cf62-4424-be42-b06e70cb366d"
/>


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

- **New Features**
- Added AI-assisted SQL generation with contextual prompts and
OS-specific guidance.
- Review generated SQL changes in a diff, then accept, reject, or cancel
suggestions.
- Added inline, resizable AI prompt controls with loading and submission
states.
  - Added the Ctrl/Cmd+Shift+K shortcut to run AI SQL generation.

- **Improvements**
  - Added options to disable query execution and run custom actions.
  - Renamed “Recent” to “Recently updated.”
  - Improved editor widget positioning and display behavior.
  - Added clearer error notifications when AI generation fails.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-20 14:05:38 +08:00
Joshen LimandAli Waseem ce2ed77c02 Add clickhouse migration banner to QueryEditor (#49184)
## Context

Adds the clickhouse migration banner into the QueryEditor for explorer
if the source selected is logs - will apply for both the notebook query
cells and query tab

JFYI i've omitted out the diffing view for now, like what've currently
got for the SQL Editor

Got a separate ticket to look into that, but was thinking of waiting for
[this PR](https://github.com/supabase/supabase/pull/49112) from Charis
to go in first

<img width="1391" height="369" alt="image"
src="https://github.com/user-attachments/assets/5880df99-44b5-4a9f-8ff7-c9d7af3bcb93"
/>
<img width="1054" height="474" alt="image"
src="https://github.com/user-attachments/assets/ef5d225b-3b53-4d6d-ab6c-19804e3358e6"
/>


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

* **New Features**
* Added guidance in SQL editors to identify and rewrite legacy logs
queries.
* Integrated rewrite suggestions into the query editor’s existing SQL
diff workflow.
* Increased the height of embedded query editors for improved usability.
* Kept rewrite guidance available when no rewrite is needed or an
attempt is unsuccessful.

* **Bug Fixes**
  * Improved spacing for empty query-result messages.

* **Tests**
* Added coverage for rewrite visibility, acceptance, dismissal, and
no-change outcomes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Ali Waseem <waseema393@gmail.com>
2026-08-19 00:16:00 +08:00
Joshen Lim 097a105663 joshenlim/fe 4176 add role impersonation to explorerquerysourcemenu (#49101)
## Context

Stacked off from https://github.com/supabase/supabase/pull/49098 - adds
role impersonation for both Notebook Query cell + Explorer Query tab

Note that this refactors the role impersonation state a little to
decouple some stuffs to make this work, since the role impersonation
state is global and we need a local state to support this UX

Similarly to row limit, for query tab its intentional that for now that
the role impersonation isn't scoped to the query draft atm as I wanna
avoid making changes to explorer-query given there was a couple of PRs
in flux that adjusts that file - will handle that separately

<img width="1117" height="577" alt="image"
src="https://github.com/user-attachments/assets/9bfd6287-efff-418b-a1c0-934ee2c840cb"
/>

<img width="1917" height="436" alt="image"
src="https://github.com/user-attachments/assets/bfd1be82-8f77-4764-bd3a-4b9c63169b82"
/>


## To test
- [ ] Verify that role impersonation works in notebook query cell
- [ ] Verify that role impersonation works in notebook query tab

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

* **New Features**
  * Added role impersonation support to SQL Explorer queries.
* Users can select an impersonated role directly from database query
menus.
  * Query execution now applies the selected role when configured.
* Added local role selection state for individual query tabs and cells.
* Improved reuse and consistency of role impersonation controls across
the interface.
* Role selections and impersonation details remain synchronized across
supported query components.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-17 14:22:50 +08:00
Joshen Lim d61477085e Joshenlim/fe 4175 add row limit in explorerquerysourcemenu (#49098)
## Context

Related to Explorer/Notebook - builds on the ExplorerQuerySourceMenu by
adding an option for row limit in both Notebook Query cell + Query Tab

## Side note RE persistence of the selected row limit value
Note that for QueryTab - its intentional that for now that the row limit
isn't scoped to the query draft atm as I wanna avoid making changes to
`explorer-query` atm as there's a couple of PRs in flux that touches
that file. So will handle that separately

^ This means that switching between query tabs will not change nor
persist the row limit

<img width="931" height="335" alt="image"
src="https://github.com/user-attachments/assets/d1d52ee7-7c1d-42aa-a6ae-1d7d99ab95c9"
/>

<img width="1381" height="486" alt="image"
src="https://github.com/user-attachments/assets/689368c9-c0fc-4000-a09e-f59bfa7afa97"
/>

## To test
- [ ] Verify that row limit behaviour works in notebooks
- [ ] Verify that row limit behaviour works in explorer query tab
2026-08-17 13:36:31 +08:00
Charis 0ed49231b7 refactor(studio): unify CellSource and the SQL editor's QuerySource into QuerySourceBinding (#49072)
Third of a stack. **Stacked on #49070** (which is stacked on #49069) —
review those first. Base retargets automatically as each merges.

Mechanical throughout; no behavior change.

## The problem

Three types described where a query runs, and no two agreed:

| | shape |
|---|---|
| `CellSource` (registry) | `{ id, type, parameters: { … } }` — `id` and
`type` always held the same literal |
| `QuerySource` (SQL editor) | `{ type: 'database' } \| { type: 'logs',
dateRange }` |
| notebook cells | flat per-backend fields, neither of the above |

Anything crossing between them needed a translation that dropped fields
on the way — which is how a notebook cell's replica selection had
nowhere to go.

## What changed

One `QuerySourceBinding`: a backend `_tag` with that backend's
parameters spread flat beside it, borrowed from the wire schema (#49069)
so the binding and the persisted cell agree by construction.

- **`QuerySource` is deleted.** `useRunSource` returns the shared
binding, so `runSource.type`/`dateRange` become `_tag`/`time_range`
across the SQL editor — that is most of the file count here.
- **`getQuerySourceBinding`** projects a notebook cell onto a binding;
**`toQuerySourceBinding`** does the same for any backend-tagged carrier.
Both overloaded so an already-narrowed caller gets the matching binding
back rather than the union, which keeps the result spreadable without
re-narrowing.
- **`ExplorerQuerySourceMenu`** drops its inline copy of the
custom-range and upgrade-prompt logic in favor of `useLogsCustomRange`,
which the SQL editor menu already used.

The registry keeps only what is genuinely runtime: endpoints, labels,
icons, availability, defaults. What a query *is* stays in the wire
schema.

## Verification

Typecheck, Prettier, and the lint ratchet clean. 405 tests pass across
the notebook schema, query sources, the logs components, the SQL editor,
and the Explorer surfaces.

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

* **Improvements**
* Updated query source handling across Explorer and SQL Editor for a
more consistent selection experience.
* Database and log sources now preserve identifiers and time ranges more
reliably when switching or editing queries.
* Source menus, labels, icons, validation, and query execution now
reflect the selected source more accurately.

* **Bug Fixes**
* Invalid or outdated saved source settings now safely fall back to a
database source.
* Improved log-source detection and time-range handling throughout query
editing and execution.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-08-14 15:09:29 +07:00
Charis c0e109f662 refactor(studio): borrow the wire schema's time range in the query-source registry (#49070)
Second of a stack. **Stacked on #49069** — review that one first; this
PR's diff only makes sense on top of it. Base will retarget to `master`
automatically when #49069 merges.

Net `-72` lines. No behavior change beyond the one noted at the bottom.

## The problem

The query-source registry carried its own `LogTimeRange` type and
`logTimeRangeSchema`, which had drifted from the notebook wire schema's
copy in four ways:

| | wire schema | registry |
|---|---|---|
| discriminant | `_tag: 'relative_time_range'` | `type: 'relative'` |
| absolute bounds | `start` / `end` | `from` / `to` |
| relative units | minute…year | minute, hour, day |
| validation | none | positive int, end-after-start |

Two definitions of one concept, neither convertible to the other without
a lossy mapping — and the notebook query cell was papering over it by
discarding a log cell's persisted range and substituting a default.

## What changed

#49069 moved the validations onto the wire schema's `timeRangeSchema`
and exported it. This PR deletes the registry's copy and points every
consumer at `TimeRange`. The registry keeps what is genuinely runtime:
endpoints, labels, availability, defaults.

The field renames ripple mechanically through the logs date-picker
helpers, the time-range submenu, `useLogsCustomRange`, the SQL editor's
session state, and their tests. Coverage for the absolute-range and unit
rules moved to `notebook-schema.test.ts` in #49069, alongside the schema
that now owns them.

`ExplorerQuerySourceMenu` also drops its hand-rolled custom-range
construction in favor of `customDateRangeToLogTimeRange`, which already
existed and does the same clamping.

## One behavior change

`logTimeRangeToDatePickerValue` now renders a range whose unit has no
picker preset (week, month, year — allowed by the wire schema, not
offered in the UI) as a resolved absolute range, instead of trying and
failing to build a helper for it. Previously unreachable, since the
registry's narrower unit set made those ranges unrepresentable.

## Verification

Typecheck, Prettier, and the lint ratchet clean. 401 tests pass across
the notebook schema, query sources, the logs source components, the SQL
editor, and the Explorer surfaces.

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

## Summary by CodeRabbit

* **Bug Fixes**
  * Improved log time-range handling across Explorer and SQL Editor.
* Custom date ranges now display and resolve correctly, including
clamping invalid ranges.
* Unsupported relative time units are converted to compatible absolute
date-picker values.

* **Refactor**
* Standardized log queries on a shared time-range format for more
consistent validation and behavior.


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

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-08-14 13:45:41 +07:00
Joshen Lim 67d4fed40d Joshenlim/fe 4157 explorer migrate results component into explorer (#49066)
## Context

Related to Notebooks/Explorers - this one's just shifting files from the
SQLEditor into more generic folders from a file organization POV, such
that files under the Explorer folder have no dependency on files within
the SQLEditor folder

Mainly
- UtilityTabResults.utils: `getSqlErrorLines`
  - Moved into `data/sql/utils.ts`
- SQLEditor.utils: `applyAutoLimit`, `getSqlErrorLines`,
`trimTrailingSemicolons`
  - Moved into `data/sql/utils.ts`
- SQLEditor/UtilityPanel: `ResultCell`, `Results`, `CellDetailPanel`
  - Moved into `components/ui/DataGridResults`
  - Also shifted corresponding tests over here
- Also addressed some `any` type casts 

## To test
- Just need to ensure that the SQL Editor still works as expected

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

## Summary by CodeRabbit

* **New Features**
* Standardized query results across the Studio with a shared data grid.
* Improved result-table formatting, column sizing, clipboard handling,
and large-value display.
  * Added safer automatic row limits for eligible SQL queries.
  * Centralized SQL error display and formatting utilities.

* **Refactor**
  * Improved type safety for query rows and cell values.

* **Tests**
* Added comprehensive coverage for result-grid and SQL utility behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-14 11:29:39 +07:00
Saxon Fletcher cc6fe2100a refactor(studio): centralize query sources (#49027)
## Summary

- define application-owned database and logs source contracts, defaults,
validation, labels, and execution endpoints
- extract controlled database and logs parameter controls for reuse
outside SQL snippets
- adapt the SQL editor to the shared source model without changing
snippet behavior
- standardize source icons at 16px with a 2px stroke
- keep relative logs ranges aligned with the existing date picker units

## To test

1. Open an existing query in the SQL Editor and run it against the
database.
2. Switch the query source to Logs, change the time range, and confirm
the query still runs as expected.

## Why

Explorer queries and notebook query cells need to select an execution
source without coupling that source to SQL snippets. This provides the
shared registry and controlled UI foundation for those consumers.

## Impact

Existing SQL snippets retain their current database/logs routing and
session behavior. The registry documents the SQL editor legacy
database-selector adapter while new consumers own their identifier
inline. The shared Logs date picker remains unchanged; query ranges
support its existing minute, hour, and day units. This PR does not add
the Explorer query tab itself.

## Validation

- pnpm --filter studio typecheck
- focused Vitest coverage for the registry, canonical log-range
utilities, SQL execution adapters, source filtering, retention locking,
custom ranges, and preset selection
- pnpm --filter studio run lint:ratchet

Component and state tests cover this change per the Studio testing
guidance; no E2E test is added.

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

* **New Features**
  * Added a unified query-source menu for database queries and logs.
* Added custom log time-range selection with calendar support and
retention-aware upgrade prompts.
* Added consistent source icons and improved database selection
handling.
  * Added support for relative and absolute log time ranges.

* **Bug Fixes**
  * Improved log-range validation, defaults, and current-time handling.
* Updated query execution to use the correct source-specific endpoints.

* **Tests**
* Expanded coverage for query sources, log ranges, menus, and retention
behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-13 16:51:06 +07:00
Joshen Lim 77c5a0b9d9 Joshen/fe 4077 explorer query cells (#48989)
## Context

Related to Explorer / Notebooks - adds a barebones query cell that
minimally can run SQL queries + render results

The intention is to migrate the components used in the SQL Editor into
this new Query cell since all the functionality is very similar, but the
SQL Editor component is tightly coupled to the SQL Editor valtio store.
So we'll be duplicating a bit of UI for now - which will also make
deprecating the SQL Editor eventually a bit easier by just deleting them

Have deliberately omitted a lot of details for now just to keep the PRs
small, so will be continuing to build out the QueryCell's functionality
in subsequent PRs. This includes
- Source selector
- Data display (Table / Chart)
- Autolimit logic

Other changes also includes
- Updating NotebookEditor to use the new Explorer UI components that
Saxon introduced

<img width="500" alt="image"
src="https://github.com/user-attachments/assets/d709f6f1-f6cc-4e6a-babd-f5b68bba2a55"
/>
<img width="500" alt="image"
src="https://github.com/user-attachments/assets/a286ceca-ac84-4fbd-afd5-b24f940e2e29"
/>



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

* **New Features**
* Added notebook database cells for writing, editing, and running SQL
queries.
* Added query result displays with loading, empty, error, row-limit, and
result states.
  * Added editable notebook titles with save and cancel controls.
  * New notebooks can start with customizable Markdown and SQL cells.
* Added helpful SQL error actions, including copying messages, database
connection guidance, and AI Assistant support where available.

* **Improvements**
* Improved notebook spacing, section layout, toolbar tooltips, and
empty-result presentation.
  * Markdown changes now save automatically through the notebook editor.
  * Improved drag-and-drop controls and query visibility management.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-13 08:44:27 +07:00
Charis 4ca17a23ce fix(studio): keep the new SQL editor tab from being pruned on first keystroke (#48956)
## What kind of change does this PR introduce?

Bug fix.

## What is the current behavior?

With a snippet already open in the SQL Editor, clicking the `+` button
and typing in the new tab made it look like the previously open tab was
being taken over: the tab bar showed the *old* snippet's name while the
editor showed the newly typed content. With several tabs open, the
rightmost one appeared to be the one taken over.

`useSqlEditorTabsCleanup` prunes any `sql-*` tab whose snippet is absent
from the server-fetched snippet list, so tabs for snippets deleted in
another session don't linger. But a snippet created by typing in a new
tab exists only in the local store until its first save lands, so it is
legitimately absent from that list — and the same keystroke that creates
it calls `setSql({ shouldInvalidate: true })`, invalidating the snippet
lists and triggering a refetch that pruned the tab that had just been
opened.

`removeTab` then reassigns `activeTab` to a neighbor, so the tab bar
fell back to whichever tab was open before, while the URL, sidebar, and
editor content all stayed correctly on the new snippet — none of them
read from the tabs store.

Confirmed from a user's persisted tab state, which showed a single tab
in `openTabs` pointing at the previous snippet while the URL pointed at
the new one.

No snippet content was ever lost — this was tab state only.

## What is the new behavior?

Tabs (and recent items) whose snippet is present in the local store with
a never-persisted status (`new`, `new_saving`, `new_save_failed`) are
preserved by the cleanup pass. Genuine stale-tab pruning for snippets
removed outside the session is unaffected.

## Additional context

The regression test in `Tabs.utils.test.tsx` fails without the fix
(`expected undefined to be defined`) and passes with it. The
pre-existing pruning tests still pass, confirming legitimate cleanup
still works.

Also adds two tests covering adjacent invariants that were verified
while narrowing this down: snippet content isolation between tabs, and
unique snippet id generation across `/sql/new` navigations.

Verified: 343 tests pass across `components/layouts/Tabs` and
`components/interfaces/SQLEditor`; typecheck clean; ESLint warning count
unchanged (ratchet safe); Prettier clean.

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

## Summary by CodeRabbit

- **Bug Fixes**
- Preserved newly created SQL editor tabs and recent items before their
first save.
  - Prevented unsaved snippets from being removed during tab cleanup.
- Ensured editing a new tab does not overwrite content in existing tabs.
  - Ensured successive new SQL tabs receive distinct identities.

- **Tests**
- Added regression coverage for snippet editing, route changes, and tab
cleanup behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-12 09:30:59 -04:00
Joshen Lim cdfb5b310f Add cancel query action for database connections (#48922)
## Context

Related to Database Connections
- Adds a "cancel query" action for "active" sessions using
`pg_cancel_backend`
- Gentler alternative as the connection stays alive, unlike terminating
the session
- Not applicable for queries idle in transaction as there's no query
running (Disabled in this case)
- Rename "Terminate" to "Terminate session"
- Rename "Abort query" to "Terminate session"

For active queries:
<img width="220" height="135" alt="image"
src="https://github.com/user-attachments/assets/d6ca790d-bb6a-4582-8554-24431388483a"
/>

For idle in txn queries:
<img width="433" height="135" alt="image"
src="https://github.com/user-attachments/assets/615d0651-9f5b-4efc-a5cf-72f93727aa91"
/>

Also updating confirmation modal for terminating session CTA:

For active queries:
<img width="407" height="301" alt="image"
src="https://github.com/user-attachments/assets/e5f56764-11b9-4c10-ba01-d7547aaec872"
/>

All other queries:
<img width="410" height="212" alt="image"
src="https://github.com/user-attachments/assets/8631633f-5d4a-40a7-b089-6980a5180219"
/>



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

## New Features
- Added a separate **Cancel query** action for active database queries.
- Added **Terminate session** to close connections and roll back active
transactions.
- Added safeguards based on query activity and permissions.
- Added confirmation guidance for active queries, including cancellation
options.
- Added loading, success, and error feedback for query cancellation and
session termination.
- Added telemetry for query-cancellation actions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-12 09:56:49 +07:00
Charis 065468f8ac fix(studio): reset rename form after renaming a SQL snippet (#48951)
## 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 SQL snippet rename modal is mounted once per nav and reused for
every snippet, so a single form instance is shared across renames. On a
successful rename the form was never re-baselined, leaving it dirty, and
the effect that synced the form to the selected snippet bailed out
whenever the form was dirty.

Renaming a second snippet therefore opened the modal pre-filled with the
previous snippet's name, with the submit button enabled — one careless
confirm renamed the wrong query.

## What is the new behavior?

The form is reset after a successful rename, and the hand-rolled sync
effect is replaced with react-hook-form's `values` option so the form
follows whichever snippet is selected.

`keepDirtyValues` keeps a background refetch from clobbering in-progress
input, which is what the old dirty guard was protecting against. It has
to be disabled explicitly on the resets that discard input, since
`resetOptions` on `useForm` applies to every `reset` call — not just the
`values`-driven one.

Adds component tests covering the submit path, the rename-then-rename
regression, and discarding an abandoned edit on cancel.

## Additional context

Fixes FE-4114

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

## Summary by CodeRabbit

- **Bug Fixes**
- Improved the rename query experience by ensuring the selected snippet
name is displayed correctly when reopening the rename dialog.
- Cancelled edits are now discarded reliably, preventing unsaved changes
from persisting.
- After a successful rename, the form reflects the updated query name
and maintains consistent input and button behavior.
- **Tests**
- Added coverage for successful renaming, cancellation, reopening with a
newly selected snippet, and submitted values.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-11 20:05:46 +00:00
CharisandJoshen Lim 0b97e37ccf feat: notebook content schema (#48813)
Related to FE-4109.

## Summary

- **API codegen workaround**: Platform API's `notebook` content type
hasn't shipped to the OpenAPI spec yet, so `pnpm api:codegen` can't be
run. Locally widened `ContentBase.type` to include `'notebook'` (marked
with TODO for removal once spec publishes).
- **Notebook schema & type system**: Introduced Zod schemas mirroring
RFC-defined notebook shape (`schema_version: 1, cells: Cell[]`).
Maintains wire/domain boundary (cell `sql` → `unchecked_sql` branded for
security). Agent-writable schema for `create_notebook` tool omits cell
IDs (backend-generated); future update operations will require them. All
TypeScript types are `z.infer`'d from schemas (no hand-written parallel
interfaces).
- **IsoDateTimeString moved**: Extracted ISO datetime validator from
`querySource.ts` to `lib/iso-datetime.ts` (data layer shouldn't import
from components layer). Needed by notebook `time_range` fields.

## Test plan

- [x] Unit tests: `notebook-schema.test.ts` (9 tests),
`iso-datetime.test.ts` (3 tests), `querySource.test.ts` updated and
passing (26 tests)
- [x] Typecheck: no new errors
- [x] Prettier: formatting clean

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

## Summary by CodeRabbit

- **New Features**
- Added support for validating and processing notebook content,
including markdown, database, log cells, time ranges, and chart
configurations.
  - Added compatibility for notebook content types in content handling.
- Added reliable ISO date-time validation for notebook data and related
features.

- **Tests**
- Expanded coverage for valid and invalid notebook structures, cell
requirements, time ranges, chart settings, and date-time values.

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

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-08-07 13:40:18 +07:00
Charis 2165746784 fix(studio): keep SQL editor source menu open when switching sources (#48715)
## 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?

Selecting Database/Logs in the SQL Editor's query-source dropdown closes
the menu (Radix's default select behavior), so switching to Logs gives
no visible indication that a Time range control just became available
until the dropdown is reopened.

## What is the new behavior?

Selecting a source keeps the dropdown open, so the newly-available
source-specific controls (e.g. Time range for Logs) are immediately
visible.

## Additional context

Fixes FE-4036

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

## Summary by CodeRabbit

* **Bug Fixes**
* Improved source switching in the SQL editor so the selection menu
remains open while changing between database and logs sources.
  * Ensured source-specific controls update correctly after switching.

* **Tests**
* Added coverage for source selection, menu behavior, and
source-specific control updates.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-04 20:23:12 +00:00
Charis b9053794a0 fix(studio): add tooltip explaining why Prettify SQL is disabled (#48712)
## 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?

In the SQL Editor, the Prettify SQL action (both the "More actions"
dropdown menu item and the toolbar button) is disabled for logs
snippets, but gives no indication why.

## What is the new behavior?

The disabled Prettify menu item now uses `DropdownMenuItemTooltip` and
the disabled Prettify toolbar button uses `ButtonTooltip`, both showing
"Can only prettify SQL queries" while disabled. Addresses review
feedback from #48452 (Linear FE-4038).

## Additional context

Resolves FE-4038

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

## Summary by CodeRabbit

* **Improvements**
  * Updated SQL editor tooltips with clearer, consistent messaging.
* Log-source users now see an explanation when SQL formatting is
unavailable.
  * Regular users continue to see the SQL prettify keyboard shortcut.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-04 18:07:08 +00:00
Charis 89010c1649 fix(studio): show selected custom time range in SQL editor time range menu (#48709)
## What

Display the actual selected custom date range in the Time Range
dropdown's secondary text, instead of the static "Custom range" label.
The range is formatted as `DD MMM, HH:mm - DD MMM, HH:mm` to match the
existing format in the Logs Explorer's date-picker trigger button,
ensuring visual consistency across the Logs UI.

Fixes FE-4035

## Test plan

- [x] Typecheck passes: `pnpm typecheck`
- [x] Manually verify: Open SQL Editor with `sqlEditorLogsSource` flag
enabled, open the Time Range dropdown menu, select a Custom range, and
confirm the dropdown's secondary text now displays the selected date
range instead of "Custom range"

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

## Summary by CodeRabbit

* **New Features**
* Custom time ranges now display formatted start and end timestamps for
clearer time selection.
  * Preset time ranges continue to show their existing helper text.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-04 13:26:02 -04:00
Charis 0791b04eb8 feat(sql-editor): roll out manual saving by default (#48706)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Feature — progresses the SQL Editor manual saving rollout, and removes a
fully rolled out feature flag.

## What is the current behavior?

Manual saving (snippets save only on an explicit Save / Cmd+S rather
than autosaving every edit) is opt-in. It requires both the
`sqlEditorManualSave` ConfigCat flag and the user turning on the
"Disable snippet auto-saving" feature preview themselves. That flag is
now fully rolled out.

## What is the new behavior?

- `sqlEditorManualSave` is removed, so the feature preview is listed for
everyone. (Delete the flag in ConfigCat after a few months.)
- New `sqlEditorManualSaveForced` flag progresses the rollout. It forces
manual saving on regardless of what the user stored previously,
including an explicit opt-out, via a new `isForced` field on
`FeaturePreview` that `initializeFlags` resolves ahead of the
localStorage lookup — so the feature preview modal reflects the forced
state too, not just the save behavior. Turning the flag off reverts
everyone who never opted in, so it remains a working kill switch.
- Users the rollout switches over get a one-time dialog on their first
SQL Editor route, explaining that snippets no longer autosave. Dismissal
persists in `sql-editor-manual-save-notice-dismissed` (allowlisted, so
it survives sign-out).
- Users who opted into the preview themselves never see the dialog — it
records their dismissal up front instead, since the notice needs to
outlive the feature preview and once the preview is retired there's no
stored opt-in left to recognize them by.
- The preview keeps its switch so users who lose their local storage can
opt in early, but once the rollout reaches them the "Disable feature"
button is disabled with a tooltip explaining why.

### To test

Turn on `sqlEditorManualSaveForced` on via the dev toolbar.

- No `supabase-ui-sql-editor-manual-save` and no dismissal key → dialog
appears on `/project/<ref>/sql`, toolbar shows the Save button. Dismiss,
reload → no dialog.
- `supabase-ui-sql-editor-manual-save` set to `false` (previously opted
out) → still forced onto manual saving, and still gets the dialog.
- `supabase-ui-sql-editor-manual-save` set to `true` → no dialog, and
the dismissal key is written automatically.
- Flag off, no opt-in → autosave, no dialog, and the "Disable autosave"
power-off button still opens the preview modal.
- Preview modal while forced → "Disable feature" is disabled with a
tooltip; another preview (e.g. Column-level privileges) still disables
normally.

## Additional context
2026-08-04 12:16:18 -04:00
Hoon ceace2e90b fix(studio): account for SQL result column headers (#48676)
## 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 #48672.

The SQL Editor results grid calculates each column's initial width from
cell values only. When a long final column contains a short value such
as `NULL`, scrolling to the end of a wide result set reveals a truncated
header even though the full column name is needed to identify the
result.

### Before

<img width="760" height="370" alt="Before: final SQL result column
header is truncated"
src="https://github.com/user-attachments/assets/f73b7540-fc45-4ddf-91b6-996afe41807e"
/>

## What is the new behavior?

The initial width now accounts for both the column name and its cell
values while preserving the existing minimum and maximum width
constraints.

### After

<img width="760" height="370" alt="After: full SQL result column header
is visible"
src="https://github.com/user-attachments/assets/b289ab86-4277-46fc-ae9a-35c3eac5442f"
/>

## Additional context

The width calculation was extracted into a utility and covered for:

- short headers and values
- headers longer than their values
- values longer than their headers
- empty result sets
- maximum-width capping

Verification:

- `pnpm --filter studio exec vitest --run
components/interfaces/SQLEditor/UtilityPanel/Results.utils.test.ts
tests/components/SQLEditor/Results.test.tsx`
- `pnpm --filter studio run typecheck`
- `pnpm --filter studio run lint:ratchet`
- `pnpm run test:prettier`
- `SKIP_ASSET_UPLOAD=1 pnpm run build:studio`


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

- **Improvements**
- SQL query results now automatically size columns based on their
headers and content.
- Column widths remain within practical minimum and maximum limits for
improved readability and usability.

- **Tests**
- Added coverage for minimum and maximum widths, content-based sizing,
and empty result sets.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-04 14:31:59 +00:00
Charis 21511042a3 feat(studio): assistant logs context and reports guard (#48514)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Feature — final PR (9/9) of the SQL editor logs-source stack.

**Base branch:** `charislam/sql-editor-inline-ai-clickhouse-dialect` (PR
8). Nothing here is user-visible: entry points stay behind
`sqlEditorLogsSource` + `otelLegacyLogs`, and flag rollout happens after
the whole stack merges.

## What is the current behavior?

- The Assistant has no idea a SQL editor snippet targets the logs
backend. Ask it about a logs snippet and it answers in Postgres, because
the attached query is fenced as ` ```sql ` and nothing tells the model
otherwise.
- Because the `sql` fence is what `MessageMarkdown` treats as runnable
Postgres, an attached ClickHouse query is rendered with a
Run-against-Postgres affordance and branded with `untrustedSql`.
- "Debug with Assistant" on a failed logs query produces a dialect-less
prompt, so both the in-app assistant and the copyable version get
debugged as Postgres.
- A report referencing a `log_sql` snippet runs its ClickHouse SQL
against the user's Postgres database and surfaces the resulting error.

## What is the new behavior?

**Assistant panel.** The "Current Query" chip records which backend the
attached query targets. That reaches the model two ways: each attachment
is fenced with its own dialect (` ```clickhouse ` vs ` ```sql `), and a
`containsLogsSnippets` flag rides on the user message as AI SDK
`metadata`. The server reads the flag off the conversation and prepends
the ClickHouse dialect rules plus the logs schema reference as a
non-cached context message.

Two design points worth calling out in review:

- The flag lives on the **message**, not the request body, so Retry and
the tool-approval continuation reproduce the context a message was
originally asked in — neither of those passes a per-call body.
- It's derived from **what's actually attached**, so detaching the chip
drops the claim rather than leaving the two able to disagree.

The `clickhouse` fence also keeps a logs query out of
`MessageMarkdown`'s `sql` branch, so it's no longer offered as runnable
Postgres or branded with `untrustedSql` — a boundary this stack's
distinct brands exist to prevent crossing.

**Debug flow.** `buildDebugChatArgs` attaches its query with a source
for the same reason, and names the dialect in the prompt text so the
copyable version stands on its own outside the app.

**Reports.** A report only stores a snippet id, so whether it queries
the logs backend is only knowable once the content loads. `ReportBlock`
guards on the fetched type and renders a `LogsSnippetReportBlock`
placeholder instead of executing. Double-guarded: no `sql` for a logs
snippet (so it's out of the query key and `queryFn` short-circuits even
on an explicit `refetch`) and `enabled` excludes it.

**Incidental cleanups.** `buildAssistantContextMessages` extracted out
of `generate-assistant-response`; a schema-access sentinel that was
duplicated as a string literal across two files (and compared against)
replaced with one exported constant; `SqlSnippet` deduplicated to a
single declaration; `resolveSnippetSource` / `isLogsSource` shared
instead of re-implemented per surface.

**Tests.** 4 new/extended suites. Notable cases pinned: a message with
no metadata must validate (`safeValidateUIMessages` applies
`metadataSchema` to *every* message, so a required schema would 400
every existing conversation); only *user* messages count, so a model
reply can't talk the server into a different dialect; a mixed-attachment
message is flagged without overclaiming a single source; and
`ReportBlock` registers no pg-meta mock for the logs cases, so an
unhandled request failing the test *is* the assertion that logs SQL
never reaches Postgres.

Verified: `pnpm typecheck`, `lint:ratchet` (no regression), Prettier,
and the full Studio suite (459 files / 4969 tests).

## Additional context

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

## Summary by CodeRabbit

- **New Features**
- Added support for recognizing log snippets in reports, with clear
guidance to open them in the SQL editor or remove them.
- AI Assistant now understands log snippets and provides
ClickHouse-specific context, formatting, and troubleshooting guidance.
- Snippets retain their source information when shared with the AI
Assistant.

- **Bug Fixes**
- Prevented unsupported log snippets from being executed as regular
database queries.
  - Improved source detection when opening snippets directly from links.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-04 09:02:40 -04:00
Charis 8b38e0d1ed feat(studio): ClickHouse dialect for logs snippet AI + rewrite to ClickHouse (#48501)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Feature, plus a refactor of the shared logs-rewrite flow.

PR 8 of the SQL editor query-source series. Stacked on #48457 — review
that one first, and merge this after it.

## What is the current behavior?

A `log_sql` snippet runs against the ClickHouse-backed analytics
endpoint, but the SQL editor's AI still writes Postgres: inline edits
get Postgres system prompts, and the result is run through
`sql-formatter`, which mangles ClickHouse backticks and `log_attributes`
map lookups.

Legacy Logs Explorer saved queries open in the editor as `log_sql`
snippets. Those are BigQuery dialect and error against the ClickHouse
endpoint the editor runs them on, with no in-editor way out — only the
Logs Explorer offered a rewrite.

The completion route was also asymmetric. It assembled a
schema/code/instruction message for Postgres but forwarded `prompt`
verbatim for ClickHouse, so a client wanting ClickHouse had to
hand-build the equivalent string.

## What is the new behavior?

**Inline AI speaks ClickHouse for logs snippets.** `sqlSourceToDialect`
maps a snippet's source to `postgres`/`clickhouse` and
`buildCompletionRequestBody` threads it through. For ClickHouse,
`useSqlEditorAi` strips code fences from the response and skips
`formatSql`. Execution and dialect both follow the snippet type, so a
snippet's valid dialect never flips.

**Rewrite to ClickHouse in the editor.** A banner offers the rewrite for
a logs snippet whose text trips `looksLikeLegacyLogsQuery`, and proposes
the result through the editor's existing AI diff view rather than
replacing the snippet, so it's accepted or discarded like any other AI
edit. Gated on `otelLegacyLogs`: on a non-migrated org the BigQuery text
is still correct, so rewriting it would break a working query.

The offer is a state machine (`offered` / `rewriting` / `failed` /
`noRewriteNeeded` / `dismissed`) with a declarative table of valid
transitions, so the states are mutually exclusive by construction and
dismissal is terminal. A failure keeps its message and offers a retry; a
response identical to the input is reported rather than opening an empty
diff.

**One place assembles completion prompts.** The route now uses a single
template for both dialects, branching only the schema section and — for
`intent: 'rewrite'` — the instruction. `lib/ai/clickhouse-logs.ts` is
the single home for ClickHouse-logs prompt content, replacing two
independently maintained descriptions of the same table. Clients carry
no prompt text.

**The rewrite flow is shared with the Logs Explorer.** Both surfaces
previously hand-rolled the same sequence and had drifted: only one
detected a no-op rewrite, they sourced `log_attributes` keys
differently, and the Explorer formatted errors with an `as Error` cast.
Both now use `useLegacyLogsRewrite` and the same state-driven banner, so
the Explorer picks up no-op detection and typed error extraction.

**Attribute keys are fetched on submit, not while typing.** The detected
source would otherwise feed a reactive query key, making every edit that
changed it cost another network call. `useLogsAttributeKeys` is
imperative and goes through `queryClient.fetchQuery`, so a source
already cached — including by the Explorer header and query panel, which
subscribe reactively — is reused. This also closes a gap where inline
edits never received keys at all, unlike full rewrites.

`getErrorMessage` gains an optional typed fallback and no longer
stringifies a bare object into `'[object Object]'`; every existing
caller already hand-rolled a fallback, except `QueueSettings`, which
interpolated the raw result and now passes one.

Nothing here is user-visible until the `sqlEditorLogsSource` flag is
enabled.

Tests: dialect selection and request-body shape, the ClickHouse prompt
content (including that the schema section does not restate the dialect
rules), the reducer's valid and invalid transitions,
`shouldOfferLegacyLogsRewrite`, on-submit key discovery with cache
reuse, and `getErrorMessage`.

## Additional context

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

## Summary by CodeRabbit

* **New Features**
* Added an Assistant banner to help rewrite legacy BigQuery-style logs
queries into ClickHouse SQL.
* SQL assistance now adapts to the selected query type, including
relevant log attribute context.
* Rewrite suggestions can be reviewed as editor diffs before being
applied.

* **Bug Fixes**
* Improved rewrite failure handling, retry options, dismissal behavior,
and “no rewrite needed” messaging.
* Error notifications now provide a clearer fallback message when
details are unavailable.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-04 09:02:40 -04:00
Charis 50e1eb7436 chore(eslint): bump eslint-config-next to v16 for useEffectEvent (#48458)
## 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?

Chore / build (ESLint config upgrade + lint cleanup).

## What is the current behavior?

`eslint-plugin-react-hooks` v5 (pulled in transitively by
`eslint-config-next` v15) doesn't recognize stable `useEffectEvent`, so
every effect that calls an effect-event handler needs an `eslint-disable
react-hooks/exhaustive-deps` to silence a false positive. There are 30
such dead disables across Studio.

## What is the new behavior?

Bumps `eslint-config-next` to v16, which pulls in
`eslint-plugin-react-hooks` v7 whose `exhaustive-deps` understands
`useEffectEvent`, and removes the 30 now-dead disable directives (and
their orphaned explanatory comments).

Supporting changes:

- **Flat-config migration**: v16 is a native flat-config array (v15 was
eslintrc), so `eslint-config-supabase` now spreads it directly instead
of bridging through `FlatCompat`.
- **React Compiler rules off**: v16 enables react-hooks v7's
`recommended`, which layers the React Compiler lint rules on top of the
two classic rules. These are switched off (derived dynamically from what
next enables) to keep this change scoped to the `exhaustive-deps`
improvement.
- **Plugin-registration fallout** (v16 scopes plugin registration to a
file glob rather than registering globally like FlatCompat did): stop
re-registering `@typescript-eslint` (shared) and `jsx-a11y` (studio);
scope our react / react-hooks / jsx-a11y rule overrides (studio, www) to
v16's plugin glob so they don't error on files outside it (e.g. `.cjs`).
- **Lint surface preserved**: v16's glob newly includes `.mts`/`.cts`
(v15 didn't lint them), which surfaced pre-existing errors in tooling
scripts. The shared config keeps the prior surface by leaving
`.mts`/`.cts` unlinted; linting them is left as a separate change.
- **Ratchet**: rebaselines `@tanstack/query/exhaustive-deps` 9 → 89. v15
forced next's `@babel/eslint-parser` onto `.ts` files, hiding these
deps; v16 parses `.ts` with `@typescript-eslint/parser` and correctly
surfaces the intentional `connectionString`-excluded-from-`queryKey`
pattern. Worth a follow-up to review whether any are real
cache-correctness bugs.
- Drops three now-dead devDeps from `eslint-config-supabase`:
`@eslint/eslintrc`, `@eslint/js`, `@typescript-eslint/eslint-plugin`.

Verified locally: `turbo run lint` → 7/7 packages pass with 0 errors;
Studio `lint:ratchet` passes; Prettier clean on changed files; typecheck
unaffected.

## Additional context

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

## Summary by CodeRabbit

* **Chores**
* Refined linting configuration and removed outdated lint suppressions
across Studio.
* Updated Next.js linting support and refreshed related development
configuration.
  * Expanded lint baseline coverage for query-related code.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-31 09:01:05 -04:00
CharisandJoshen Lim c16c7e94cc feat(studio): SQL editor logs source — toolbar UI + creation flow (#48452)
## What

PR 6 of the SQL-editor "query source (Database vs Logs)" stack (builds
on the merged PR 5, #48414). Adds the user-facing toolbar surface for
the logs query source and consolidates the SQL-editor toolbar into a
single **source menu**.

Everything stays behind `sqlEditorLogsSource` + `otelLegacyLogs`
(dual-flag gated); with the flags off the toolbar is unchanged.

## Changes

- **Consolidated source menu** (`QuerySourceMenu`) — one `Database ▾` /
`Logs ▾` dropdown that both labels the snippet's source and hosts the
source-specific controls as flyout submenus:
- Database: database selector (`Primary` / read replicas), `Run as`
(role impersonation), and `Row limit`.
- Logs: `Time range` — the same relative presets as the Logs Explorer
plus a `Custom range…` calendar dialog.
- **Source is immutable** — the Database/Logs rows aren't a toggle. An
existing (materialized) snippet opens a *fresh* tab of the target source
(never reinterpreting a query against the wrong backend); a blank new
tab re-flavors in place. Extracted as the pure, unit-tested
`resolveSourceSwitch`.
- **New-snippet-with-source** threaded through `/sql/new?source=`, the
nav "Create a new logs query" entry, and the duplicate flow. Logs
snippets hide the (db-dialect) Export action.
- **Run-affordance guard** — the Run button is disabled + annotated for
a logs snippet on a non-ClickHouse org (sits above PR 5's execution
short-circuit).
- **Retention entitlement gating** — both preset and custom logs ranges
past `log.retention_days` surface the upgrade prompt instead of applying
silently. Prettify is disabled for logs (sql-formatter mangles
ClickHouse).

## Tests

- `querySource.test.ts` — `logDateRangesEqual` (structural
relative/absolute matching, incl. the "Last hour" vs "Last 1 hour" label
case).
- `QuerySourceMenu.utils.test.ts` — `resolveSourceSwitch`
push-vs-replace / no-op behavior.

`pnpm --filter studio typecheck` · `lint:ratchet` · Prettier · SQL
editor suite (307 tests) all green.

## For reviewers

To test manually, enable the `sqlEditorLogsSource` feature flag for
yourself on local/staging. There is no nav for Log SQL snippets
currently (that is by design, this PR is big enough as-is), so to check
an existing logs snippet, you can create one using the existing Logs
Explorer, copy its UUID, and force navigate to that snippet in the SQL
editor via URL.

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

## Summary by CodeRabbit

* **New Features**
* Added support for creating and switching between database and logs
queries.
  * Added log time-range presets and custom date-range selection.
  * Added database, run-as role, and row-limit controls.
* Added read-replica selection, including options to create a new
replica when available.
* **Improvements**
  * Added clearer explanations when query execution is unavailable.
* Disabled SQL formatting and query export where unsupported for logs
queries.

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

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-07-30 08:38:11 -04:00
Miranda Limonczenko 0d465e7b5f chore(ui): Remove 'tip' from Admonition (#48419)
Closes FE-3966

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## Problem

- The admonition uses both 'tip' and 'note', but the visual distinction
has long-ago collapsed.
- 'Note' is used far more frequently than 'tip'
- The two are very similar and it is confusing to know which one to use
when they are visually identical

## Solution

Collapse 'tip' and 'note' into one by removing all places where there is
'tip' and updating all references to 'tip' into 'note'.

**Note:** This PR also resolves new broken links flagged by the E2E docs
checker. It may move to another PR since E2Es keep erroring.

### Specific changes

See below for an AI-generated list of changes:

- **Type system** — removed `'tip'` from `AdmonitionType`, its
`TYPE_TO_VARIANT`/`TYPE_LABEL` entries, and the test case in
[`packages/ui-patterns/src/Admonition/](packages/ui-patterns/src/Admonition/)
- **Remark plugin** —
[remarkAdmonition.ts](apps/docs/lib/mdx/plugins/remarkAdmonition.ts) now
maps mkdocs `tip` → `note`
- **Lint allowlist** — `tip` dropped from `supa-mdx-lint.config.toml`
- **Content migration** — all 109 files with `type="tip"` (across
`apps/docs`, `apps/www`, `apps/studio`) converted to `type="note"`; zero
remaining hits confirmed by repo-wide grep
- **Style guide** — `CONTRIBUTING.md` and `contributing/content.mdx`
updated to describe 4 admonition types instead of 5

### Usage before implementation

See the usage table that points toward 'note' as being dominant across
all apps:

Here's the usage table:

| Location | `note` | `tip` |
|---|---|---|
| apps/docs | ~480 | ~143 |
| apps/studio | 34 | 6 |
| apps/www (blog) | 19 | 3 |
| packages/ui-patterns (tests) | 3 | 1 (parametrized) |
| design-system / ui-library / packages/ui / packages/common | 0–1 (test
fixture only) | 0 |

## Preview links


| App | Page | Search text (Ctrl+F) | Verify |
|---|---|---|---|
| docs |
[/docs/guides/ai-tools/byo-mcp](https://docs-git-admonition-collapse-note-tip-supabase.vercel.app/docs/guides/ai-tools/byo-mcp)
| official MCP TypeScript SDK | callout's aria-label="Note" |
| docs |
[/docs/guides/ai-tools/mcp](https://docs-git-admonition-collapse-note-tip-supabase.vercel.app/docs/guides/ai-tools/mcp)
| MCP server is available at | callout's aria-label="Note" |
| docs |
[/docs/guides/ai/python-clients](https://docs-git-admonition-collapse-note-tip-supabase.vercel.app/docs/guides/ai/python-clients)
| Click Connect at the top of any project page | callout's
aria-label="Note" |
| docs |
[/docs/guides/auth/audit-logs](https://docs-git-admonition-collapse-note-tip-supabase.vercel.app/docs/guides/auth/audit-logs)
| Disabling Postgres storage reduces your database storage costs |
callout's aria-label="Note" |
| docs |
[/docs/guides/database/tables](https://docs-git-admonition-collapse-note-tip-supabase.vercel.app/docs/guides/database/tables)
| access a custom schema through the Supabase Data API | callout's
aria-label="Note" |
| docs |
[/docs/guides/troubleshooting/edge-function-404-error-response](https://docs-git-admonition-collapse-note-tip-supabase.vercel.app/docs/guides/troubleshooting/edge-function-404-error-response)
| Always configure an appropriate time frame | callout's
aria-label="Note" (was single-quoted type='tip') |
| www | [blog:
cli-v2-config-as-code](https://zone-www-dot-com-git-admonition-collapse-note-tip-supabase.vercel.app/blog/cli-v2-config-as-code)
| Detecting config drift | callout's aria-label="Note" |
| www | [blog:
cli-v2-config-as-code](https://zone-www-dot-com-git-admonition-collapse-note-tip-supabase.vercel.app/blog/cli-v2-config-as-code)
| Setting Edge Function secrets | callout's aria-label="Note" |
| www | [blog:
nosql-mongodb-compatibility-with-ferretdb-and-flydotio](https://zone-www-dot-com-git-admonition-collapse-note-tip-supabase.vercel.app/blog/nosql-mongodb-compatibility-with-ferretdb-and-flydotio)
| If your network supports IPv6 connections | callout's
aria-label="Note" |

Note: the `www` rows use the `zone-www-dot-com` preview host, not the
`docs` one you gave — since blog pages are served from the www app, not
docs.


## Manual testing

1. Open preview links for affected pages.
2. Inspect. Open console.
3. Paste the following in and see there is no 'Tip' on the page:
```
document.querySelectorAll('[role="alert"]').forEach(el => console.log(el.getAttribute('aria-label'), el.textContent.slice(0,60)))
```



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

* **Documentation**
* Standardized informational callouts across docs and tutorials from
**“Tip”** to **“Note”**, updating multiple examples and guidance blocks.
* Updated a few related doc references/links and conditional “Next
steps” content.
* **UI Updates**
* Switched various in-app banners and notices to the **“Note”** style
variant.
* **Bug Fixes / Improvements**
* Removed support for the retired **“Tip”** callout type and aligned
docs linting, component behavior, and aria labeling to the remaining
admonition types.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-29 09:26:50 -07:00
Charis 4c8ed105d2 feat(studio): logs SQL execution wiring + source-aware run gestures (#48414)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Feature (SQL editor: execution wiring for logs-source snippets). Part of
the stacked SQL-editor "Database vs Logs" query-source series.

## What is the current behavior?

The SQL editor only ever runs queries against the user's Postgres
database. There is no execution path for a logs (`log_sql`) snippet, and
the run-button telemetry event carries no backend discriminator.

## What is the new behavior?

- `useRunSource(id)` derives the run backend from the snippet type; a
`log_sql` snippet resolves to `{ type: 'logs', dateRange }`, pairing the
run with its session time range (default: last hour).
- `useLogsSqlExecution` runs a promoted `SafeLogSqlFragment` against the
analytics OTEL (ClickHouse) endpoint with the resolved time range as
`iso_timestamp_start`/`iso_timestamp_end` request params. The endpoint
is **pinned to OTEL** — a snippet's dialect must not flip with org
migration.
- The run gestures (toolbar button and Cmd+Enter) branch on the source
and promote with the matching `acceptUntrusted*` right at the user
action, preserving the auditable promotion-at-gesture boundary. pg
intellisense is gated off for logs snippets.
- The `sql_editor_query_run_button_clicked` telemetry event gains a
required `{ source: 'database' | 'logs' }` property, fired from both
execution paths.
- Capability guard: a `log_sql` snippet is reachable by direct URL
regardless of the (later) entry-point flag gating, so `executeLogsQuery`
short-circuits when `otelLegacyLogs` is off — recording a clear "not
available yet" result message instead of firing a request that would
only return an opaque backend error on a non-ClickHouse project. This is
a guard on the gesture, not endpoint selection.
- Tests: `useRunSource` routing, `useLogsSqlExecution`
endpoint/range/structured-error/capability-guard, and a reusable `flags`
option on `renderSqlEditorHook`.

No UI entry points are added — the feature runs dark until the
flag-gated creation/nav PRs later in the stack.

## Additional context

Stacked on the query-source series; base branch is `master` now that PR
4 (log date range domain + session state, #48401) is merged. Follow-ups
in the stack add the toolbar/creation UI (with a run-affordance gate on
`otelLegacyLogs`), nav section, AI dialect support, and reports guard.

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

## Summary by CodeRabbit

* **New Features**
  * Added support for running log queries directly from the SQL editor.
* Log query results, errors, and time ranges are now handled within the
editor session.
* Added automatic selection between database and log query execution,
including support for custom date ranges.
* SQL assistance is disabled while editing log queries where database
definitions do not apply.

* **Tests**
* Added coverage for log query execution, date ranges, feature
availability, and execution source selection.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-29 10:43:48 -04:00
Charis d5436ae826 feat(studio): log date range domain + session logRange state (#48401)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Feature (+ a small refactor and a docs/convention note). PR 4 of the
stacked SQL-editor query-source series (Database vs Logs).

## What is the current behavior?

The SQL editor has no representation of a logs query's time range:
`querySource.ts` only knows how to map a snippet type to a source
(`getSnippetSource`), and session state (`sql-editor-session-state.ts`)
tracks results and the row limit but not a per-snippet time range. The
Logs date picker's pure range helpers (`parseCustomInput`,
`generateDynamicHelper`, the `Unit` type) are trapped inside the
`Logs.DatePickers.tsx` React component.

## What is the new behavior?

- **Logs time-range domain** in `querySource.ts`: branded
`IsoDateTimeString` + `isoDateTimeString()`, `RelativeTimeUnit`, a
`LogDateRange` discriminated union (relative/absolute),
`DEFAULT_LOG_DATE_RANGE`, a single date-picker parser
(`datePickerValueToLogDateRange` / `logDateRangeToDatePickerValue` —
handles the five presets *and* dynamic `2h`/`30m` helpers; `calcTo ===
''` means "now"; unparseable helpers degrade to absolute), and
`resolveLogRunRange` which re-resolves relative ranges against `now` at
run time (reusing the existing `ResolvedLogDateRange` shape).
- **Session state**: per-snippet `logRange` + `setLogRange` —
session-only, never written to snippet content, so it works on read-only
shared snippets and is cleaned up in `clearForSnippet`.
- **Refactor**: extracted the picker's framework-free helpers into a new
pure `Logs.datePickerHelpers.ts`; the logs domain now shares the `Unit`
type and reuses `generateDynamicHelper` instead of duplicating them.
Importers point at the new module directly (no re-export shim). Hardened
the amount parse against `NaN`.
- **Full unit coverage** in `querySource.test.ts`. Recorded the no-shim
refactoring convention in the `studio-best-practices` skill.

Verification: `pnpm typecheck` clean, lint ratchet improved, 43 tests
pass (querySource + Logs.Datepickers), Prettier clean.

## Additional context

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

- **New Features**
- Added robust Logs date-range modeling with support for relative (e.g.,
last N units) and absolute time periods.
  - SQL Editor sessions now remember log date ranges per snippet.
- **Bug Fixes**
- Safer handling of invalid or missing date inputs, with sensible
fallback to default/current time.
- **Tests**
- Added/expanded automated coverage for date-range conversion, helper
parsing, and resolution behavior.
- **Refactor**
- Centralized date-picker helper utilities for reuse across the Logs and
SQL query experience.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-28 13:49:11 -04:00
Alaister YoungandAlaister Young ca2b50a0a7 chore(ui-patterns): collapse the admonition shim into ui-patterns/Admonition (#48377)
Follow-up to #48344: collapses the two resolution paths for the
Admonition module into one.

`src/admonition.tsx` was a back-compat shim re-exporting
`src/Admonition/`. Two ways to resolve one module is exactly what
produced the macOS self-import bug fixed in #48344, and the local
typecheck errors that #48374 worked around. This removes the shim and
standardizes on the PascalCase subpath, matching every other export in
the package.

**Changed:**

- Codemodded all 246 `ui-patterns/admonition` imports to
`ui-patterns/Admonition` (240 `.tsx`, 5 `.mdx`, 1 `.ts` across studio,
docs, www, design-system, and lite-studio)
- Pointed the 5 internal `'../admonition'` imports back at the
`'../Admonition'` directory

**Removed:**

- `packages/ui-patterns/src/admonition.tsx`, and its `./admonition`
entry in the exports map (regenerated with `pnpm gen:exports`)

## To test

- `grep -r "ui-patterns/admonition" --include='*.ts*'` → no hits
- `pnpm test:case-hazards` → passes
- `pnpm typecheck` → all 15 tasks green
- `pnpm --filter studio run lint:ratchet` → passes
- `pnpm --filter ui-patterns vitest run src/Admonition` → 11 tests pass

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

## Summary by CodeRabbit

* **Bug Fixes**
* Standardized Admonition component imports across the application and
documentation.
* Improved compatibility with case-sensitive environments by using the
canonical component path.
  * Removed the legacy Admonition import entry point.

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

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-07-29 00:48:56 +08:00
Charis fa5eb17277 feat(studio): discriminated snippet union + source-aware writes (#48313)
Stacked on #48305.

## What

PR 3 of the stacked SQL-editor query-source series (Database vs Logs).
Stacked on the PR 2 branch `charislam/log-sql-content-shape`.

Turns `SnippetWithContent` into a discriminated union on `type` and
makes all snippet writes source-aware:

- `data/content/sql-folders-query.ts`: `SnippetWithContent` is now `{
type: 'sql'; content?: SqlSnippets.Content } | { type: 'log_sql';
content?: LogSqlSnippets.Content } | { type: 'report'; content?: never
}`. `report` is kept (the content endpoints' wire type carries it) but
has no SQL content — its body is `Dashboards.Content`, loaded through
the separate `Content` union.
- `setSql` brands per type (`untrustedLogSql` vs `untrustedSql`).
- `buildUpsertPayload` persists `snippet.type` (no longer hardcoded
`'sql'`).
- `createSqlSnippetSkeletonV2({ source })` emits the matching type +
content shape with the `as any` cast removed.
- New `components/interfaces/SQLEditor/querySource.ts`:
`SqlSnippetSource` + `getSnippetSource`.
- `seedSnippet` test helper gains a `source` arg.
- New `remapWireSnippet` boundary helper in `content-remap.ts`
concentrates the single wire->domain assertion, so `content-id-query` /
`content-upsert-mutation` call sites are cast-free (no `as unknown as`).
- Collateral: query result types aligned to the union; `updateSnippet`
no longer accepts `type` (source is immutable); db-only editor read
paths narrow away `log_sql`.

## Why

Impossible-states-impossible typing: a snippet's brand follows its
content type, so logs SQL and database SQL can never cross execution
paths. No behavior change for existing database snippets.

## Testing

- \`pnpm typecheck\` — clean
- \`pnpm --filter studio run lint:ratchet\` — no new warnings
- \`pnpm test:studio\` (data/content, SQLEditor, state/sql-editor) —
passing, including new tests for \`getSnippetSource\`, source-aware
\`setSql\`, type-aware \`buildUpsertPayload\`, and both skeleton shapes.

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

* **New Features**
* Added source-aware creation for SQL editor snippets, including
log-based SQL snippets.
* Introduced backend source mapping so log snippets are treated as
log_sql.
* **Bug Fixes**
* Improved SQL retrieval/prettification so log snippets no longer use
the wrong fallback content.
* Ensured log snippets are sanitized and preserve correct type, content,
identifiers, and statuses during save/upsert flows.
* **Tests**
* Expanded unit and integration coverage for log snippet creation,
source mapping, editing, prettification, and upsert payloads.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-28 12:28:36 -04:00
Charis 7743fee3ab feat(studio): log_sql content shape + remap content.sql to unchecked_sql (#48305)
## What

PR **2 of 9** in the SQL-editor query-source (Database vs Logs) stack.

**Base:** `charislam/snippet-source-typing` (#48301) — this is a stacked
PR; review/merge that one first.

Client-side rename only — **the wire format is unchanged** (the platform
API still stores and returns `content.sql`). This moves the frontend
`LogSqlSnippets.Content` field to the branded `unchecked_sql`, matching
`SqlSnippets.Content`, and hardens the remap boundary so the rename
can't silently drop saved query text.

## Changes

- **`types/userContent.ts`** — `LogSqlSnippets.Content`'s plain `sql:
string` becomes `unchecked_sql: UntrustedLogSqlFragment` (the brand
added in PR 1). Shape kept minimal: `{ content_id, unchecked_sql,
schema_version }`.
- **`data/content/content-remap.ts`** — extend
`remapSqlContentField`/`unmapSqlContentField` to `log_sql`, branding
**per type** (`untrustedLogSql` for logs, `untrustedSql` for database)
and never mixing brands. **Defensive unmap**: content missing
`unchecked_sql` is never clobbered with `sql: undefined`; a residual raw
`sql` field (a missed save-path rename) throws in development to surface
the bug loudly, while production no-ops safely.
- **Legacy Logs Explorer consumers** updated to the branded field: the
explorer save/update paths, `SavedQueriesItem`, `RecentQueriesItem`, and
the recent-queries page.
- **Two db-only write sites** that leaned on
`LogSqlSnippets.Content.sql`: `EditorPanel` now saves `unchecked_sql`,
and `MoveQueryModal` switches to the SQL-editor-specific
`getSqlSnippetById` so its content is typed as `SqlSnippets.Content` —
no narrowing or casting.

## Tests

- **content-remap**: `log_sql` remap/unmap round-trip with the logs
brand; the defensive-unmap no-op (prod) and dev throw.
- **content-upsert-mutation**: a `log_sql` payload reaches the wire as a
plain `content.sql` and the response remaps back to `unchecked_sql` (the
data-loss-critical round-trip shared by both explorer save-new and
`SavedQueriesItem` update).

## Verification

- `pnpm --filter studio run typecheck` ✓
- `pnpm --filter studio run lint:ratchet` ✓ (no new warnings)
- `pnpm test:studio` for `data/content` + `Settings/Logs` — 139 passing
✓
- Prettier ✓

Nothing is user-visible yet — logs snippet entry points arrive later in
the stack behind the `sqlEditorLogsSource` flag.

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

- **Bug Fixes**
- Improved handling of saved and recent log queries across the SQL
editor and Logs Explorer.
- Log SQL now uses `unchecked_sql` (branded as untrusted) consistently
when creating, editing, moving, and reopening queries, with correct
remapping to/from the API boundary.
- Fixed saved-query update payloads to preserve the right query content
and omit legacy fields.

- **Tests**
- Added/expanded Vitest coverage for saved log query editing, recent-log
normalization, and `log_sql` remap/upsert request/response behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-28 10:47:43 -04:00
Charis 0bef8e7d90 test(sql-editor): e2e coverage + delete jsdom test + merge Results.utils tests (Steps 5-6) (#48217)
## Summary

Steps 5 and 6 of the SQL editor test refactor plan (the final two
steps).

**Step 5** — extends `e2e/studio/features/sql-editor.spec.ts` (real
browser, zero mocks) with cases that need the real Monaco editor / full
app render:
- destructive-query warning modal: confirm actually re-runs the forced
query (previously only `Cancel` was exercised)
- debug button opens the AI Assistant with the query error pre-filled

Deletes `apps/studio/tests/components/SQLEditor/SQLEditor.test.tsx` —
its logic-level cases are now covered mock-free by the Step 4 hook
tests, and its integration cases by e2e. Deleting rather than narrowing
is the honest consequence of "no mocking": every remaining assertion it
could make in jsdom requires a Monaco mock.

**Step 6** — merges
`apps/studio/tests/components/SQLEditor/Results.utils.test.ts`
(`formatClipboardValue`/`formatCellValue`) into the colocated
`apps/studio/components/interfaces/SQLEditor/UtilityPanel/Results.utils.test.ts`
(`formatResults`/`convertResultsToMarkdown`/`convertResultsToJSON`/`getResultsHeaders`/`isLargeValue`/`convertResultsToCSV`)
— both tested disjoint exports of the same source file. Deletes the
`tests/` copy.

This is the last step in the plan.

## Test plan

- [x] `pnpm --filter studio typecheck` — no new errors in changed files
- [x] `npx prettier --check` on all changed files
- [x] Ran the new/changed e2e cases locally end-to-end against a live
local stack — both pass
- [x] `cd apps/studio && npx vitest run
components/interfaces/SQLEditor/UtilityPanel/Results.utils.test.ts` —
42/42 passing after the merge

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

* **Tests**
* Added end-to-end coverage for destructive SQL query warning modal flow
before forced execution.
* Added end-to-end coverage for the AI Assistant debug flow when SQL
execution fails.
* Expanded unit test coverage for SQL editor results formatting
utilities (clipboard and cell value formatting).
* Removed the prior SQLEditor unit test suite and the older
results-formatting unit tests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-22 16:55:17 -04:00
Charis 08c4f64c42 test(sql-editor): add mock-free hook tests (Step 4) (#48214)
## What

Step 4 of the SQL editor testability plan: **mock-free hook tests** for
the extracted SQL editor hooks, built on the Step 3 renderHook harness
(`tests/lib/sql-editor-test-utils.tsx`) — in-memory editor port + real
valtio stores + MSW. **Zero `vi.mock`.**

| File | Tests | Covers |
|------|-------|--------|
| `useSqlEditorExecution.test.tsx` | 8 | destructive-query gating
(`potentialIssues` vs. forced run), auto-limit suffixing,
connection-string → `x-connection-encrypted` header,
`onSuccess`/`onError` session-store writes, error-line highlight,
diff-open short-circuit |
| `useSqlEditorAi.test.tsx` | 7 | one-shot diff-request drain (empty vs.
non-empty editor), drain-exactly-once across remounts, accept/discard
diff, `onDebug` opening the assistant chat + debug prompt |
| `usePrettifyQuery.test.tsx` | 2 | in-place format + write-back,
diff-open no-op |
| `useSnippetIdentity.test.tsx` | 2 | generated identity + store-driven
loading state |
| `useSnippetTitleGenerator.test.tsx` | 2 | untitled-snippet naming via
the title endpoint |

Every test exercises real dependencies at the seam where they're real:
network via MSW, stores used real and reset per test, Monaco via the
in-memory editor port.

## Test plan

- [x] `pnpm test:studio -- SQLEditor` → **286/286 passing** (21 new
tests included)
- [x] `pnpm --filter studio typecheck` clean
- [x] Confirmed zero `vi.mock` in the new files


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

## Summary by CodeRabbit

* **Tests**
* Added comprehensive automated coverage for SQL query formatting,
snippet identity, and AI-generated titles.
* Added coverage for AI-assisted SQL editing, including diff acceptance,
rejection, debugging, and request handling.
* Added coverage for query execution, result persistence, safety checks,
replica selection, error highlighting, and diff-state behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-22 14:53:46 -04:00