diff --git a/src/components/grid/DataGrid.vue b/src/components/grid/DataGrid.vue index ff03c25362..a3ef36fdde 100644 --- a/src/components/grid/DataGrid.vue +++ b/src/components/grid/DataGrid.vue @@ -63,7 +63,7 @@ import { type CellPosition, type CellSelectionRange, } from "@/lib/gridSelection"; -import { buildTableSelectSql, normalizeWhereInput, quoteTableIdentifier } from "@/lib/tableSelectSql"; +import { quoteTableIdentifier } from "@/lib/tableSelectSql"; import { buildDataGridSaveStatements, formatGridSqlLiteral } from "@/lib/dataGridSql"; import { formatMarkdownTable } from "@/lib/markdownTable"; import { @@ -97,8 +97,8 @@ const props = defineProps<{ const emit = defineEmits<{ reload: []; - paginate: [offset: number, limit: number, whereInput?: string, orderBy?: string]; - sort: [column: string, direction: "asc" | "desc" | null, whereInput?: string]; + paginate: [offset: number, limit: number, orderBy?: string]; + sort: [column: string, direction: "asc" | "desc" | null]; }>(); const hasData = computed(() => props.result.columns.length > 0); @@ -205,154 +205,14 @@ const showTranspose = ref(false); const sortCol = ref(null); const sortDir = ref<"asc" | "desc">("asc"); const searchText = ref(""); -const searchSuggestions = ref([]); -const suggestionIndex = ref(-1); -const searchInputRef = ref(); -const measureRef = ref(); -const suggestionLeft = ref(0); - -function updateSuggestionPosition() { - nextTick(() => { - const input = searchInputRef.value; - const measure = measureRef.value; - if (!input || !measure) return; - const cursorPos = input.selectionStart ?? 0; - measure.textContent = searchText.value.slice(0, cursorPos); - suggestionLeft.value = measure.getBoundingClientRect().width; - }); -} - -watch(searchText, (val) => { - searchSuggestions.value = []; - if (!canUseWhereSearch.value || !props.tableMeta?.columns?.length) return; - - const trimmed = val.trimStart(); - const lower = trimmed.toLowerCase(); - - if (trimmed.length > 0 && lower !== "where" && "where".startsWith(lower)) { - searchSuggestions.value = ["WHERE "]; - suggestionIndex.value = 0; - updateSuggestionPosition(); - return; - } - - const m = val.match(/^\s*where\s+(.+)$/i); - if (m) { - const lastToken = m[1].split(/[\s,()><=!]+/).pop() || ""; - if (lastToken.length > 0) { - const tl = lastToken.toLowerCase(); - searchSuggestions.value = props.tableMeta.columns - .map((c) => c.name) - .filter((n) => n.toLowerCase().startsWith(tl) && n.toLowerCase() !== tl) - .slice(0, 8); - suggestionIndex.value = 0; - updateSuggestionPosition(); - } - } -}); - -function acceptSuggestion() { - const idx = suggestionIndex.value; - if (idx < 0 || idx >= searchSuggestions.value.length) return; - const sug = searchSuggestions.value[idx]; - - if (sug === "WHERE ") { - const trimmed = searchText.value.trimStart(); - const leading = searchText.value.slice(0, searchText.value.length - trimmed.length); - searchText.value = leading + "WHERE "; - } else { - const lastWordMatch = searchText.value.match(/([^\s,()><=!]+)$/); - if (lastWordMatch) { - const lastWord = lastWordMatch[1]; - const prefix = searchText.value.slice(0, -lastWord.length); - searchText.value = prefix + sug; - } - } - searchSuggestions.value = []; - suggestionIndex.value = -1; - searchInputRef.value?.focus(); -} - -function dismissSuggestions() { - searchSuggestions.value = []; - suggestionIndex.value = -1; -} - -function navigateSuggestion(delta: number) { - if (searchSuggestions.value.length === 0) return; - suggestionIndex.value = Math.min(Math.max(suggestionIndex.value + delta, 0), searchSuggestions.value.length - 1); -} - -const PAIRS: Record = { "'": "'", '"': '"', "(": ")" }; function onSearchKeydown(e: KeyboardEvent) { - if (e.key in PAIRS && !e.ctrlKey && !e.metaKey) { - const input = e.target as HTMLInputElement; - const start = input.selectionStart ?? 0; - const end = input.selectionEnd ?? 0; - const close = PAIRS[e.key]; - - if (start !== end) { - // Wrap selection: 'text' → 'text' - e.preventDefault(); - const selected = searchText.value.slice(start, end); - searchText.value = searchText.value.slice(0, start) + e.key + selected + close + searchText.value.slice(end); - nextTick(() => { - input.setSelectionRange(start + 1 + selected.length, start + 1 + selected.length); - }); - suggestionIndex.value = -1; - return; - } - - if (searchText.value[start] === close) { - // Cursor before closing char → skip over it - e.preventDefault(); - input.setSelectionRange(start + 1, start + 1); - return; - } - - e.preventDefault(); - searchText.value = searchText.value.slice(0, start) + e.key + close + searchText.value.slice(end); - nextTick(() => { - input.setSelectionRange(start + 1, start + 1); - }); - suggestionIndex.value = -1; - return; - } - - if (searchSuggestions.value.length > 0) { - if (e.key === "Tab") { - e.preventDefault(); - acceptSuggestion(); - return; - } - if (e.key === "Escape") { - e.preventDefault(); - dismissSuggestions(); - return; - } - if (e.key === "ArrowDown") { - e.preventDefault(); - navigateSuggestion(1); - return; - } - if (e.key === "ArrowUp") { - e.preventDefault(); - navigateSuggestion(-1); - return; - } - } - if (e.key === "Enter") { - onSearchEnter(e); - return; - } if (e.key === "Escape") { searchText.value = ""; } } const saveError = ref(""); -const isApplyingWhere = ref(false); const rowStatusFilter = ref("all"); const columnWidths = ref([]); const gridRef = ref(); @@ -423,11 +283,7 @@ watch(() => props.result.columns.length, initColumnWidths); const pageSize = ref(100); const currentPage = ref(1); const isFullPage = computed(() => props.result.rows.length >= pageSize.value); -const canUseWhereSearch = computed(() => !!props.tableMeta && !!props.onExecuteSql); -const isWhereSearch = computed(() => canUseWhereSearch.value && /^\s*where\b/i.test(searchText.value)); -const wherePredicate = computed(() => normalizeWhereInput(searchText.value)); -const activeWhereInput = computed(() => (isWhereSearch.value && wherePredicate.value ? searchText.value : undefined)); -const clientSearchText = computed(() => (isWhereSearch.value ? "" : searchText.value)); +const clientSearchText = computed(() => searchText.value); function currentOrderBy(): string | undefined { return sortCol.value ? `${quoteIdent(sortCol.value)} ${sortDir.value.toUpperCase()}` : undefined; @@ -436,17 +292,17 @@ function currentOrderBy(): string | undefined { function prevPage() { if (currentPage.value <= 1) return; currentPage.value--; - emit("paginate", (currentPage.value - 1) * pageSize.value, pageSize.value, activeWhereInput.value, currentOrderBy()); + emit("paginate", (currentPage.value - 1) * pageSize.value, pageSize.value, currentOrderBy()); } function nextPage() { if (!isFullPage.value) return; currentPage.value++; - emit("paginate", (currentPage.value - 1) * pageSize.value, pageSize.value, activeWhereInput.value, currentOrderBy()); + emit("paginate", (currentPage.value - 1) * pageSize.value, pageSize.value, currentOrderBy()); } function changePageSize(size: number) { pageSize.value = size; currentPage.value = 1; - emit("paginate", 0, size, activeWhereInput.value, currentOrderBy()); + emit("paginate", 0, size, currentOrderBy()); } // --- Editing --- @@ -604,45 +460,16 @@ function toggleSort(colName: string) { if (sortCol.value === colName) { if (sortDir.value === "asc") { sortDir.value = "desc"; - emit("sort", colName, "desc", activeWhereInput.value); + emit("sort", colName, "desc"); } else { sortCol.value = null; sortDir.value = "asc"; - emit("sort", colName, null, activeWhereInput.value); + emit("sort", colName, null); } } else { sortCol.value = colName; sortDir.value = "asc"; - emit("sort", colName, "asc", activeWhereInput.value); - } -} - -function onSearchEnter(event: KeyboardEvent) { - if (!isWhereSearch.value) return; - event.preventDefault(); - void applyWhereSearch(); -} - -async function applyWhereSearch() { - if (!props.tableMeta || !props.onExecuteSql || !wherePredicate.value) return; - isApplyingWhere.value = true; - saveError.value = ""; - currentPage.value = 1; - try { - const sql = buildTableSelectSql({ - databaseType: props.databaseType, - schema: props.tableMeta.schema, - tableName: props.tableMeta.tableName, - primaryKeys: props.tableMeta.primaryKeys, - orderBy: sortCol.value ? `${quoteIdent(sortCol.value)} ${sortDir.value.toUpperCase()}` : undefined, - limit: pageSize.value, - whereInput: searchText.value, - }); - await props.onExecuteSql(sql); - } catch (e: any) { - saveError.value = String(e?.message || e); - } finally { - isApplyingWhere.value = false; + emit("sort", colName, "asc"); } } @@ -1318,45 +1145,17 @@ function escapeAndHighlightKeywords(s: string): string { -
+
-