diff --git a/frontend/src/components/tool/SqlEditor.tsx b/frontend/src/components/tool/SqlEditor.tsx index f2ed146..9819425 100644 --- a/frontend/src/components/tool/SqlEditor.tsx +++ b/frontend/src/components/tool/SqlEditor.tsx @@ -1,10 +1,14 @@ -import { useEffect, useRef } from 'react'; +import { useEffect, useRef, useImperativeHandle, forwardRef } from 'react'; import { EditorState, Prec } from '@codemirror/state'; import { EditorView, keymap, placeholder as placeholderExt } from '@codemirror/view'; import { sql } from '@codemirror/lang-sql'; import { defaultKeymap } from '@codemirror/commands'; import { basicSetup } from 'codemirror'; +export interface SqlEditorHandle { + getSelectedSql: () => string; +} + interface SqlEditorProps { value: string; onChange?: (value: string) => void; @@ -14,14 +18,14 @@ interface SqlEditorProps { placeholder?: string; } -export function SqlEditor({ +export const SqlEditor = forwardRef(function SqlEditor({ value, onChange, onRunShortcut, disabled = false, readOnly = false, placeholder = 'Enter SQL statement...', -}: SqlEditorProps) { +}, ref) { const containerRef = useRef(null); const viewRef = useRef(null); const onRunShortcutRef = useRef(onRunShortcut); @@ -33,6 +37,18 @@ export function SqlEditor({ disabledRef.current = disabled; }, [onRunShortcut, disabled]); + // Expose method to get selected SQL (or full content if no selection) + useImperativeHandle(ref, () => ({ + getSelectedSql: () => { + const view = viewRef.current; + if (!view) return ''; + const { from, to } = view.state.selection.main; + return from !== to + ? view.state.sliceDoc(from, to) + : view.state.doc.toString(); + }, + }), []); + useEffect(() => { if (!containerRef.current) return; @@ -130,4 +146,4 @@ export function SqlEditor({ className="border border-border rounded-lg bg-background overflow-hidden" /> ); -} +}); diff --git a/frontend/src/components/tool/index.ts b/frontend/src/components/tool/index.ts index 79c6aae..bfa625a 100644 --- a/frontend/src/components/tool/index.ts +++ b/frontend/src/components/tool/index.ts @@ -1,4 +1,5 @@ export { SqlEditor } from './SqlEditor'; +export type { SqlEditorHandle } from './SqlEditor'; export { ParameterForm } from './ParameterForm'; export { RunButton } from './RunButton'; export { ResultsTable } from './ResultsTable'; diff --git a/frontend/src/components/views/ToolDetailView.tsx b/frontend/src/components/views/ToolDetailView.tsx index 056faeb..77e1a10 100644 --- a/frontend/src/components/views/ToolDetailView.tsx +++ b/frontend/src/components/views/ToolDetailView.tsx @@ -1,10 +1,10 @@ -import { useEffect, useState, useCallback } from 'react'; +import { useEffect, useState, useCallback, useRef } from 'react'; import { useParams, Navigate, useSearchParams } from 'react-router-dom'; import { fetchSource } from '../../api/sources'; import { executeTool, type QueryResult } from '../../api/tools'; import { ApiError } from '../../api/errors'; import type { Tool } from '../../types/datasource'; -import { SqlEditor, ParameterForm, RunButton, ResultsTabs, type ResultTab } from '../tool'; +import { SqlEditor, ParameterForm, RunButton, ResultsTabs, type ResultTab, type SqlEditorHandle } from '../tool'; import LockIcon from '../icons/LockIcon'; import CopyIcon from '../icons/CopyIcon'; import CheckIcon from '../icons/CheckIcon'; @@ -16,6 +16,9 @@ export default function ToolDetailView() { const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); + // Ref to access SqlEditor's selection + const sqlEditorRef = useRef(null); + // Query state const [sql, setSql] = useState(() => { // Only for execute_sql tools - read from URL on mount @@ -210,8 +213,9 @@ export default function ToolDetailView() { let sqlToExecute: string; if (toolType === 'execute_sql') { - sqlToExecute = sql; - queryResult = await executeTool(toolName, { sql }); + // Get selected SQL from editor (returns selection if any, otherwise full content) + sqlToExecute = sqlEditorRef.current?.getSelectedSql() ?? sql; + queryResult = await executeTool(toolName, { sql: sqlToExecute }); } else { sqlToExecute = getSqlPreview(); queryResult = await executeTool(toolName, params); @@ -386,6 +390,7 @@ export default function ToolDetailView() {