feat: add JSON view mode toggle for query results
Add a Table/JSON segmented toggle to both the query workspace and table data viewer, allowing users to switch between tabular and pretty-printed JSON display of results without exporting to a file. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useState, useCallback, useMemo } from "react";
|
||||
import { useTableData } from "@/hooks/use-table-data";
|
||||
import { ResultsTable } from "@/components/results/ResultsTable";
|
||||
import { ResultsJsonView } from "@/components/results/ResultsJsonView";
|
||||
import { PaginationControls } from "./PaginationControls";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
@@ -9,7 +10,7 @@ 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, Lock, Download, Plus } from "lucide-react";
|
||||
import { Save, RotateCcw, Filter, Loader2, Lock, Download, Plus, Table2, Braces } from "lucide-react";
|
||||
import { InsertRowDialog } from "./InsertRowDialog";
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -41,6 +42,7 @@ export function TableDataView({ connectionId, schema, table }: Props) {
|
||||
>(new Map());
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [insertDialogOpen, setInsertDialogOpen] = useState(false);
|
||||
const [viewMode, setViewMode] = useState<"table" | "json">("table");
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { data, isLoading, error } = useTableData({
|
||||
@@ -197,26 +199,54 @@ export function TableDataView({ connectionId, schema, table }: Props) {
|
||||
Apply
|
||||
</Button>
|
||||
{data && data.columns.length > 0 && (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-6 gap-1 text-xs"
|
||||
<>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-6 gap-1 text-xs"
|
||||
>
|
||||
<Download className="h-3 w-3" />
|
||||
Export
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem onClick={() => handleExport("csv")}>
|
||||
Export CSV
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => handleExport("json")}>
|
||||
Export JSON
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<div className="flex items-center rounded-md border text-xs">
|
||||
<button
|
||||
className={`flex items-center gap-1 px-2 py-0.5 font-medium ${
|
||||
viewMode === "table"
|
||||
? "bg-muted text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
}`}
|
||||
onClick={() => setViewMode("table")}
|
||||
title="Table view"
|
||||
>
|
||||
<Download className="h-3 w-3" />
|
||||
Export
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem onClick={() => handleExport("csv")}>
|
||||
Export CSV
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => handleExport("json")}>
|
||||
Export JSON
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Table2 className="h-3 w-3" />
|
||||
Table
|
||||
</button>
|
||||
<button
|
||||
className={`flex items-center gap-1 px-2 py-0.5 font-medium ${
|
||||
viewMode === "json"
|
||||
? "bg-muted text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
}`}
|
||||
onClick={() => setViewMode("json")}
|
||||
title="JSON view"
|
||||
>
|
||||
<Braces className="h-3 w-3" />
|
||||
JSON
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{!isReadOnly && (
|
||||
<Button
|
||||
@@ -269,18 +299,25 @@ export function TableDataView({ connectionId, schema, table }: Props) {
|
||||
{String(error)}
|
||||
</div>
|
||||
) : data ? (
|
||||
<ResultsTable
|
||||
columns={data.columns}
|
||||
types={data.types}
|
||||
rows={data.rows}
|
||||
onCellDoubleClick={handleCellDoubleClick}
|
||||
highlightedCells={highlightedCells}
|
||||
externalSort={{
|
||||
column: sortColumn,
|
||||
direction: sortDirection,
|
||||
onSort: handleSort,
|
||||
}}
|
||||
/>
|
||||
viewMode === "json" ? (
|
||||
<ResultsJsonView
|
||||
columns={data.columns}
|
||||
rows={data.rows}
|
||||
/>
|
||||
) : (
|
||||
<ResultsTable
|
||||
columns={data.columns}
|
||||
types={data.types}
|
||||
rows={data.rows}
|
||||
onCellDoubleClick={handleCellDoubleClick}
|
||||
highlightedCells={highlightedCells}
|
||||
externalSort={{
|
||||
column: sortColumn,
|
||||
direction: sortDirection,
|
||||
onSort: handleSort,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user