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 (
case "query": <>
return ( {tabs.map((tab) => {
<WorkspacePanel const isActive = tab.id === activeTabId;
key={activeTab.id} let content: React.ReactNode;
connectionId={activeTab.connectionId}
initialSql={activeTab.sql} switch (tab.type) {
onSqlChange={(sql) => updateTab(activeTab.id, { sql })} case "query":
/> content = (
); <WorkspacePanel
case "table": connectionId={tab.connectionId}
return ( initialSql={tab.sql}
<TableDataView onSqlChange={(sql) => updateTab(tab.id, { sql })}
key={activeTab.id} />
connectionId={activeTab.connectionId} );
schema={activeTab.schema!} break;
table={activeTab.table!} case "table":
/> content = (
); <TableDataView
case "structure": connectionId={tab.connectionId}
return ( schema={tab.schema!}
<TableStructure table={tab.table!}
key={activeTab.id} />
connectionId={activeTab.connectionId} );
schema={activeTab.schema!} break;
table={activeTab.table!} case "structure":
/> content = (
); <TableStructure
case "roles": connectionId={tab.connectionId}
return ( schema={tab.schema!}
<RoleManagerView table={tab.table!}
key={activeTab.id} />
connectionId={activeTab.connectionId} );
/> break;
); case "roles":
case "sessions": content = (
return ( <RoleManagerView
<SessionsView connectionId={tab.connectionId}
key={activeTab.id} />
connectionId={activeTab.connectionId} );
/> break;
); case "sessions":
case "lookup": content = (
return ( <SessionsView
<EntityLookupPanel connectionId={tab.connectionId}
key={activeTab.id} />
connectionId={activeTab.connectionId} );
/> break;
); case "lookup":
default: content = (
return null; <EntityLookupPanel
} connectionId={tab.connectionId}
/>
);
break;
default:
content = null;
}
return (
<div
key={tab.id}
className="h-full"
style={{ display: isActive ? undefined : "none" }}
>
{content}
</div>
);
})}
</>
);
} }