mirror of
https://github.com/supabase/supabase.git
synced 2026-09-09 19:42:46 +08:00
## 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>
55 lines
1.6 KiB
TypeScript
55 lines
1.6 KiB
TypeScript
import { DiffEditor as BaseDiffEditor } from '@monaco-editor/react'
|
|
import type { editor as monacoEditor } from 'monaco-editor'
|
|
|
|
interface DiffViewerProps {
|
|
/** Original/left hand side content (optional) */
|
|
original?: string
|
|
/** Modified/right hand side content */
|
|
modified: string | undefined
|
|
/** Language identifier understood by Monaco */
|
|
language?: string
|
|
/** Height for the editor container */
|
|
height?: string | number
|
|
/** Diff Editor Options */
|
|
options?: monacoEditor.IStandaloneDiffEditorConstructionOptions
|
|
onMount?: (editor: monacoEditor.IStandaloneDiffEditor) => void
|
|
}
|
|
|
|
// Centralised set of options so all diff editors look the same
|
|
const DEFAULT_OPTIONS: monacoEditor.IStandaloneDiffEditorConstructionOptions = {
|
|
fontSize: 13,
|
|
minimap: { enabled: false },
|
|
wordWrap: 'on',
|
|
lineNumbers: 'on',
|
|
folding: false,
|
|
lineNumbersMinChars: 3,
|
|
scrollBeyondLastLine: false,
|
|
renderSideBySide: false,
|
|
renderGutterMenu: false,
|
|
padding: { top: 4 },
|
|
}
|
|
|
|
export const DiffEditor = ({
|
|
original = '',
|
|
modified = '',
|
|
language = 'pgsql',
|
|
height = '100%',
|
|
options,
|
|
onMount,
|
|
}: DiffViewerProps) => (
|
|
<BaseDiffEditor
|
|
// [Joshen] These ones are meant to solve a UI issue that seems to only be happening locally
|
|
// Happens when you use the inline assistant in the SQL Editor and accept the suggestion
|
|
// Error: TextModel got disposed before DiffEditorWidget model got reset
|
|
keepCurrentOriginalModel
|
|
keepCurrentModifiedModel
|
|
theme="supabase"
|
|
language={language}
|
|
height={height}
|
|
original={original}
|
|
modified={modified}
|
|
options={{ ...DEFAULT_OPTIONS, ...options }}
|
|
onMount={onMount}
|
|
/>
|
|
)
|