mirror of
https://github.com/supabase/supabase.git
synced 2026-07-20 22:47:17 -04:00
9e80a159b5
## 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 -->
43 lines
1.6 KiB
TypeScript
43 lines
1.6 KiB
TypeScript
import { useCallback, useContext, useState } from 'react'
|
|
import { snapshot } from 'valtio'
|
|
|
|
import type { IStandaloneCodeEditor } from './SQLEditor.types'
|
|
import { useSQLEditorContext } from './SQLEditorContext'
|
|
import { createTabId, TabsStateContext } from '@/state/tabs'
|
|
|
|
/**
|
|
* Owns the editor `onMount` handler (scroll-position restore + tracking) and the
|
|
* mount counter that lets a diff request which arrived before the editor was
|
|
* ready re-run once it is.
|
|
*/
|
|
export function useEditorMount({ id }: { id: string }) {
|
|
const { scrollTopRef } = useSQLEditorContext()
|
|
// The proxy store (stable reference), read non-reactively in onMount so the
|
|
// callback identity doesn't churn on every tab-state change.
|
|
const tabsState = useContext(TabsStateContext)
|
|
|
|
// Bumped on every editor mount (including the keyed remount on snippet switch)
|
|
// so a diff request that arrived before the editor was ready gets re-processed.
|
|
const [editorMountCount, setEditorMountCount] = useState(0)
|
|
|
|
const onMount = useCallback(
|
|
(editor: IStandaloneCodeEditor) => {
|
|
setEditorMountCount((count) => count + 1)
|
|
|
|
const tabId = createTabId('sql', { id })
|
|
const tabData = snapshot(tabsState).tabsMap[tabId]
|
|
|
|
// [Joshen] Tiny timeout to give a bit of time for the content to load before scrolling
|
|
setTimeout(() => {
|
|
if (tabData?.metadata?.scrollTop) {
|
|
editor.setScrollTop(tabData.metadata.scrollTop)
|
|
}
|
|
}, 20)
|
|
editor.onDidScrollChange((e) => (scrollTopRef.current = e.scrollTop))
|
|
},
|
|
[id, scrollTopRef, tabsState]
|
|
)
|
|
|
|
return { onMount, editorMountCount }
|
|
}
|