feat: add connection colors, query history, SQL autocomplete, and EXPLAIN visualizer
Add four developer/QA features: - Connection color coding: color picker in dialog, colored indicators across toolbar, tabs, status bar, and connection selectors - Query history: Rust backend with JSON file storage (500 entry cap), sidebar panel with search/clear, auto-recording from workspace - Schema-aware SQL autocomplete: backend fetches column metadata, CodeMirror receives schema namespace with public tables unprefixed - EXPLAIN ANALYZE visualizer: recursive tree view with cost-colored bars, expand/collapse nodes, buffers info, Results/Explain tab toggle Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,18 @@ import {
|
||||
import { useSaveConnection, useTestConnection } from "@/hooks/use-connections";
|
||||
import { toast } from "sonner";
|
||||
import type { ConnectionConfig } from "@/types";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { Loader2, X } from "lucide-react";
|
||||
|
||||
const CONNECTION_COLORS = [
|
||||
{ name: "Red", value: "#ef4444" },
|
||||
{ name: "Orange", value: "#f97316" },
|
||||
{ name: "Yellow", value: "#eab308" },
|
||||
{ name: "Green", value: "#22c55e" },
|
||||
{ name: "Cyan", value: "#06b6d4" },
|
||||
{ name: "Blue", value: "#3b82f6" },
|
||||
{ name: "Purple", value: "#a855f7" },
|
||||
{ name: "Pink", value: "#ec4899" },
|
||||
];
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
@@ -173,6 +184,37 @@ export function ConnectionDialog({ open, onOpenChange, connection }: Props) {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 items-center gap-3">
|
||||
<label className="text-right text-sm text-muted-foreground">
|
||||
Color
|
||||
</label>
|
||||
<div className="col-span-3 flex items-center gap-1.5">
|
||||
<button
|
||||
type="button"
|
||||
className={`flex h-6 w-6 items-center justify-center rounded-full border-2 ${
|
||||
!form.color ? "border-primary" : "border-transparent"
|
||||
} bg-muted`}
|
||||
onClick={() => setForm((f) => ({ ...f, color: undefined }))}
|
||||
title="No color"
|
||||
>
|
||||
<X className="h-3 w-3 text-muted-foreground" />
|
||||
</button>
|
||||
{CONNECTION_COLORS.map((c) => (
|
||||
<button
|
||||
key={c.value}
|
||||
type="button"
|
||||
className={`h-6 w-6 rounded-full border-2 ${
|
||||
form.color === c.value
|
||||
? "border-primary"
|
||||
: "border-transparent"
|
||||
}`}
|
||||
style={{ backgroundColor: c.value }}
|
||||
onClick={() => setForm((f) => ({ ...f, color: c.value }))}
|
||||
title={c.name}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
|
||||
@@ -91,7 +91,14 @@ export function ConnectionList({ open, onOpenChange, onEdit, onNew }: Props) {
|
||||
isActive ? "border-primary bg-accent" : ""
|
||||
}`}
|
||||
>
|
||||
<Database className="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
{conn.color ? (
|
||||
<span
|
||||
className="h-4 w-4 shrink-0 rounded-full"
|
||||
style={{ backgroundColor: conn.color }}
|
||||
/>
|
||||
) : (
|
||||
<Database className="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
)}
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="truncate text-sm font-medium">
|
||||
{conn.name}
|
||||
|
||||
@@ -21,18 +21,36 @@ export function ConnectionSelector() {
|
||||
);
|
||||
}
|
||||
|
||||
const activeConn = connectedList.find((c) => c.id === activeConnectionId);
|
||||
|
||||
return (
|
||||
<Select
|
||||
value={activeConnectionId ?? undefined}
|
||||
onValueChange={setActiveConnectionId}
|
||||
>
|
||||
<SelectTrigger className="h-7 w-[200px] text-xs">
|
||||
<SelectValue placeholder="Select connection" />
|
||||
<div className="flex items-center gap-1.5">
|
||||
{activeConn?.color && (
|
||||
<span
|
||||
className="h-2.5 w-2.5 shrink-0 rounded-full"
|
||||
style={{ backgroundColor: activeConn.color }}
|
||||
/>
|
||||
)}
|
||||
<SelectValue placeholder="Select connection" />
|
||||
</div>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{connectedList.map((conn) => (
|
||||
<SelectItem key={conn.id} value={conn.id}>
|
||||
{conn.name}
|
||||
<div className="flex items-center gap-1.5">
|
||||
{conn.color && (
|
||||
<span
|
||||
className="h-2.5 w-2.5 shrink-0 rounded-full"
|
||||
style={{ backgroundColor: conn.color }}
|
||||
/>
|
||||
)}
|
||||
{conn.name}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
Reference in New Issue
Block a user