This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris-tools.git
The following commit(s) were added to refs/heads/main by this push:
new a96fae3 Console: Make Generic Tables Show in the Catalog Explorer
(#113)
a96fae3 is described below
commit a96fae36fdde3d0432ba7c6c90d522caf6480618
Author: Adam Christian
<[email protected]>
AuthorDate: Mon Jan 5 09:32:25 2026 -0500
Console: Make Generic Tables Show in the Catalog Explorer (#113)
---
console/src/components/catalog/CatalogTreeNode.tsx | 33 +++++++-
.../src/components/catalog/TableDetailsDrawer.tsx | 88 +++++++++++++++++++++-
2 files changed, 116 insertions(+), 5 deletions(-)
diff --git a/console/src/components/catalog/CatalogTreeNode.tsx
b/console/src/components/catalog/CatalogTreeNode.tsx
index 78e0630..6682330 100644
--- a/console/src/components/catalog/CatalogTreeNode.tsx
+++ b/console/src/components/catalog/CatalogTreeNode.tsx
@@ -121,6 +121,22 @@ export function CatalogTreeNode({
currentNamespacePath.length > 0,
})
+ // Fetch generic tables when namespace is expanded
+ const genericTablesQuery = useQuery({
+ queryKey: [
+ "generic-tables",
+ node.catalogName || "",
+ currentNamespacePath.join(".") || "",
+ ],
+ queryFn: () =>
+ tablesApi.listGeneric(node.catalogName || "", currentNamespacePath),
+ enabled:
+ node.type === "namespace" &&
+ isExpanded &&
+ !!node.catalogName &&
+ currentNamespacePath.length > 0,
+ })
+
const handleClick = () => {
// Only toggle expand/collapse, don't navigate when clicking in tree
if (node.type === "catalog") {
@@ -231,6 +247,20 @@ export function CatalogTreeNode({
parent: node,
})
})
+
+ // Add generic tables under namespace
+ const genericTables = genericTablesQuery.data || []
+ genericTables.forEach((table) => {
+ const namespaceId = `${node.id}.table.${table.name}`
+ children.push({
+ type: "table",
+ id: namespaceId,
+ name: table.name,
+ namespace: currentNamespacePath, // Full namespace path where table
resides
+ catalogName: node.catalogName,
+ parent: node,
+ })
+ })
}
return children
@@ -239,13 +269,14 @@ export function CatalogTreeNode({
namespacesQuery.data,
childNamespacesQuery.data,
tablesQuery.data,
+ genericTablesQuery.data,
currentNamespacePath,
])
const isLoading =
(node.type === "catalog" && namespacesQuery.isLoading) ||
(node.type === "namespace" &&
- (childNamespacesQuery.isLoading || tablesQuery.isLoading))
+ (childNamespacesQuery.isLoading || tablesQuery.isLoading ||
genericTablesQuery.isLoading))
const Icon = useMemo(() => {
if (node.type === "catalog") return Database
diff --git a/console/src/components/catalog/TableDetailsDrawer.tsx
b/console/src/components/catalog/TableDetailsDrawer.tsx
index ab69235..10f56e4 100644
--- a/console/src/components/catalog/TableDetailsDrawer.tsx
+++ b/console/src/components/catalog/TableDetailsDrawer.tsx
@@ -47,12 +47,30 @@ export function TableDetailsDrawer({
}: TableDetailsDrawerProps) {
const tableQuery = useQuery({
queryKey: ["table", catalogName, namespace.join("."), tableName],
- queryFn: () => tablesApi.get(catalogName, namespace, tableName),
+ queryFn: async () => {
+ // Try to fetch as an Iceberg table first
+ try {
+ return await tablesApi.get(catalogName, namespace, tableName)
+ } catch (icebergError) {
+ // If that fails, try to fetch as a generic table
+ try {
+ return await tablesApi.getGeneric(catalogName, namespace, tableName)
+ } catch (genericError) {
+ // If both fail, throw the original Iceberg error
+ throw icebergError
+ }
+ }
+ },
enabled: open && !!catalogName && namespace.length > 0 && !!tableName,
})
const tableData = tableQuery.data
- const currentSchema = tableData?.metadata.schemas.find(
+
+ // Check if this is a generic table (has 'table' property) or Iceberg table
(has 'metadata' property)
+ const isGenericTable = tableData && 'table' in tableData
+ const genericTableData = isGenericTable ? (tableData as any).table : null
+
+ const currentSchema = !isGenericTable && tableData?.metadata?.schemas?.find(
(s) => s["schema-id"] === tableData.metadata["current-schema-id"]
)
@@ -90,9 +108,71 @@ export function TableDetailsDrawer({
</div>
)}
- {tableData && (
+ {tableData && isGenericTable && genericTableData && (
+ <div className="mt-6 space-y-6">
+ {/* Generic Table Info */}
+ <div>
+ <h3 className="text-sm font-semibold mb-2">Generic Table
Information</h3>
+ <div className="space-y-1 text-sm">
+ <div className="flex justify-between">
+ <span className="text-muted-foreground">Name:</span>
+ <span className="font-mono text-xs">
+ {genericTableData.name}
+ </span>
+ </div>
+ <div className="flex justify-between">
+ <span className="text-muted-foreground">Format:</span>
+ <span>{genericTableData.format}</span>
+ </div>
+ {genericTableData["base-location"] && (
+ <div className="flex justify-between">
+ <span className="text-muted-foreground">Base
Location:</span>
+ <span className="font-mono text-xs break-all">
+ {genericTableData["base-location"]}
+ </span>
+ </div>
+ )}
+ {genericTableData.doc && (
+ <div className="flex justify-between">
+ <span className="text-muted-foreground">Description:</span>
+ <span className="text-xs break-all">
+ {genericTableData.doc}
+ </span>
+ </div>
+ )}
+ </div>
+ </div>
+
+ {/* Properties */}
+ {genericTableData.properties &&
+ Object.keys(genericTableData.properties).length > 0 && (
+ <div>
+ <h3 className="text-sm font-semibold mb-2">Properties</h3>
+ <div className="border rounded-md">
+ <div className="divide-y">
+ {Object.entries(genericTableData.properties).map(
+ ([key, value]) => (
+ <div
+ key={key}
+ className="px-3 py-2 flex justify-between text-sm"
+ >
+ <span
className="text-muted-foreground">{key}:</span>
+ <span className="font-mono text-xs break-all">
+ {String(value)}
+ </span>
+ </div>
+ )
+ )}
+ </div>
+ </div>
+ </div>
+ )}
+ </div>
+ )}
+
+ {tableData && !isGenericTable && (
<div className="mt-6 space-y-6">
- {/* Table Info */}
+ {/* Iceberg Table Info */}
<div>
<h3 className="text-sm font-semibold mb-2">Table Information</h3>
<div className="space-y-1 text-sm">