Commit Graph
347 Commits
Author SHA1 Message Date
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
Charis 4d793a708e test(sql-editor): shared renderHook harness with in-memory editor port (#48209)
## Summary

- Add `renderSqlEditorHook()` test harness that eliminates mocking
Monaco by injecting a real, deterministic in-memory editor port
(EditorController/DiffController backed by plain JS state)
- Include `createInMemoryEditor()`, `resetSqlEditorStores()`, and
`setupSqlEditorMocks()` utilities to provide isolation and mock-free
network testing via MSW handlers
- Export `CustomWrapper` from custom-render and add optional
`editor`/`diff` injection points to SQLEditorProvider (production
unaffected via null-coalesce fallback)

This is **Step 3** of an in-progress SQL editor testability refactor
(Step 2 finished EditorController/DiffController port; this harness has
no consumers yet — hook tests land in a follow-up step).

## Test plan

- [x] `pnpm --filter studio typecheck` passes (already verified)

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

## Summary by CodeRabbit

* **Tests**
* Added reusable SQL Editor test utilities for in-memory editing,
selections, error highlighting, snippets, and diff content.
* Added helpers for resetting editor state, configuring API mocks, and
rendering SQL Editor hooks in a complete test environment.
* Enabled SQL Editor providers to accept optional controller overrides
for isolated testing.
  * Exported the shared test wrapper for reuse across test suites.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-22 13:32:55 -04:00
Alaister YoungandAlaister Young 0fe2366659 [FE-3790] fix(studio): hide Multigres from user-facing surfaces (#48191)
Hides the "Multigres" term from user-facing surfaces — it's the tech
powering High Availability projects, but "High Availability" is the only
term users should see for now (per Slack discussion with Saxon/Ivan).

**Changed:**
- High Availability badge hover card (project overview) no longer says
"Driven by Multigres"
- Project creation HA toggle description drops the Multigres name +
multigres.com link, keeps the informational copy
- All schema dropdowns now hide the `multigres` schema on HA projects,
by wiring in the previously-unused `filterSchemasForHighAvailability`
helper:
- `SchemaSelector` (shared — Table Editor, Functions, Indexes, Triggers,
Schema Visualizer, etc.)
  - `ExposedSchemaSelector` (API settings → exposed schemas)
- `EnableExtensionModal`, `CreateIndexSidePanel`, `ForeignKeySelector`,
`WrapperTableEditor`, Integrations install sheet `AdvancedSettings`
  - SQL editor schema autocomplete (`useAddDefinitions`)
- Schema list computations in the touched components are now memoized
(incl. stabilizing `SchemaSelector`'s `excludedSchemas` default so the
memo actually holds)

**Added:**
- Unit tests for `filterSchemasForHighAvailability` /
`resolveHighAvailability`
- MSW component test for `SchemaSelector` asserting `multigres` is
hidden on HA projects and still shown on non-HA projects

The filter is HA-gated on purpose: a self-hosted/non-HA user with their
own schema named `multigres` still sees it. The flag-gated Multigres
option in Logs is intentionally untouched — that exposure is kept for
the Multigres team's debugging (separate track).

## To test

- On an HA project (`high_availability: true`): hover the High
Availability badge on project overview — no "Multigres" mention; open
schema dropdowns in Table Editor / Database pages / SQL editor
autocomplete — no `multigres` schema
- Project creation with HA entitlement: toggle description has no
Multigres wording/link
- On a non-HA project: schema dropdowns behave as before

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

* **Improvements**
* Made schema dropdowns and related selectors high-availability aware
across extensions, indexes, integrations, SQL editing, API exposed
schemas, and relationship editors.
* Updated project high-availability UI text and badge hover description
to remove outdated branding and clarify horizontally scalable Postgres
architecture.
* **Tests**
* Added coverage to ensure the schema “multigres” option is hidden/shown
correctly based on high availability, and validated high-availability
value handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-07-23 00:08:11 +08:00
Charis 3d83e026f9 refactor(sql-editor): finish EditorController/DiffController port (Step 2) (#48166)
## Summary
Step 2 of the SQL Editor testability plan.

`SQLEditorContext` already wrapped the Monaco refs and exposed a few
semantic imperative helpers (`getEditorSql`, `clearHighlights`,
`applyErrorHighlight`, `refocusEditor`, …). This finishes that
abstraction so no hook or controller touches
`editorRef.current`/`diffEditorRef.current` directly anymore — they only
call the port. The port is what will let Step 3's test harness inject a
real in-memory editor adapter instead of mocking Monaco; production
wires it to the real Monaco refs, unchanged.

- Extends the context value with two semantic controllers, backed by the
existing refs:
- `editor: EditorController` — `isReady`, `getValue`,
`getSelectionStartLine`, `getSql` (today's `getEditorSql`), `replaceAll`
(wraps the repeated `executeEdits(...)` pattern), `focus`,
`revealLineInCenter`, `highlightErrorLine` (today's
`applyErrorHighlight`), `clearHighlights`.
- `diff: DiffController` — `isMounted`, `getModifiedValue`, `setDiff`
(the diff-sync effect body), `attach` (today's `handleDiffEditorMount`).
- Migrates every touch point off raw refs onto the port:
`useSqlEditorExecution`, `usePrettifyQuery`, `useSqlEditorShortcuts`,
`SQLEditorControllers`' `readEditorSql`, and `useSqlEditorAi`'s
`acceptAiHandler`/`drainDiffRequest`/`handleDiffEditorMount`/diff-sync
effect.
- `SQLEditorEditorPanel.tsx` is intentionally left untouched — it wires
the raw refs into the real Monaco/DiffEditor React components for
rendering, which isn't decision logic to abstract.

Behavior-preserving.

## Test plan
- [x] `pnpm --filter studio typecheck`
- [x] `pnpm test:studio -- SQLEditor` (265 tests passing)
- [x] `pnpm --filter studio run lint:ratchet`
2026-07-21 16:22:47 -04:00
Charis cdc843dadd refactor(sql-editor): extract deriveSnippetIdentity, debug/completion/diff-key helpers (#48014)
## Summary
Pure-fn extraction pass across the SQL editor hooks.

- Extracts `deriveSnippetIdentity` out of `useSnippetIdentity`'s inline
id + `isLoading` derivation into `SQLEditor.utils.ts`.
- Extracts `extractDebugContext` (shared snippet/result/error
extraction) and `buildDebugChatArgs` (the `aiSnap.newChat(...)` payload
builder) out of `useSqlEditorAi`'s `buildDebugPrompt`/`onDebug` into
`SQLEditor.utils.ts`.
- Extracts `buildCompletionRequestBody` (the AI completion endpoint's
request body builder) and `planDiffRequestApplication` (the
pending-diff-request application decision: replace vs. open a diff,
depending on whether the editor is currently empty) out of
`useSqlEditorAi` into `SQLEditor.utils.ts`. The `drainDiffRequest`
effect now just applies the plan instead of branching inline.
- Extracts `resolveDiffKeyAction` out of `useSqlEditorShortcuts`'s
window-keydown Enter/Escape branch into `SQLEditor.utils.ts`.

## Test plan
- [x] `pnpm --filter studio typecheck`
- [x] `pnpm test:studio -- SQLEditor` (265 tests passing)
- [x] `pnpm --filter studio run lint:ratchet`
2026-07-21 13:47:40 -04:00
Charis 1c827c5cbb refactor(sql-editor): extract title-gen/execute-params + merge auto-limit functions (#48013)
## Summary
Part 2/6 of the SQL Editor testability follow-up, stacked on #47980 (the
analyzeQueryIssues/resolveConnectionString PR).

- Extracts `shouldAutoGenerateTitle` and `buildExecuteParams` out of
`useSqlEditorExecution`'s inline logic into `SQLEditor.utils.ts`.
- Merges `checkIfAppendLimitRequired` and `suffixWithLimit` into a
single `applyAutoLimit` function — the two were only ever called
together and re-parsed the same query twice at every call site.
`applyAutoLimit` only accepts `SafeSqlFragment` (never a plain string)
and composes the `LIMIT` suffix through `safeSql`/`literal` rather than
raw template concatenation, so the only place in the file that reasserts
the `SafeSqlFragment` brand on a derived string is the small, dedicated
`trimTrailingSemicolons` helper — removing existing terminators can't
introduce unsafe content, unlike gluing new text onto the fragment.
- Updates the two other `checkIfAppendLimitRequired`/`suffixWithLimit`
call sites (`EditorPanel.tsx`, `ReportBlock.tsx`) accordingly;
`ReportBlock` now promotes its report SQL once and reuses the result for
both its display-only auto-limit hint and its execution, instead of
promoting twice.

## Test plan
- [x] `pnpm --filter studio typecheck`
- [x] `pnpm test:studio -- SQLEditor ReportBlock EditorPanel` (239 tests
passing)
2026-07-16 17:08:26 -04:00
Charis 11fb715149 refactor(sql-editor): extract query-issue analysis + connection string resolution (#47980)
## Summary
Part 1/6 of the SQL Editor testability follow-up (extracting pure
decision logic out of the SQL editor hooks so it can be exhaustively
unit-tested without mocking).

- Extracts `analyzeQueryIssues` and `hasBlockingIssues` out of
`useSqlEditorExecution`'s inline destructive-query /
warning-modal-gating logic into `SQLEditor.utils.ts`.
- Extracts `resolveConnectionString`, deduping the
`databases?.find(...)` lookup that was duplicated verbatim in both
`useSqlEditorExecution` and `useSqlEditorExplain`.
- Behavior-preserving — same runtime logic, now unit-testable in
isolation.

## Test plan
- [x] `pnpm --filter studio typecheck`
- [x] `pnpm test:studio -- SQLEditor.utils` (159 tests passing, includes
new exhaustive-permutation cases for the three extracted functions)

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

* **Bug Fixes**
* Improved SQL safety checks before execution, including destructive
queries, unsafe updates, database-altering commands, and tables missing
row-level security.
  * Correctly recognizes tables protected by active security triggers.
* Improved database connection selection for primary and read-replica
databases.
* Preserved the ability to run queries with force enabled when safety
warnings are present.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-16 15:30:44 -04:00
Ali Waseem b100272376 chore(sql-editor): remove Pretty Explain feature (#47981)
Removes the SQL Editor Pretty Explain feature — the Explain tab, the Run
EXPLAIN ANALYZE action + shortcut, and its dead plumbing. It's been
gated off behind the `DisablePrettyExplainOnSqlEditor` kill switch for
weeks with no usage or complaints.

`ExplainVisualizer` / `isExplainQuery` are kept — they're used
independently by Query Insights, Query Performance, and the EditorPanel
quick-runner. Manually-run `EXPLAIN` queries still render as raw rows in
the Results tab.

Typecheck, lint, and all affected unit tests pass.

Closes FE-3930

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

## Summary by CodeRabbit

* **Changes**
* Removed the SQL editor’s EXPLAIN execution workflow, including its
toolbar action, keyboard shortcut, utility tab, and visual query-plan
display.
  * Simplified query execution to focus on standard results and charts.
* Improved result clearing when switching databases and refined
execution error handling.
* Updated SQL editor state and tests to reflect the streamlined
experience.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-16 11:04:34 +08:00
Charis 9e80a159b5 refactor(sql-editor): decompose into controller contexts + presentational components (decompose 6/6) (#47938)
## What

Final step (**6 of 6**) of the `SQLEditor.tsx` decomposition. Splits the
two `ResizablePanel` bodies out of the `SQLEditorContent` monolith into
presentational sub-components:

- **`SQLEditorPane`** — the editor panel: loading state, `DiffEditor` +
diff ask-AI widget, `MonacoEditor` + ask-AI widget. Reads the Monaco
refs (`editorRef`/`monacoRef`/`diffEditorRef`) from `SQLEditorContext`,
and receives the `diff`/`prompt`/`ai` controllers plus reactive state as
props.
- **`SQLEditorResults`** — the results panel: loading state +
`UtilityPanel`.

`SQLEditorContent` is now a composition root: shared-ref provider, hook
composition, and the run-query warning modal.

## Result

`SQLEditor.tsx` goes from the original **1056-line** monolith down to
**259 lines** (≈75% reduction). The remaining size over a bare ~140-line
root is the run-query warning modal, kept inline **deliberately**: its
handlers hold the `acceptUntrustedSql` promotion, which must stay at the
explicit user-action boundary in the root rather than moving into a
presentational pane.

## Behavior-preserving

The moved JSX is byte-identical aside from prop threading. No logic,
effects, dependency arrays, or `eslint-disable`s changed. The two
**render-time ref reads** — the editor placeholder (`!promptState.isOpen
&& !editorRef.current?.getValue()`) and the ask-AI widget gate
(`editorRef.current && promptState.isOpen && !isDiffOpen`) — are
preserved verbatim in `SQLEditorPane`, which re-renders whenever the
`prompt`/`diff` props change, keeping those reads fresh (the guardrail
from the plan).

Verification (all green):
- `SQLEditor.test.tsx` characterization suite — 11/11 pass
- `tsc --noEmit` — no new errors
- eslint — clean (no new ratchet entries)
- prettier — clean

## Stack

Builds on decompose 5 (#47935). This is the last PR in the series — the
decomposition is complete after this merges.


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

* **New Features**
* Added a resizable SQL editor layout with run warnings, query results,
and an Explain view.
* Introduced centralized SQL editor controllers and expanded AI-assisted
prompt/diff workflows.
  * Added keyboard support for running and Explain analysis.
* **Bug Fixes**
  * Restored editor focus after accepting or discarding AI changes.
  * Improved handling and validation of SQL Explain actions.
  * Preserved editor scroll position when switching snippets.
* **Refactor**
* Streamlined the SQLEditor into a composed layout and improved
memoization to reduce unnecessary re-renders.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-15 13:10:09 -04:00
Charis 52a25c2ebb refactor(sql-editor): extract AI/diff + shortcuts hooks (decompose 5/6) (#47935)
## What

Decompose step **5 of 6** for `SQLEditor.tsx`. Extracts the Assistant /
diff cluster and the keyboard-shortcut wiring out of the
`SQLEditorContent` monolith into two focused, individually-testable
hooks:

- **`useSqlEditorAi`** — SQL completion (`complete`), the ask-AI prompt
flow (`handlePrompt`), accept/discard diff handlers, `onDebug` /
`buildDebugPrompt` helpers, `handleDiffEditorMount`, and the fragile
diff lifecycle effects (one-shot diff-request drain, diff-editor value
sync, ask-AI widget visibility).
- **`useSqlEditorShortcuts`** — the registered shortcuts (focus editor,
new snippet, format, explain) plus the accept/discard/escape keydown
handling.

`SQLEditorContent` now composes these hooks alongside the
execution/explain hooks landed in decompose 4.

## Behavior-preserving

This is a pure extraction. The moved function bodies, effect logic,
dependency arrays, and JSX are unchanged from the previous monolith
(verified via `git diff` against the pre-decomposition source). In
particular:

- `useEffectEvent` is preserved for `drainDiffRequest` / `resetDiff`.
- `editorMountCount` remains single-owner (passed into the AI hook to
drive the one-shot drain).
- The untrusted→safe SQL promotion (`acceptUntrustedSql`) continues to
happen in the run/explain gesture and warning-modal handlers in
`SQLEditorContent`, as close to the explicit user action as possible.

The Phase-1 characterization suite (`SQLEditor.test.tsx`, 11 tests)
remains green.

## Stack

Part of the SQLEditor decomposition stack (1/6 … 6/6). Builds on
decompose 4 (execution + explain hooks, #47923). Next: PR6 splits the
JSX into panes + final cleanup.


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

## Summary by CodeRabbit

* **New Features**
* Improved SQL editor AI assistance, including completion prompts,
debugging support, and diff review controls.
* Added keyboard shortcuts for accepting or discarding AI-generated SQL
changes.
* Added shortcuts for focusing the editor, creating snippets, formatting
queries, and explaining SQL.

* **Bug Fixes**
  * Prevented SQL execution while reviewing AI-generated differences.
* Improved handling of AI diff state during editor loading and
interaction.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-14 15:14:12 -04:00
Charis 3fa7f086df refactor(sql-editor): extract execution + explain hooks (decompose 4/6) (#47923)
## Summary

PR **4 of 6** in the SQLEditor decomposition stack. Extracts the two
query-run concerns out of the composition root into cohesive hooks.
Behavior-preserving — the characterization suite stays green.

## New hooks

- `useSqlEditorExecution` — the execute mutation, the `executeQuery`
pipeline (destructive-query gating, lazy title generation, connection
resolution), and the `potentialIssues` warning-modal state.
- `useSqlEditorExplain` — the execute-explain mutation and the
`executeExplainQuery` pipeline.

Both pipelines accept an **already-promoted `SafeSqlFragment`**.

## Safe-SQL boundary

Per review guidance, `acceptUntrustedSql` promotion stays in the
**composition root's** run/explain gesture handlers and warning-modal
confirm handlers — as close to the explicit user action as possible, so
it's auditable. The hooks never call `acceptUntrustedSql`; they only
accept safe SQL. `executeQuery` lists its (now all-stable) dependencies
directly rather than suppressing `react-hooks/exhaustive-deps`.

## Verification

- `vitest` — 11 characterization tests pass
- `pnpm --filter studio typecheck` — clean for SQL editor files
- `eslint` / `lint:ratchet` — pass (0 new violations)
- `prettier --check` — clean

`SQLEditorContent` is down to ~530 lines (from 1056 at the start of the
stack). Remaining: PR5 (AI/diff + shortcuts), PR6 (JSX pane split +
cleanup).

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

## Summary by CodeRabbit

* **Bug Fixes**
* Improved SQL query execution safeguards for potentially destructive
statements, unsafe updates, and missing row-level security coverage.
* Improved EXPLAIN handling, including clearer validation for
unsupported multi-statement queries.
* Preserved query results, errors, and EXPLAIN output more reliably in
the SQL editor.

* **Improvements**
* Added clearer execution status handling and more consistent editor
focus, highlighting, and utility-tab behavior.
* Improved connection selection and SQL execution reliability across
supported database configurations.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-14 10:37:22 -04:00
Charis c9a649cf73 refactor(sql-editor): extract snippet-identity/mount/prettify/title hooks (decompose 3b/6) (#47893)
## Summary

Continues the SQLEditor decomposition. Pulls four cohesive concerns out
of the `SQLEditorContent` composition root into co-located `use*` hooks.

## New hooks

- `useSnippetIdentity` — derives `id` / `generatedNewSnippetName` /
`isLoading` from the URL + snippet store (keeps the `[urlId]` memo dep
verbatim).
- `useEditorMount` — the editor `onMount` (scroll restore/track) + the
mount counter that lets a pre-mount diff request re-run.
- `usePrettifyQuery` — formats the editor SQL in place and writes it
back to the store.
- `useSnippetTitleGenerator` — the title-generation mutation +
`setAiTitle`.
2026-07-13 15:35:30 -04:00
Charis 9726940dba refactor(sql-editor): own shared editor refs in SQLEditorContext (decompose 3/N) (#47837)
## Summary

PR **3** in the SQLEditor decomposition stack. The keystone structural
step: introduce a context provider that owns the shared, mutable Monaco
state, so later PRs can extract logic hooks and presentational panes
without threading the same three refs through every signature.

Behavior-preserving — the characterization suite (merged in PR 1) stays
green with identical assertions.

## What changed

New `SQLEditorContext.tsx`:
- `SQLEditorProvider` owns the shared refs (`editorRef`, `monacoRef`,
`diffEditorRef`, `scrollTopRef`), the run-refocus flag, and the
error-highlight decorations.
- `useSQLEditorContext()` guard hook (React 19 `use()`), mirroring the
canonical `PoliciesDataContext` pattern.
- Stable helpers: `refocusEditor`, `clearPendingRunRefocus`,
`markRefocusAfterRun`, `refocusEditorAfterRunIfNeeded`, `getEditorSql`,
`clearHighlights`, `applyErrorHighlight`.

`SQLEditor.tsx`:
- Split into
`<SQLEditorProvider><SQLEditorContent/></SQLEditorProvider>`.
- `SQLEditorContent` reads refs/helpers from context instead of local
`useRef`/`useCallback`.
- `lineHighlights` moves from React state to a ref inside the provider
(decorations are purely imperative; nothing renders off them). This also
removes the stale-closure hazard the old `executeQuery` dep-array
omission worked around.

The context value holds only stable identities (refs + `useCallback`s,
memoized once), so the provider never re-renders its consumers — it's a
dependency-injection channel, not reactive state.

## Verification

- `vitest` — 156 pass (characterization + utils), assertions unchanged
- `pnpm --filter studio typecheck` — clean for all SQL editor files (the
two `@sentry/tanstackstart-react` errors are a pre-existing
local-install gap on master, unrelated)
- `eslint` — 0 errors
- Equivalence: single `useEffectEvent`, `drainDiffRequest`
driving-effect deps `[diffRequest.pending, editorMountCount]`
byte-identical, all 8 `eslint-disable` dep arrays preserved

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

* **Bug Fixes**
* Improved SQL editor focus restoration after running or explaining
queries.
* Centralized run/explain highlighting so errors are highlighted
consistently and old highlights are reliably cleared.
* Ensured the SQL snippet used for run/explain is derived consistently
from the current editor state.
* **Refactor**
* Restructured the SQL editor to use a shared internal context for
editor UI, refs, and imperative highlight/focus helpers, keeping the
external editor interface unchanged.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-13 13:02:03 -04:00
Charis b6cdd5cce3 refactor(sql-editor): extract pure SQL helpers + tighten safe-SQL boundary (decompose 2/6) (#47831)
## Summary

1. **Extract pure logic** out of the 1056-line `SQLEditor.tsx` monolith
into unit-tested functions in `SQLEditor.utils.ts`.
2. **Remove `rawSql()` from the SQL editor** and tighten the
untrusted→safe boundary per the `safe-sql-execution` model.

## Extracted functions (+ tests)

- `getEditorSql(editor, snippetContent?)` — selection → full value →
snippet fallback. Returns an **`UntrustedSqlFragment`** so
editor/snippet SQL keeps its provenance.
- `computeErrorHighlightLine(error, startLineNumber)` — parses the `LINE
n:` marker + selection offset.
- `assembleCompletionDiff(meta, text)` — before/selection/after assembly
for the AI completion diff.
- `buildExplainSql(sql, impersonatedRoleState)` — takes an already-safe
fragment; EXPLAIN ANALYZE + role impersonation + rollback wrapping.
- `buildDebugPromptText(sql, errorMessage)` — the assistant debug prompt
string.

## Safe-SQL boundary

- `rawSql()` is no longer used anywhere in the SQL editor.
- `executeQuery` / `executeExplainQuery` now **require a
`SafeSqlFragment`** — safe by construction, so they can never auto-run
untrusted SQL.
- `acceptUntrustedSql` promotion happens **only in the small run/explain
gesture handlers** (`executeQueryFromButton`, `handleRunShortcut`,
`handleRunExplain`, and the warning-modal confirm handlers), never
buried in the long helpers.

## Verification

- `vitest` — 156 pass (11 characterization + 145 utils, incl. new cases)
- `pnpm --filter studio typecheck` — clean for all SQL editor files (two
unrelated `@sentry/tanstackstart-react` module-resolution errors exist
on current master pre-install; not touched by this PR)
- `eslint` — 0 errors

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

## Summary by CodeRabbit

* **Enhancements**
* Improved SQL execution and EXPLAIN workflows with safer handling at
run and analysis actions.
  * Enhanced SQL selection and snippet handling in the editor.
* Improved error highlighting to more accurately identify affected
lines.
* Refined completion previews and debugging prompts for clearer results.
* EXPLAIN ANALYZE now supports rollback-wrapped execution and avoids
duplicate wrapping.

* **Bug Fixes**
* Improved behavior when working with selected, empty, or missing SQL
content.
* Prevented existing EXPLAIN statements from being unnecessarily
modified.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-10 15:00:58 -04:00
Charis 3461d60aba feat(sql-editor): consolidate controls into a single top bar (#47792)
## 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?

Refactor / UI improvement

## What is the current behavior?

SQL editor controls are split across two rows: a bar between the editor
and results (tabs, download,
run/save/format/db-selector/role/favorite/intellisense) and a separate
footer at the very bottom (row count + limit dropdown).

## What is the new behavior?

All controls are consolidated into a single top bar above the editor (⋮
overflow menu, database selector, role impersonation, limit, save, run).
The bar between the editor and results now holds only result-relevant
information: the Results/Explain/Chart tabs, the row-count summary, and
the Export button. The limit dropdown is now always visible as a
persistent query setting.
2026-07-10 10:27:43 -04:00
ChloeGarciaMillerandandGildas Garcia 59a82c52f8 Fix: improve accessibility for icon button (SQL Editor menu) (#47674)
## 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 (accessibility improvement)

## What is the current behavior?

Icon-only button (not visible on widescreen displays) does not have
explicit accessible name for screen readers and tooltip.

## What is the new behavior?

The icon-only button now has explicit accessible name using visually
hidden text (sr-only), ensuring proper screen reader support.

## Additional context

Tooltip text is added for visual users.
No visual changes were introduced


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

* **UI Improvements**
* Added a tooltip to the SQL editor’s “More actions” dropdown button,
improving discoverability.
  * The tooltip now shows “More actions” when hovering over the trigger.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
2026-07-10 11:30:45 +02:00
Charis 1987f19d0a feat(sql-editor): add manual save feature preview (#47745)
## What

Adds an opt-in **SQL Editor manual save** feature preview that switches
the SQL Editor from autosaving every edit to saving only on demand, and
hardens the tab-close flow so unsaved edits are handled correctly.

## Changes

**Feature preview**
- New `sqlEditorManualSave` flag + `UI_PREVIEW_SQL_EDITOR_MANUAL_SAVE`
local-storage toggle, wired into the Feature Preview modal with an
explanatory panel.
- `useIsSqlEditorManualSaveEnabled` gates behavior on both the flag and
the user's preview opt-in.

**Editor toolbar**
- Save button (with `Cmd+S`) next to Run, plus an autosave status
indicator showing dirty/saving/saved state and a shortcut to disable
autosave (emits a `sql_editor_autosave_disable_clicked` telemetry
event).

**Discard on close**
- Closing a snippet tab with unsaved edits prompts for confirmation and,
on confirm, actually discards the local edits and evicts the cached
server copy so the snippet reopens clean.

**Decouple tab layout from SQL specifics**
- Tabs store gains a generic per-type close-handler registry
(`registerTabCloseHandler` / `getCloseConfirmation` / `closeTabs`). The
SQL editor registers its discard + confirmation behavior from the save
coordinator.
- Low-level `removeTab`/`removeTabs` (rename/move re-keying, stale
cleanup) intentionally do **not** trigger discard.
- Adds `statusOnDiscard` lifecycle transition and `clearSnippetContent`
store action.

## Testing
- `pnpm --filter=studio typecheck` — clean.
- Added unit tests for the close-handler registry (fires on single/multi
close, skips re-keying/cleanup removals, respects tab type, selects
confirmation copy, unregisters cleanly).

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

* **New Features**
* Added a SQL editor manual-save preview with a “Save” button and
`Cmd+S`, plus a modal option to disable manual-save/preview.
* Added “unsaved changes” tab status indication when manual-save is
enabled.
* Introduced tab-type-specific close confirmations (shown only when
needed).
* **Bug Fixes**
* In manual-save mode, closing a SQL tab with unsaved edits now clears
local snippet content and refreshes it on reopen.
* **Tests**
  * Added coverage for tab close handlers and confirmation behavior.
* **Chores**
* Added a persisted setting allowlist entry and tracked autosave-disable
clicks via telemetry.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-09 08:37:38 -04:00
Vaibhav c070893475 fix: limit regex (#47717)
- closes https://github.com/supabase/supabase/issues/47712 

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

## Summary by CodeRabbit

* **Bug Fixes**
* Improved SQL query handling so automatic row limits are no longer
added when a query already ends with `LIMIT`, even if there’s whitespace
before the semicolon.
  * Preserved correct behavior for queries using `LIMIT ... OFFSET ...`.
* **Tests**
* Expanded coverage for SQL limit detection and limit-suffix behavior
around whitespace and semicolon placement.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-08 08:11:39 -06:00
Gildas Garcia cabe14e5ca chore: remove _Shadcn_ suffix from ui tabs components (#47628)
## Problem

Now that we migrated all usages of the deprecated `Tabs` component, we
don't need the `_Shadcn_` suffix anymore.

## Solution

Remove `_Shadcn_` suffix from `ui` tabs components. That's all this PR
does, no visual nor functional changes

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

## Summary by CodeRabbit

* **New Features**
* Standardized tab components across the app so pages and dialogs now
use the same consistent tab UI.
* Improved tab-based views in design, docs, studio, learn, and website
experiences for a more uniform interface.

* **Chores**
* Updated shared UI exports to expose tab components directly,
simplifying future usage across the product.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-06 15:29:16 +02:00
Charisandsupabase-autofix-bot cdc2dc4e26 refactor(studio): import SQL editor store from source, delete facade + barrel (#47533)
## What

Final PR of the SQL editor state re-layering stack. Removes the
compatibility shims left in place during the migration:

- Migrates all **23** consumers of the `@/state/sql-editor-v2` facade to
import directly from `@/state/sql-editor/sql-editor-state`, where
`useSqlEditorV2StateSnapshot`, `getSqlEditorV2StateSnapshot`,
`useSnippets`, and `useSnippetFolders` actually live.
- Deletes `state/sql-editor-v2.ts` (the facade) and
`state/sql-editor/index.ts` (the barrel). Both re-exported the same
symbols; nothing imports them after the migration.

This collapses the two-layer re-export (`sql-editor-v2` → `index` →
source) into direct source imports, matching the repo convention to
avoid barrel re-export files.

## Notes

- Pure import-path migration — no behavior change. All 23 consumers
imported only value symbols that resolve to `sql-editor-state.ts`; none
imported the `StateSnippet`/`StateSnippetFolder` types via the facade.
- Symbol names keep their `V2` suffix for now — renaming
`useSqlEditorV2StateSnapshot` etc. is a separate, larger churn best done
on its own.
- 25 files: 23 one-line import changes + 2 deletions (23 insertions / 39
deletions).

## Validation

- `pnpm --filter studio typecheck` ✅ (confirms no dangling facade/barrel
imports anywhere)
- `pnpm exec vitest --run state/sql-editor/` ✅ (113 passed)
- lint ✅ (0 errors; no ratcheted-rule regressions — a path swap can't
add `any`/deps/nested-component violations, and no import-order rule is
enforced)
- grep confirms zero remaining `sql-editor-v2` references

---------

Co-authored-by: supabase-autofix-bot <noreply@supabase.com>
2026-07-02 13:15:47 -04:00
Ali WaseemandIvan Vasilov 3fcf980b0a fix(studio): batch of production Sentry crash fixes (array/null guards) (#47460)
Fixes a batch of production Studio crashes from Sentry (all caught by
the global error boundary). Most are missing array/null guards where an
endpoint typed as an array — or with a nested array field — returned a
non-array body in production; a few are one-off render crashes.

Resolves FE-3748.

## Issues fixed

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


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

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

---------

Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
2026-07-02 08:38:17 +00:00
Charis 7c1ea30e43 refactor(studio): extract useSnippetEditor from MonacoEditor (#47500)
## What

PR 7 of the SQL editor state re-layering stack. Extracts the snippet
editing lifecycle out of `MonacoEditor` into a co-located
`useSnippetEditor` hook, and consolidates the edit debounce.

`useSnippetEditor` owns:
- creating the snippet in the store on first edit and routing to its URL
(replace vs push for a `?content=` deep link)
- writing changes back to the store via `setSql` (with
`wasNeverPersisted` → `shouldInvalidate`)
- seeding the editor from the `content` param
- the read-only determination (`canEditSnippet`)

`MonacoEditor` now consumes `{ snippet, disableEdit, handleEditorChange
}` and keeps only the editor shell + Monaco action wiring. It sheds the
`router`/`profile`/`project`/`params`/store/tabs hooks.

`handleEditorChange` was also flattened with an early return.

## Debounce consolidation

Previously there were **two 1s debounces in series**: `useSnippetEditor`
debounced editor changes before writing to the store, and the save
mechanism (`createSaveMechanism`) already debounces persistence. That
added latency (up to ~2s to save) and split the "when to persist" timing
policy across two layers — at odds with PR 5's design where the
scheduler/mechanism owns *when* and dirty state is meant to be
immediate.

This PR removes the editor-side debounce: edits write to the store
synchronously on every change, and the save mechanism's 1s debounce is
the sole throttle. Net effects:
- the store — and the snippet's dirty status — reflects the latest edit
immediately (correct for the future manual-save mode's Save button / nav
guard)
- save fires ~1s after the *last* keystroke instead of up to ~2s
- only the active snippet's own reactive consumers (a lightweight
sidebar item) re-render per keystroke; Monaco is uncontrolled
(`defaultValue`) so it is unaffected

Note: the double-debounce was legacy (the pre-refactor god store had the
same `useDebounce(value, 1000)` in MonacoEditor plus a debounced
module-load subscribe).

## Notes

- Behavior-preserving in outcome — autosave still lands ~1s after typing
stops, just with lower latency and immediate store consistency.

## Validation

- `pnpm --filter studio typecheck` ✅
- `pnpm exec vitest --run state/sql-editor/` ✅ (110 passed)
- lint ✅ (0 errors; no ratcheted-rule regressions)

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

## Summary by CodeRabbit

* **New Features**
* SQL editor changes now apply immediately, with unsaved status
reflected as soon as you edit.
* The editor now keeps the latest snippet details available for saving,
improving reliability when using “Save Query.”

* **Bug Fixes**
* Improved handling for creating and opening snippets from shared links
or prefilled content.
* Fixed status updates so saved snippets correctly switch to unsaved
after edits.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-01 15:59:15 -04:00
Joshen Lim 7203a97a90 Chore/clean up feature flags 300626 (#47429)
## Context

Cleans up a number of stale feature flags that have been enabled for all
users for more than 3 months
- enableSmartRegion
- SentryLogDrain
- axiomLogDrain
- S3logdrain
- Last9LogDrain
- otlpLogDrain 
- ShowPrettyExplain
- pgdeltaDiff
- CustomOauthProviders
- timezonePicker

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

* **New Features**
  * Timezone selector is now always available in the user menu.
  * Log drain “Type” options are expanded in the creation flow.
* Custom auth providers now appear when the custom providers setting is
enabled.
* **Bug Fixes**
* Smart region selection and related queries now follow the selected
cloud provider.
* PG Delta Diff preview availability and SQL editor “EXPLAIN” routing
now follow the latest enabled settings (including platform-only preview
behavior).
* **Changes**
* Removed the Storage List-V2 migration callout from the Storage
settings page.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-01 14:42:08 +08:00
CharisandJoshen Lim d153bab849 refactor(studio): extract SQL editor session store from god store (#47349)
## What

PR 6 of the SQL editor state re-layering stack. Moves ephemeral,
never-persisted SQL editor state out of the snippet/folder "god store".

**Session store** — `state/sql-editor/sql-editor-session-state.ts` holds
per-snippet, read-by-many session state:
- query `results`
- `explainResults`
- the row `limit`

…with their mutators (`addResult`/`addResultError`/`resetResult`,
`addExplainResult`/`addExplainResultError`/`resetExplainResult`,
`resetResults`, `setLimit`). `removeSnippet` drops a snippet's session
entries via `clearForSnippet(id)`.

**Diff-request slice** — `state/sql-editor/sql-editor-diff-request.ts`.
The Assistant's "Insert code" / "Replace code" diff is *not* per-snippet
session state: it's a transient, fire-and-forget command produced
outside the editor (e.g. query blocks / assistant) and consumed exactly
once by whichever editor is active. It's modeled as a consume-once
request (`requestDiff` / `consumeDiffRequest`) rather than durable state
— the editor drains it on apply, so a stale diff can't leak into a later
editor or session. (Previously this was `diffContent` in the god store:
never cleared and triggered by object-reference identity.)

Consumers read session state from `useSqlEditorSessionSnapshot` and the
diff channel from `useSqlEditorDiffRequestSnapshot`, keeping
`useSqlEditorV2StateSnapshot` only for snippets/folders.

### Why not the TanStack Query cache for results/explain?

Editor execution is a **mutation**, not a keyed query — `mutation.data`
is per-hook-instance and not keyed by snippet id, and there's no caching
value to capture (re-running SQL must return *fresh* data, never a
cached result). `EXPLAIN ANALYZE` actually executes the statement, so a
declarative/auto-refetching `useQuery` is semantically wrong.
Results/explain are imperative mutation outputs, scoped to the session,
read by several decoupled consumers keyed by snippet id — exactly what a
small in-memory keyed store models honestly.

## Consumers migrated

- `SQLEditor.tsx` — results/explain/limit reads +
`addResult`/`addResultError`/`addExplainResult`/`addExplainResultError`/`setLimit`;
diff-apply effect now drains a consume-once request
- `UtilityPanel.tsx`, `UtilityTabResults.tsx`, `UtilityTabExplain.tsx`,
`UtilityActions.tsx`
- `QueryBlock/EditQueryButton.tsx` — produces via `requestDiff`

## Notes

- Result/explain types are kept verbatim from the god store
(pre-existing `any` row/error types come along unchanged; tightening
them is out of scope for this move).
- `ref()` on result rows is preserved to avoid Valtio proxying large row
sets.

## Tests

- `sql-editor-session-state.test.ts` — result/explain mutators,
`resetResults`, `clearForSnippet`, `limit`
- `sql-editor-diff-request.test.ts` — `requestDiff`,
`consumeDiffRequest` (drain + queue-of-one)

Validation:
- `pnpm --filter studio typecheck` ✅
- `pnpm exec vitest --run state/sql-editor/` ✅ (110 passed)
- lint ✅ (no new errors)

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

* **New Features**
* SQL editor query results, EXPLAIN output, and the “Limit results to”
setting now persist more reliably across a session.
* AI-assisted SQL insert/replace actions now use a pending diff workflow
to apply updates more consistently.

* **Bug Fixes**
* Results/EXPLAIN rendering and downloads stay in sync with the latest
executed data.
* Switching databases/snippets now clears the correct temporary results.
* Diff application is more resilient when an editor is still loading,
including empty-vs-non-empty editor cases.

* **Tests**
  * Added coverage for the session and diff-request state logic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-06-30 11:24:48 -04:00
Chris Chinchilla 16ce2c1a8a Studio: Add quickstarts instruments example to dashboard examples (#47402)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

Adds a new SQL example to the SQL editor to make following quickstarts
easier.

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

## Summary by CodeRabbit

* **New Features**
  * Added a new SQL quickstart template called **“Instruments”**.
* The template helps users create a sample `instruments` table, add
example rows, and set up read access with row-level security.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-30 12:26:09 +02:00