Files
tusk/src/components/ai/AiSettingsPopover.tsx
A.Shakhmatov d507162377 fix: harden security, reduce duplication, and improve robustness
- Fix SQL injection in data.rs by wrapping get_table_data in READ ONLY transaction
- Fix SQL injection in docker.rs CREATE DATABASE via escape_ident
- Fix command injection in docker.rs by validating pg_version/container_name
  and escaping shell-interpolated values
- Fix UTF-8 panic on stderr truncation with char_indices
- Wrap delete_rows in a transaction for atomicity
- Replace .expect() with proper error propagation in lib.rs
- Cache AI settings in AppState to avoid repeated disk reads
- Cap JSONB column discovery at 50 to prevent unbounded queries
- Fix ERD colorMode to respect system theme via useTheme()
- Extract AppState::get_pool() replacing ~19 inline pool patterns
- Extract shared AiSettingsFields component (DRY popover + sheet)
- Make get_connections_path pub(crate) and reuse from docker.rs
- Deduplicate check_docker by delegating to check_docker_internal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 11:41:14 +03:00

67 lines
1.9 KiB
TypeScript

import { useState } from "react";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Button } from "@/components/ui/button";
import { useAiSettings, useSaveAiSettings } from "@/hooks/use-ai";
import { Settings } from "lucide-react";
import { toast } from "sonner";
import { AiSettingsFields } from "./AiSettingsFields";
export function AiSettingsPopover() {
const { data: settings } = useAiSettings();
const saveMutation = useSaveAiSettings();
const [url, setUrl] = useState<string | null>(null);
const [model, setModel] = useState<string | null>(null);
const currentUrl = url ?? settings?.ollama_url ?? "http://localhost:11434";
const currentModel = model ?? settings?.model ?? "";
const handleSave = () => {
saveMutation.mutate(
{ provider: "ollama", ollama_url: currentUrl, model: currentModel },
{
onSuccess: () => toast.success("AI settings saved"),
onError: (err) =>
toast.error("Failed to save AI settings", {
description: String(err),
}),
}
);
};
return (
<Popover>
<PopoverTrigger asChild>
<Button
size="sm"
variant="ghost"
className="h-6 w-6 p-0"
title="AI Settings"
>
<Settings className="h-3 w-3" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-80" align="end">
<div className="flex flex-col gap-3">
<h4 className="text-sm font-medium">Ollama Settings</h4>
<AiSettingsFields
ollamaUrl={currentUrl}
onOllamaUrlChange={setUrl}
model={currentModel}
onModelChange={setModel}
/>
<Button size="sm" className="h-7 text-xs" onClick={handleSave}>
Save
</Button>
</div>
</PopoverContent>
</Popover>
);
}