@@ -21,9 +21,10 @@ import '@object-ui/plugin-grid';
2121import '@object-ui/plugin-kanban' ;
2222import '@object-ui/plugin-calendar' ;
2323import { Button , Empty , EmptyTitle , EmptyDescription , NavigationOverlay , DropdownMenu , DropdownMenuContent , DropdownMenuItem , DropdownMenuTrigger , DropdownMenuSeparator } from '@object-ui/components' ;
24- import { Plus , Table as TableIcon , Settings2 , Wrench , KanbanSquare , Calendar , LayoutGrid , Activity , GanttChart , MapPin , BarChart3 } from 'lucide-react' ;
24+ import { Plus , Table as TableIcon , Settings2 , Wrench , KanbanSquare , Calendar , LayoutGrid , Activity , GanttChart , MapPin , BarChart3 , ChevronRight } from 'lucide-react' ;
2525import type { ListViewSchema , ViewNavigationConfig } from '@object-ui/types' ;
2626import { MetadataToggle , MetadataPanel , useMetadataInspector } from './MetadataInspector' ;
27+ import { ViewConfigPanel } from './ViewConfigPanel' ;
2728import { useObjectActions } from '../hooks/useObjectActions' ;
2829import { useObjectTranslation } from '@object-ui/i18n' ;
2930import { usePermissions } from '@object-ui/permissions' ;
@@ -62,6 +63,12 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) {
6263 const { showDebug, toggleDebug } = useMetadataInspector ( ) ;
6364 const { t } = useObjectTranslation ( ) ;
6465
66+ // Inline view config panel state (Airtable-style right sidebar)
67+ const [ showViewConfigPanel , setShowViewConfigPanel ] = useState ( false ) ;
68+
69+ // Record count tracking for footer
70+ const [ recordCount , setRecordCount ] = useState < number | undefined > ( undefined ) ;
71+
6572 // Admin users automatically get design tools (no toggle needed)
6673 const { user } = useAuth ( ) ;
6774 const isAdmin = user ?. role === 'admin' ;
@@ -152,6 +159,23 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) {
152159 }
153160 } , [ realtimeMessage , hasConflicts , resolveAllConflicts ] ) ;
154161
162+ // Fetch record count for footer display
163+ useEffect ( ( ) => {
164+ if ( dataSource ?. find && objectDef . name ) {
165+ dataSource . find ( objectDef . name , { limit : 0 } ) . then ( ( result : any ) => {
166+ if ( typeof result ?. total === 'number' ) {
167+ setRecordCount ( result . total ) ;
168+ } else if ( Array . isArray ( result ?. data ) ) {
169+ setRecordCount ( result . data . length ) ;
170+ } else if ( Array . isArray ( result ) ) {
171+ setRecordCount ( result . length ) ;
172+ }
173+ } ) . catch ( ( ) => {
174+ // Silently ignore — record count is non-critical
175+ } ) ;
176+ }
177+ } , [ dataSource , objectDef . name , refreshKey ] ) ;
178+
155179 // Navigation overlay for record detail (supports drawer/modal/split/popover via config)
156180 const detailNavigation : ViewNavigationConfig = objectDef . navigation ?? { mode : 'drawer' } ;
157181 const drawerRecordId = searchParams . get ( 'recordId' ) ;
@@ -301,14 +325,23 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) {
301325
302326 return (
303327 < div className = "h-full flex flex-col bg-background" >
304- { /* 1. Simplified Header */ }
328+ { /* 1. Header with breadcrumb + description */ }
305329 < div className = "flex justify-between items-center py-2.5 sm:py-3 px-3 sm:px-4 border-b shrink-0 bg-background z-10" >
306330 < div className = "flex items-center gap-2 sm:gap-3 min-w-0 flex-1" >
307331 < div className = "bg-primary/10 p-1.5 sm:p-2 rounded-md shrink-0" >
308332 < TableIcon className = "h-4 w-4 text-primary" />
309333 </ div >
310334 < div className = "min-w-0" >
335+ { /* Breadcrumb: Object > View */ }
336+ < div className = "flex items-center gap-1 text-xs text-muted-foreground mb-0.5" >
337+ < span className = "truncate" > { objectDef . label } </ span >
338+ < ChevronRight className = "h-3 w-3 shrink-0" />
339+ < span className = "truncate font-medium text-foreground" > { activeView ?. label || t ( 'console.objectView.allRecords' ) } </ span >
340+ </ div >
311341 < h1 className = "text-base sm:text-lg font-semibold tracking-tight text-foreground truncate" > { objectDef . label } </ h1 >
342+ { objectDef . description && (
343+ < p className = "text-xs text-muted-foreground truncate hidden sm:block max-w-md" > { objectDef . description } </ p >
344+ ) }
312345 </ div >
313346 </ div >
314347
@@ -353,7 +386,7 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) {
353386 { t ( 'console.objectView.metadataInspector' ) }
354387 </ DropdownMenuItem >
355388 < DropdownMenuSeparator />
356- < DropdownMenuItem onClick = { ( ) => navigate ( viewId ? `../../views/ ${ viewId } ` : `views/ ${ activeViewId } ` , { relative : 'path' } ) } >
389+ < DropdownMenuItem onClick = { ( ) => setShowViewConfigPanel ( prev => ! prev ) } >
357390 < Settings2 className = "h-4 w-4 mr-2" />
358391 { t ( 'console.objectView.editView' ) }
359392 </ DropdownMenuItem >
@@ -415,8 +448,8 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) {
415448
416449 { /* 2. Content — Plugin ObjectView with ViewSwitcher + Filter + Sort */ }
417450 < div className = "flex-1 overflow-hidden relative flex flex-row" >
418- < div className = "flex-1 relative h-full" >
419- < div className = "absolute inset-0 overflow-auto p-3 sm:p-4" >
451+ < div className = "flex-1 relative h-full flex flex-col " >
452+ < div className = "flex-1 relative overflow-auto p-3 sm:p-4" >
420453 < PluginObjectView
421454 key = { refreshKey }
422455 schema = { objectViewSchema }
@@ -429,6 +462,12 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) {
429462 renderListView = { renderListView }
430463 />
431464 </ div >
465+ { /* Footer — Record count */ }
466+ { typeof recordCount === 'number' && (
467+ < div data-testid = "record-count-footer" className = "border-t px-3 sm:px-4 py-1.5 text-xs text-muted-foreground bg-muted/5 shrink-0" >
468+ { t ( 'console.objectView.recordCount' , { count : recordCount } ) }
469+ </ div >
470+ ) }
432471 </ div >
433472 { /* Metadata panel only shows for admin users */ }
434473 < MetadataPanel
@@ -438,6 +477,14 @@ export function ObjectView({ dataSource, objects, onEdit, onRowClick }: any) {
438477 { title : 'Object Definition' , data : objectDef } ,
439478 ] }
440479 />
480+ { /* Inline View Config Panel — Airtable-style right sidebar */ }
481+ < ViewConfigPanel
482+ open = { showViewConfigPanel && isAdmin }
483+ onClose = { ( ) => setShowViewConfigPanel ( false ) }
484+ activeView = { activeView }
485+ objectDef = { objectDef }
486+ recordCount = { recordCount }
487+ />
441488 </ div >
442489
443490 { /* Record Detail Overlay — navigation mode driven by objectDef.navigation */ }
0 commit comments