mirror of
https://github.com/supabase/supabase.git
synced 2026-10-09 19:35:06 +03:00
Mark provenance of SQL via the branded types SafeSqlFragment and UntrustedSqlFragment. Only SafeSqlFragment should be executed; UntrustedSqlFragments require some kind of implicit user approval (show on screen + user has to click something) before they are promoted to SafeSqlFragment. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Editor and RLS tester show loading states for inferred/generated SQL and include a dedicated user SQL editor for safer edits. * **Refactor** * Platform-wide SQL handling tightened: snippets and AI-generated SQL are treated as untrusted/display-only until promoted, improving safety and consistency. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
76 lines
2.0 KiB
TypeScript
76 lines
2.0 KiB
TypeScript
import { safeSql, type DisplayableSqlFragment } from '@supabase/pg-meta'
|
|
import { proxy, snapshot, useSnapshot } from 'valtio'
|
|
|
|
type Template = {
|
|
name: string
|
|
description: string
|
|
content: string
|
|
}
|
|
|
|
export type SqlError = {
|
|
error?: string
|
|
formattedError?: string
|
|
message?: string
|
|
}
|
|
|
|
type EditorPanelState = {
|
|
value: DisplayableSqlFragment
|
|
templates: Template[]
|
|
results: Record<string, unknown>[] | undefined
|
|
error: SqlError | undefined
|
|
initialPrompt: string
|
|
onChange: ((value: DisplayableSqlFragment) => void) | undefined
|
|
activeSnippetId: string | null
|
|
pendingReset: boolean
|
|
}
|
|
|
|
const initialState: EditorPanelState = {
|
|
value: safeSql``,
|
|
templates: [],
|
|
results: undefined,
|
|
error: undefined,
|
|
initialPrompt: '',
|
|
onChange: undefined,
|
|
activeSnippetId: null,
|
|
pendingReset: false,
|
|
}
|
|
|
|
export const editorPanelState = proxy({
|
|
...initialState,
|
|
setValue(value: DisplayableSqlFragment) {
|
|
editorPanelState.value = value
|
|
editorPanelState.onChange?.(value)
|
|
editorPanelState.setResults(undefined)
|
|
editorPanelState.setError(undefined)
|
|
},
|
|
setTemplates(templates: Template[]) {
|
|
editorPanelState.templates = templates
|
|
},
|
|
setResults(results: Record<string, unknown>[] | undefined) {
|
|
editorPanelState.results = results
|
|
},
|
|
setError(error: SqlError | undefined) {
|
|
editorPanelState.error = error
|
|
},
|
|
setInitialPrompt(initialPrompt: string) {
|
|
editorPanelState.initialPrompt = initialPrompt
|
|
},
|
|
setActiveSnippetId(id: string | null) {
|
|
editorPanelState.activeSnippetId = id
|
|
},
|
|
openAsNew() {
|
|
editorPanelState.value = safeSql``
|
|
editorPanelState.results = undefined
|
|
editorPanelState.error = undefined
|
|
editorPanelState.pendingReset = true
|
|
},
|
|
reset() {
|
|
Object.assign(editorPanelState, initialState)
|
|
},
|
|
})
|
|
|
|
export const getEditorPanelStateSnapshot = () => snapshot(editorPanelState)
|
|
|
|
export const useEditorPanelStateSnapshot = (options?: Parameters<typeof useSnapshot>[1]) =>
|
|
useSnapshot(editorPanelState, options)
|