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