Files
tusk/src/components/workspace/TabContent.tsx
A.Shakhmatov a3b05b0328 feat: add AI data validation, test data generator, index advisor, and snapshots
Four new killer features leveraging AI (Ollama) and PostgreSQL internals:

- Data Validation: describe quality rules in natural language, AI generates
  SQL to find violations, run with pass/fail results and sample violations
- Test Data Generator: right-click table to generate realistic FK-aware test
  data with AI, preview before inserting in a transaction
- Index Advisor: analyze pg_stat tables + AI recommendations for CREATE/DROP
  INDEX with one-click apply
- Data Snapshots: export selected tables to JSON (FK-ordered), restore from
  file with optional truncate in a transaction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:27:41 +03:00

125 lines
3.5 KiB
TypeScript

import { useAppStore } from "@/stores/app-store";
import { WorkspacePanel } from "./WorkspacePanel";
import { TableDataView } from "@/components/table-viewer/TableDataView";
import { TableStructure } from "@/components/table-viewer/TableStructure";
import { RoleManagerView } from "@/components/management/RoleManagerView";
import { SessionsView } from "@/components/management/SessionsView";
import { EntityLookupPanel } from "@/components/lookup/EntityLookupPanel";
import { ErdDiagram } from "@/components/erd/ErdDiagram";
import { ValidationPanel } from "@/components/validation/ValidationPanel";
import { IndexAdvisorPanel } from "@/components/index-advisor/IndexAdvisorPanel";
import { SnapshotPanel } from "@/components/snapshots/SnapshotPanel";
export function TabContent() {
const { tabs, activeTabId, updateTab } = useAppStore();
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.
</div>
);
}
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;
case "erd":
content = (
<ErdDiagram
connectionId={tab.connectionId}
schema={tab.schema!}
/>
);
break;
case "validation":
content = (
<ValidationPanel
connectionId={tab.connectionId}
/>
);
break;
case "index-advisor":
content = (
<IndexAdvisorPanel
connectionId={tab.connectionId}
/>
);
break;
case "snapshots":
content = (
<SnapshotPanel
connectionId={tab.connectionId}
/>
);
break;
default:
content = null;
}
return (
<div
key={tab.id}
className="h-full"
style={{ display: isActive ? undefined : "none" }}
>
{content}
</div>
);
})}
</>
);
}