fix: preserve tab state when switching between tabs

Render all tabs simultaneously with display:none for inactive ones,
instead of conditionally rendering only the active tab. This prevents
React from unmounting/remounting components on tab switch, preserving
query results, editor cursor, AI explanations, and other local state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 19:45:45 +03:00
parent a71afe8d5e
commit b44254bb29

View File

@@ -8,9 +8,8 @@ import { EntityLookupPanel } from "@/components/lookup/EntityLookupPanel";
export function TabContent() { export function TabContent() {
const { tabs, activeTabId, updateTab } = useAppStore(); const { tabs, activeTabId, updateTab } = useAppStore();
const activeTab = tabs.find((t) => t.id === activeTabId);
if (!activeTab) { if (tabs.length === 0) {
return ( return (
<div className="flex h-full items-center justify-center text-sm text-muted-foreground"> <div className="flex h-full items-center justify-center text-sm text-muted-foreground">
Open a query tab or select a table to get started. Open a query tab or select a table to get started.
@@ -18,56 +17,75 @@ export function TabContent() {
); );
} }
switch (activeTab.type) { return (
<>
{tabs.map((tab) => {
const isActive = tab.id === activeTabId;
let content: React.ReactNode;
switch (tab.type) {
case "query": case "query":
return ( content = (
<WorkspacePanel <WorkspacePanel
key={activeTab.id} connectionId={tab.connectionId}
connectionId={activeTab.connectionId} initialSql={tab.sql}
initialSql={activeTab.sql} onSqlChange={(sql) => updateTab(tab.id, { sql })}
onSqlChange={(sql) => updateTab(activeTab.id, { sql })}
/> />
); );
break;
case "table": case "table":
return ( content = (
<TableDataView <TableDataView
key={activeTab.id} connectionId={tab.connectionId}
connectionId={activeTab.connectionId} schema={tab.schema!}
schema={activeTab.schema!} table={tab.table!}
table={activeTab.table!}
/> />
); );
break;
case "structure": case "structure":
return ( content = (
<TableStructure <TableStructure
key={activeTab.id} connectionId={tab.connectionId}
connectionId={activeTab.connectionId} schema={tab.schema!}
schema={activeTab.schema!} table={tab.table!}
table={activeTab.table!}
/> />
); );
break;
case "roles": case "roles":
return ( content = (
<RoleManagerView <RoleManagerView
key={activeTab.id} connectionId={tab.connectionId}
connectionId={activeTab.connectionId}
/> />
); );
break;
case "sessions": case "sessions":
return ( content = (
<SessionsView <SessionsView
key={activeTab.id} connectionId={tab.connectionId}
connectionId={activeTab.connectionId}
/> />
); );
break;
case "lookup": case "lookup":
return ( content = (
<EntityLookupPanel <EntityLookupPanel
key={activeTab.id} connectionId={tab.connectionId}
connectionId={activeTab.connectionId}
/> />
); );
break;
default: default:
return null; content = null;
} }
return (
<div
key={tab.id}
className="h-full"
style={{ display: isActive ? undefined : "none" }}
>
{content}
</div>
);
})}
</>
);
} }