feat: add per-connection read-only mode

Connections default to read-only. SQL editor wraps queries in a
read-only transaction so PostgreSQL rejects mutations. Data mutation
commands (update_row, insert_row, delete_rows) are blocked at the
Rust layer. Toolbar toggle with confirmation dialog lets users
switch to read-write. Badges shown in workspace, table viewer, and
status bar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-11 19:36:19 +03:00
parent 9b9d2cee94
commit 72c362dfae
14 changed files with 224 additions and 9 deletions

View File

@@ -7,8 +7,9 @@ import {
import { SqlEditor } from "@/components/editor/SqlEditor";
import { ResultsPanel } from "@/components/results/ResultsPanel";
import { useQueryExecution } from "@/hooks/use-query-execution";
import { useAppStore } from "@/stores/app-store";
import { Button } from "@/components/ui/button";
import { Play, Loader2 } from "lucide-react";
import { Play, Loader2, Lock } from "lucide-react";
import type { QueryResult } from "@/types";
interface Props {
@@ -24,6 +25,9 @@ export function WorkspacePanel({
onSqlChange,
onResult,
}: Props) {
const readOnlyMap = useAppStore((s) => s.readOnlyMap);
const isReadOnly = readOnlyMap[connectionId] ?? true;
const [sqlValue, setSqlValue] = useState(initialSql);
const [result, setResult] = useState<QueryResult | null>(null);
const [error, setError] = useState<string | null>(null);
@@ -79,6 +83,12 @@ export function WorkspacePanel({
<span className="text-[11px] text-muted-foreground">
Ctrl+Enter to execute
</span>
{isReadOnly && (
<span className="flex items-center gap-1 rounded bg-yellow-500/10 px-1.5 py-0.5 text-[10px] font-semibold text-yellow-600 dark:text-yellow-500">
<Lock className="h-3 w-3" />
Read-Only
</span>
)}
</div>
<div className="flex-1 overflow-hidden">
<SqlEditor