@@ -2,6 +2,7 @@ import { BrowserRouter, Routes, Route, Navigate, useNavigate, useLocation, useSe
22import { useState , useEffect } from 'react' ;
33import { ObjectForm } from '@object-ui/plugin-form' ;
44import { Dialog , DialogContent , DialogHeader , DialogTitle , DialogDescription , Empty , EmptyTitle } from '@object-ui/components' ;
5+ import { toast } from 'sonner' ;
56import { SchemaRendererProvider } from '@object-ui/react' ;
67import { ObjectStackAdapter } from './dataSource' ;
78import type { ConnectionState } from './dataSource' ;
@@ -20,6 +21,8 @@ import { PageView } from './components/PageView';
2021import { ReportView } from './components/ReportView' ;
2122import { ExpressionProvider } from './context/ExpressionProvider' ;
2223import { ConditionalAuthWrapper } from './components/ConditionalAuthWrapper' ;
24+ import { KeyboardShortcutsDialog } from './components/KeyboardShortcutsDialog' ;
25+ import { useRecentItems } from './hooks/useRecentItems' ;
2326
2427// Auth Pages
2528import { LoginPage } from './pages/LoginPage' ;
@@ -35,6 +38,7 @@ import { ProfilePage } from './pages/system/ProfilePage';
3538
3639import { useParams } from 'react-router-dom' ;
3740import { ThemeProvider } from './components/theme-provider' ;
41+ import { ConsoleToaster } from './components/ConsoleToaster' ;
3842
3943export function AppContent ( ) {
4044 const [ dataSource , setDataSource ] = useState < ObjectStackAdapter | null > ( null ) ;
@@ -55,6 +59,7 @@ export function AppContent() {
5559 const [ isDialogOpen , setIsDialogOpen ] = useState ( false ) ;
5660 const [ editingRecord , setEditingRecord ] = useState < any > ( null ) ;
5761 const [ refreshKey , setRefreshKey ] = useState ( 0 ) ;
62+ const { addRecentItem } = useRecentItems ( ) ;
5863
5964 // Branding is now applied by AppShell via ConsoleLayout
6065
@@ -116,6 +121,37 @@ export function AppContent() {
116121
117122 const currentObjectDef = allObjects . find ( ( o : any ) => o . name === objectNameFromPath ) ;
118123
124+ // Track recent items on route change
125+ useEffect ( ( ) => {
126+ if ( ! activeApp ) return ;
127+ const basePath = `/apps/${ activeApp . name } ` ;
128+ if ( objectNameFromPath ) {
129+ const obj = allObjects . find ( ( o : any ) => o . name === objectNameFromPath ) ;
130+ if ( obj ) {
131+ addRecentItem ( {
132+ id : `object:${ obj . name } ` ,
133+ label : obj . label || obj . name ,
134+ href : `${ basePath } /${ obj . name } ` ,
135+ type : 'object' ,
136+ } ) ;
137+ }
138+ } else if ( cleanParts [ 2 ] === 'dashboard' && cleanParts [ 3 ] ) {
139+ addRecentItem ( {
140+ id : `dashboard:${ cleanParts [ 3 ] } ` ,
141+ label : cleanParts [ 3 ] . replace ( / [ - _ ] / g, ' ' ) . replace ( / \b \w / g, ( c : string ) => c . toUpperCase ( ) ) ,
142+ href : `${ basePath } /dashboard/${ cleanParts [ 3 ] } ` ,
143+ type : 'dashboard' ,
144+ } ) ;
145+ } else if ( cleanParts [ 2 ] === 'report' && cleanParts [ 3 ] ) {
146+ addRecentItem ( {
147+ id : `report:${ cleanParts [ 3 ] } ` ,
148+ label : cleanParts [ 3 ] . replace ( / [ - _ ] / g, ' ' ) . replace ( / \b \w / g, ( c : string ) => c . toUpperCase ( ) ) ,
149+ href : `${ basePath } /report/${ cleanParts [ 3 ] } ` ,
150+ type : 'report' ,
151+ } ) ;
152+ }
153+ } , [ location . pathname ] ) ; // eslint-disable-line react-hooks/exhaustive-deps
154+
119155 const handleEdit = ( record : any ) => {
120156 setEditingRecord ( record ) ;
121157 setIsDialogOpen ( true ) ;
@@ -166,6 +202,7 @@ export function AppContent() {
166202 objects = { allObjects }
167203 onAppChange = { handleAppChange }
168204 />
205+ < KeyboardShortcutsDialog />
169206 < SchemaRendererProvider dataSource = { dataSource || { } } >
170207 < ErrorBoundary >
171208 < Routes >
@@ -242,7 +279,15 @@ export function AppContent() {
242279 ? currentObjectDef . fields . map ( ( f : any ) => typeof f === 'string' ? f : f . name )
243280 : Object . keys ( currentObjectDef . fields ) )
244281 : [ ] ,
245- onSuccess : ( ) => { setIsDialogOpen ( false ) ; setRefreshKey ( k => k + 1 ) ; } ,
282+ onSuccess : ( ) => {
283+ setIsDialogOpen ( false ) ;
284+ setRefreshKey ( k => k + 1 ) ;
285+ toast . success (
286+ editingRecord
287+ ? `${ currentObjectDef ?. label } updated successfully`
288+ : `${ currentObjectDef ?. label } created successfully`
289+ ) ;
290+ } ,
246291 onCancel : ( ) => setIsDialogOpen ( false ) ,
247292 showSubmit : true ,
248293 showCancel : true ,
@@ -292,6 +337,7 @@ function RootRedirect() {
292337export function App ( ) {
293338 return (
294339 < ThemeProvider defaultTheme = "system" storageKey = "object-ui-theme" >
340+ < ConsoleToaster position = "bottom-right" />
295341 < ConditionalAuthWrapper authUrl = "/api/auth" >
296342 < BrowserRouter basename = "/" >
297343 < Routes >
0 commit comments