@@ -31,9 +31,10 @@ import {
3131import { cn } from "@/lib/utils"
3232import { namespacesApi } from "@/api/catalog/namespaces"
3333import { tablesApi } from "@/api/catalog/tables"
34+ import { viewsApi } from "@/api/catalog/views"
3435import type { Catalog } from "@/types/api"
3536
36- export type TreeNodeType = "catalog" | "namespace" | "table"
37+ export type TreeNodeType = "catalog" | "namespace" | "table" | "view"
3738
3839export interface TreeNode {
3940 type : TreeNodeType
@@ -52,6 +53,7 @@ interface CatalogTreeNodeProps {
5253 onToggleExpand : ( nodeId : string ) => void
5354 onSelectNode ?: ( node : TreeNode ) => void
5455 onTableClick ?: ( catalogName : string , namespace : string [ ] , tableName : string ) => void
56+ onViewClick ?: ( catalogName : string , namespace : string [ ] , viewName : string ) => void
5557}
5658
5759export function CatalogTreeNode ( {
@@ -62,6 +64,7 @@ export function CatalogTreeNode({
6264 onToggleExpand,
6365 onSelectNode,
6466 onTableClick,
67+ onViewClick,
6568} : CatalogTreeNodeProps ) {
6669 const isExpanded = expandedNodes . has ( node . id )
6770 const isSelected = selectedNodeId === node . id
@@ -121,6 +124,22 @@ export function CatalogTreeNode({
121124 currentNamespacePath . length > 0 ,
122125 } )
123126
127+ // Fetch views when namespace is expanded
128+ const viewsQuery = useQuery ( {
129+ queryKey : [
130+ "views" ,
131+ node . catalogName || "" ,
132+ currentNamespacePath . join ( "." ) || "" ,
133+ ] ,
134+ queryFn : ( ) =>
135+ viewsApi . list ( node . catalogName || "" , currentNamespacePath ) ,
136+ enabled :
137+ node . type === "namespace" &&
138+ isExpanded &&
139+ ! ! node . catalogName &&
140+ currentNamespacePath . length > 0 ,
141+ } )
142+
124143 // Fetch generic tables when namespace is expanded
125144 const genericTablesQuery = useQuery ( {
126145 queryKey : [
@@ -152,6 +171,12 @@ export function CatalogTreeNode({
152171 onTableClick ?.( node . catalogName , node . namespace , node . name )
153172 }
154173 onSelectNode ?.( node )
174+ } else if ( node . type === "view" ) {
175+ // Open view details when clicking a view
176+ if ( node . catalogName && node . namespace && node . namespace . length > 0 ) {
177+ onViewClick ?.( node . catalogName , node . namespace , node . name )
178+ }
179+ onSelectNode ?.( node )
155180 }
156181 }
157182
@@ -261,6 +286,21 @@ export function CatalogTreeNode({
261286 parent : node ,
262287 } )
263288 } )
289+
290+ // Add views under namespace
291+ // Views API returns identifiers like [{namespace: ["accounting"], name: "sales_view"}]
292+ const views = viewsQuery . data || [ ]
293+ views . forEach ( ( view ) => {
294+ const namespaceId = `${ node . id } .view.${ view . name } `
295+ children . push ( {
296+ type : "view" ,
297+ id : namespaceId ,
298+ name : view . name ,
299+ namespace : currentNamespacePath , // Full namespace path where view resides
300+ catalogName : node . catalogName ,
301+ parent : node ,
302+ } )
303+ } )
264304 }
265305
266306 return children
@@ -269,14 +309,15 @@ export function CatalogTreeNode({
269309 namespacesQuery . data ,
270310 childNamespacesQuery . data ,
271311 tablesQuery . data ,
312+ viewsQuery . data ,
272313 genericTablesQuery . data ,
273314 currentNamespacePath ,
274315 ] )
275316
276317 const isLoading =
277318 ( node . type === "catalog" && namespacesQuery . isLoading ) ||
278319 ( node . type === "namespace" &&
279- ( childNamespacesQuery . isLoading || tablesQuery . isLoading || genericTablesQuery . isLoading ) )
320+ ( childNamespacesQuery . isLoading || tablesQuery . isLoading || viewsQuery . isLoading || genericTablesQuery . isLoading ) )
280321
281322 const Icon = useMemo ( ( ) => {
282323 if ( node . type === "catalog" ) return Database
@@ -327,11 +368,12 @@ export function CatalogTreeNode({
327368 onToggleExpand = { onToggleExpand }
328369 onSelectNode = { onSelectNode }
329370 onTableClick = { onTableClick }
371+ onViewClick = { onViewClick }
330372 />
331373 ) ) }
332- { ! isLoading && childNodes . length === 0 && node . type !== "table" && (
374+ { ! isLoading && childNodes . length === 0 && node . type !== "table" && node . type !== "view" && (
333375 < div className = "px-2 py-1 text-xs text-muted-foreground italic" >
334- No { node . type === "catalog" ? "namespaces" : "tables " } found
376+ No { node . type === "catalog" ? "namespaces" : "items " } found
335377 </ div >
336378 ) }
337379 </ div >
0 commit comments