@@ -18,7 +18,9 @@ import {
1818 SidebarMenuItem ,
1919 useSidebar ,
2020} from '@/components/ui/sidebar' ;
21- import { mockApps } from '@/lib/app-registry' ;
21+ import { useAppList } from '@/hooks/use-metadata' ;
22+ import { consoleApp , mockApps , toRegistryEntry } from '@/lib/app-registry' ;
23+ import type { AppRegistryEntry } from '@/lib/app-registry' ;
2224
2325interface AppSwitcherProps {
2426 /** "sidebar" = full sidebar header style, "topbar" = compact button for top bar */
@@ -29,29 +31,37 @@ function useAppSwitcherState() {
2931 const navigate = useNavigate ( ) ;
3032 const { pathname } = useLocation ( ) ;
3133 const [ query , setQuery ] = useState ( '' ) ;
34+ const { data : remoteApps } = useAppList ( ) ;
35+
36+ // Build the app list: Console (always) + remote apps converted to registry entries.
37+ // Falls back to mockApps when the server is unreachable (useAppList returns mockAppDefinitions).
38+ const apps : AppRegistryEntry [ ] = useMemo ( ( ) => {
39+ if ( ! remoteApps || remoteApps . length === 0 ) return mockApps ;
40+ return [ consoleApp , ...remoteApps . map ( toRegistryEntry ) ] ;
41+ } , [ remoteApps ] ) ;
3242
3343 const normalizedQuery = query . trim ( ) . toLowerCase ( ) ;
3444
3545 const activeApp = useMemo ( ( ) => {
3646 if ( pathname . startsWith ( '/apps/' ) ) {
3747 const [ , , appId ] = pathname . split ( '/' ) ;
38- return mockApps . find ( ( app ) => app . id === appId ) ;
48+ return apps . find ( ( app ) => app . id === appId ) ;
3949 }
4050 if ( pathname . startsWith ( '/settings' ) ) {
41- return mockApps . find ( ( app ) => app . id === 'console' ) ;
51+ return apps . find ( ( app ) => app . id === 'console' ) ;
4252 }
43- return mockApps . find ( ( app ) => app . id === 'console' ) ;
44- } , [ pathname ] ) ;
53+ return apps . find ( ( app ) => app . id === 'console' ) ;
54+ } , [ pathname , apps ] ) ;
4555
4656 const displayName = activeApp ?. name ?? 'Console' ;
4757
4858 const filteredApps = useMemo ( ( ) => {
49- if ( ! normalizedQuery ) return mockApps ;
50- return mockApps . filter ( ( app ) => {
59+ if ( ! normalizedQuery ) return apps ;
60+ return apps . filter ( ( app ) => {
5161 const haystack = `${ app . name } ${ app . description } ` . toLowerCase ( ) ;
5262 return haystack . includes ( normalizedQuery ) ;
5363 } ) ;
54- } , [ normalizedQuery ] ) ;
64+ } , [ normalizedQuery , apps ] ) ;
5565
5666 const pinnedApps = filteredApps . filter ( ( app ) => app . pinned ) ;
5767 const systemApps = filteredApps . filter (
@@ -87,7 +97,7 @@ function AppDropdownBody({
8797 customApps,
8898 filteredApps,
8999} : ReturnType < typeof useAppSwitcherState > ) {
90- const renderAppItem = ( app : ( typeof mockApps ) [ number ] ) => (
100+ const renderAppItem = ( app : AppRegistryEntry ) => (
91101 < DropdownMenuItem
92102 key = { app . id }
93103 className = "flex items-start gap-2"
0 commit comments