mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
## Context Adds the inline AI completion functionality into Explorer QueryEditor, similar to what we've got for the existing SQL editor - Shifts the `ResizableAIWidget` and `InlineWidget` components out of the SQL Editor folder into `components/ui/AiEditor` to be used by both SQL Editor and Query Editor - Consolidates the "proposal" logic that was initially set up for the Clickhouse Migration functionality with this Inline AI stuff - Also added the prompt into the proposal header (Refer to the screenshots below) - SQL Editor didn't have this - but figured this is useful as context for the user <img width="935" height="352" alt="image" src="https://github.com/user-attachments/assets/3f71539a-dda1-4763-be08-a850bdc8aec6" /> Source selected: Database <img width="922" height="357" alt="image" src="https://github.com/user-attachments/assets/81e772e6-dcc9-440d-83db-49d0d487dd13" /> Source selected: Logs <img width="920" height="345" alt="image" src="https://github.com/user-attachments/assets/83f1dae3-cf62-4424-be42-b06e70cb366d" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added AI-assisted SQL generation with contextual prompts and OS-specific guidance. - Review generated SQL changes in a diff, then accept, reject, or cancel suggestions. - Added inline, resizable AI prompt controls with loading and submission states. - Added the Ctrl/Cmd+Shift+K shortcut to run AI SQL generation. - **Improvements** - Added options to disable query execution and run custom actions. - Renamed “Recent” to “Recently updated.” - Improved editor widget positioning and display behavior. - Added clearer error notifications when AI generation fails. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
88 lines
2.2 KiB
TypeScript
88 lines
2.2 KiB
TypeScript
import type { editor as monacoEditor } from 'monaco-editor'
|
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
|
|
import { AskAIWidget } from './AskAIWidget'
|
|
import { InlineWidget } from './InlineWidget'
|
|
|
|
interface ResizableAIWidgetProps {
|
|
editor: monacoEditor.IStandaloneCodeEditor | monacoEditor.IStandaloneDiffEditor
|
|
id: string
|
|
value: string
|
|
onChange: (value: string) => void
|
|
onSubmit: (prompt: string) => void
|
|
onAccept?: () => void
|
|
onReject?: () => void
|
|
onCancel?: () => void
|
|
isDiffVisible: boolean
|
|
isLoading?: boolean
|
|
startLineNumber: number
|
|
endLineNumber: number
|
|
}
|
|
|
|
const LINE_HEIGHT = 20 // height of each line in pixels
|
|
const MIN_LINES = 3 // minimum number of lines to show
|
|
|
|
export const ResizableAIWidget = ({
|
|
editor,
|
|
id,
|
|
value,
|
|
onChange,
|
|
onSubmit,
|
|
onAccept,
|
|
onReject,
|
|
onCancel,
|
|
isDiffVisible,
|
|
isLoading = false,
|
|
startLineNumber,
|
|
endLineNumber,
|
|
}: ResizableAIWidgetProps) => {
|
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
const [heightInLines, setHeightInLines] = useState(MIN_LINES)
|
|
|
|
const updateHeight = useCallback(() => {
|
|
if (containerRef.current) {
|
|
const height = containerRef.current.offsetHeight
|
|
const newHeightInLines = Math.max(MIN_LINES, Math.ceil(height / LINE_HEIGHT))
|
|
setHeightInLines(newHeightInLines)
|
|
}
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
// Update height on value change
|
|
updateHeight()
|
|
|
|
// Set up resize observer to track height changes
|
|
const resizeObserver = new ResizeObserver(updateHeight)
|
|
if (containerRef.current) {
|
|
resizeObserver.observe(containerRef.current)
|
|
}
|
|
|
|
return () => {
|
|
resizeObserver.disconnect()
|
|
}
|
|
}, [updateHeight])
|
|
|
|
return (
|
|
<InlineWidget
|
|
editor={editor}
|
|
id={id}
|
|
heightInLines={heightInLines}
|
|
afterLineNumber={endLineNumber}
|
|
beforeLineNumber={Math.max(0, startLineNumber - 1)}
|
|
>
|
|
<div ref={containerRef}>
|
|
<AskAIWidget
|
|
value={value}
|
|
onChange={onChange}
|
|
onSubmit={onSubmit}
|
|
onAccept={onAccept}
|
|
onReject={onReject}
|
|
onCancel={onCancel}
|
|
isDiffVisible={isDiffVisible}
|
|
isLoading={isLoading}
|
|
/>
|
|
</div>
|
|
</InlineWidget>
|
|
)
|
|
}
|