feat: add unified Settings sheet, MCP indicator, and Docker host config

- Add AppSettingsSheet (gear icon in Toolbar) with MCP, Docker, and AI sections
- MCP Server: toggle on/off, port config, status badge, endpoint URL with copy
- Docker: local/remote daemon selector with remote URL input
- AI: moved Ollama settings into the unified sheet
- MCP status probes actual TCP port for reliable running detection
- Docker commands respect configurable docker host (-H flag) for remote daemons
- MCP server supports graceful shutdown via tokio watch channel
- Settings persisted to app_settings.json alongside existing config files
- StatusBar shows MCP indicator (green/gray dot) with tooltip

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 09:04:12 +03:00
parent 20b00e55b0
commit e76a96deb8
14 changed files with 800 additions and 42 deletions

View File

@@ -1,7 +1,9 @@
import { useAppStore } from "@/stores/app-store";
import { useConnections } from "@/hooks/use-connections";
import { useMcpStatus } from "@/hooks/use-settings";
import { Circle } from "lucide-react";
import { EnvironmentBadge } from "@/components/connections/EnvironmentBadge";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
function formatDbVersion(version: string): string {
const gpMatch = version.match(/Greenplum Database ([\d.]+)/i);
@@ -21,6 +23,7 @@ interface Props {
export function StatusBar({ rowCount, executionTime }: Props) {
const { activeConnectionId, connectedIds, readOnlyMap, pgVersion } = useAppStore();
const { data: connections } = useConnections();
const { data: mcpStatus } = useMcpStatus();
const activeConn = connections?.find((c) => c.id === activeConnectionId);
const isConnected = activeConnectionId
@@ -62,6 +65,25 @@ export function StatusBar({ rowCount, executionTime }: Props) {
<div className="flex items-center gap-3">
{rowCount != null && <span>{rowCount.toLocaleString()} rows</span>}
{executionTime != null && <span>{executionTime} ms</span>}
<Tooltip>
<TooltipTrigger asChild>
<span className="flex items-center gap-1 cursor-default">
<span
className={`inline-block h-1.5 w-1.5 rounded-full ${
mcpStatus?.running
? "bg-green-500"
: "bg-muted-foreground/30"
}`}
/>
<span>MCP</span>
</span>
</TooltipTrigger>
<TooltipContent side="top">
<p className="text-xs">
MCP Server {mcpStatus?.running ? `running on :${mcpStatus.port}` : "stopped"}
</p>
</TooltipContent>
</Tooltip>
</div>
</div>
);

View File

@@ -8,13 +8,15 @@ import { ReadOnlyToggle } from "@/components/layout/ReadOnlyToggle";
import { useAppStore } from "@/stores/app-store";
import { useConnections, useReconnect } from "@/hooks/use-connections";
import { toast } from "sonner";
import { Database, Plus, RefreshCw, Search } from "lucide-react";
import { Database, Plus, RefreshCw, Search, Settings } from "lucide-react";
import type { ConnectionConfig, Tab } from "@/types";
import { getEnvironment } from "@/lib/environment";
import { AppSettingsSheet } from "@/components/settings/AppSettingsSheet";
export function Toolbar() {
const [listOpen, setListOpen] = useState(false);
const [dialogOpen, setDialogOpen] = useState(false);
const [settingsOpen, setSettingsOpen] = useState(false);
const [editingConn, setEditingConn] = useState<ConnectionConfig | null>(null);
const { activeConnectionId, currentDatabase, addTab } = useAppStore();
const { data: connections } = useConnections();
@@ -116,6 +118,16 @@ export function Toolbar() {
</Button>
<div className="flex-1" />
<Button
variant="ghost"
size="sm"
className="h-7 w-7 p-0"
onClick={() => setSettingsOpen(true)}
title="Settings"
>
<Settings className="h-3.5 w-3.5" />
</Button>
</div>
<ConnectionList
@@ -136,6 +148,11 @@ export function Toolbar() {
onOpenChange={setDialogOpen}
connection={editingConn}
/>
<AppSettingsSheet
open={settingsOpen}
onOpenChange={setSettingsOpen}
/>
</>
);
}