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:
@@ -7,8 +7,9 @@ import { Input } from "@/components/ui/input";
|
||||
import { updateRow as updateRowApi } from "@/lib/tauri";
|
||||
import { getTableColumns } from "@/lib/tauri";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useAppStore } from "@/stores/app-store";
|
||||
import { toast } from "sonner";
|
||||
import { Save, RotateCcw, Filter, Loader2 } from "lucide-react";
|
||||
import { Save, RotateCcw, Filter, Loader2, Lock } from "lucide-react";
|
||||
|
||||
interface Props {
|
||||
connectionId: string;
|
||||
@@ -17,6 +18,9 @@ interface Props {
|
||||
}
|
||||
|
||||
export function TableDataView({ connectionId, schema, table }: Props) {
|
||||
const readOnlyMap = useAppStore((s) => s.readOnlyMap);
|
||||
const isReadOnly = readOnlyMap[connectionId] ?? true;
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(50);
|
||||
const [sortColumn, _setSortColumn] = useState<string | undefined>();
|
||||
@@ -57,6 +61,12 @@ export function TableDataView({ connectionId, schema, table }: Props) {
|
||||
|
||||
const handleCellDoubleClick = useCallback(
|
||||
(rowIndex: number, colIndex: number, value: unknown) => {
|
||||
if (isReadOnly) {
|
||||
toast.warning("Read-only mode is active", {
|
||||
description: "Switch to Read-Write mode to edit data.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const key = `${rowIndex}:${colIndex}`;
|
||||
const currentValue = pendingChanges.get(key)?.value ?? value;
|
||||
const newVal = prompt("Edit value (leave empty and click NULL for null):",
|
||||
@@ -69,7 +79,7 @@ export function TableDataView({ connectionId, schema, table }: Props) {
|
||||
});
|
||||
}
|
||||
},
|
||||
[pendingChanges]
|
||||
[pendingChanges, isReadOnly]
|
||||
);
|
||||
|
||||
const handleCommit = async () => {
|
||||
@@ -121,6 +131,12 @@ export function TableDataView({ connectionId, schema, table }: Props) {
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
<div className="flex items-center gap-2 border-b px-2 py-1">
|
||||
{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>
|
||||
)}
|
||||
<Filter className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<Input
|
||||
placeholder="WHERE clause (e.g. id > 10)"
|
||||
|
||||
Reference in New Issue
Block a user