feat: add Greenplum 7 compatibility and AI SQL generation

Greenplum 7 (PG12-based) compatibility:
- Auto-detect GP via version() string, store DbFlavor per connection
- connect returns ConnectResult with version + flavor
- Fix pg_total_relation_size to use c.oid (universal, safer on both PG/GP)
- Branch is_identity column query for GP (lacks the column)
- Branch list_sessions wait_event fields for GP
- Exclude gp_toolkit schema in schema listing, completion, lookup, AI context
- Smart StatusBar version display: GP shows "GP 7.0.0 (PG 12.4)"
- Fix connection list spinner showing on all cards during connect

AI SQL generation (Ollama):
- Add AI settings, model selection, and generate_sql command
- Frontend AI panel with prompt input and SQL output

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 18:24:06 +03:00
parent d5cff8bd5e
commit e8d99c645b
27 changed files with 1276 additions and 113 deletions

View File

@@ -1,5 +1,5 @@
import { create } from "zustand";
import type { ConnectionConfig, Tab } from "@/types";
import type { ConnectionConfig, DbFlavor, Tab } from "@/types";
interface AppState {
connections: ConnectionConfig[];
@@ -7,6 +7,7 @@ interface AppState {
currentDatabase: string | null;
connectedIds: Set<string>;
readOnlyMap: Record<string, boolean>;
dbFlavors: Record<string, DbFlavor>;
tabs: Tab[];
activeTabId: string | null;
sidebarWidth: number;
@@ -18,6 +19,7 @@ interface AppState {
addConnectedId: (id: string) => void;
removeConnectedId: (id: string) => void;
setReadOnly: (connectionId: string, readOnly: boolean) => void;
setDbFlavor: (connectionId: string, flavor: DbFlavor) => void;
setPgVersion: (version: string | null) => void;
addTab: (tab: Tab) => void;
@@ -33,6 +35,7 @@ export const useAppStore = create<AppState>((set) => ({
currentDatabase: null,
connectedIds: new Set(),
readOnlyMap: {},
dbFlavors: {},
tabs: [],
activeTabId: null,
sidebarWidth: 260,
@@ -50,13 +53,22 @@ export const useAppStore = create<AppState>((set) => ({
set((state) => {
const next = new Set(state.connectedIds);
next.delete(id);
const { [id]: _, ...restRo } = state.readOnlyMap;
return { connectedIds: next, readOnlyMap: restRo };
const restRo = Object.fromEntries(
Object.entries(state.readOnlyMap).filter(([k]) => k !== id)
);
const restFlavors = Object.fromEntries(
Object.entries(state.dbFlavors).filter(([k]) => k !== id)
);
return { connectedIds: next, readOnlyMap: restRo, dbFlavors: restFlavors };
}),
setReadOnly: (connectionId, readOnly) =>
set((state) => ({
readOnlyMap: { ...state.readOnlyMap, [connectionId]: readOnly },
})),
setDbFlavor: (connectionId, flavor) =>
set((state) => ({
dbFlavors: { ...state.dbFlavors, [connectionId]: flavor },
})),
setPgVersion: (version) => set({ pgVersion: version }),
addTab: (tab) =>