@@ -9,7 +9,7 @@ import { Toaster } from "@/components/ui/toaster"
99import { Card , CardContent , CardHeader , CardTitle , CardDescription } from "@/components/ui/card"
1010import { Database , Layers , Sparkles , Zap } from 'lucide-react' ;
1111import { getApiBaseUrl , config } from './lib/config' ;
12- import { appPackages , type AppPackage } from './mocks/browser' ;
12+ import type { AppPackage } from './mocks/browser' ;
1313
1414function DashboardWelcome ( ) {
1515 return (
@@ -119,13 +119,14 @@ function DashboardWelcome() {
119119
120120export default function App ( ) {
121121 const [ client , setClient ] = useState < ObjectStackClient | null > ( null ) ;
122+ const [ apps , setApps ] = useState < AppPackage [ ] > ( [ ] ) ;
123+ const [ selectedApp , setSelectedApp ] = useState < AppPackage | null > ( null ) ;
122124 const [ selectedObject , setSelectedObject ] = useState < string | null > ( null ) ;
123125 const [ editingRecord , setEditingRecord ] = useState < any > ( null ) ;
124126 const [ showForm , setShowForm ] = useState ( false ) ;
125- const [ selectedApp , setSelectedApp ] = useState < AppPackage > ( appPackages [ 0 ] ) ;
126127
128+ // 1. Create client
127129 useEffect ( ( ) => {
128- // Use the configured API base URL based on runtime mode (MSW or Server)
129130 const baseUrl = getApiBaseUrl ( ) ;
130131 console . log ( `[App] Connecting to API: ${ baseUrl } (mode: ${ config . mode } )` ) ;
131132
@@ -135,6 +136,32 @@ export default function App() {
135136 setClient ( newClient ) ;
136137 } , [ ] ) ;
137138
139+ // 2. Fetch app list from the server API (not hardcoded)
140+ useEffect ( ( ) => {
141+ if ( ! client ) return ;
142+ let mounted = true ;
143+
144+ async function loadApps ( ) {
145+ try {
146+ // Spec: GET /api/v1/meta/apps → GetMetaItemsResponse = { type: 'apps', items: AppSchema[] }
147+ const result : any = await client ! . meta . getItems ( 'apps' ) ;
148+ const items : AppPackage [ ] = result ?. items || result ?. value || ( Array . isArray ( result ) ? result : [ ] ) ;
149+
150+ console . log ( '[App] Fetched apps from API:' , items . map ( ( a : any ) => a . label || a . name ) ) ;
151+
152+ if ( mounted && items . length > 0 ) {
153+ setApps ( items ) ;
154+ setSelectedApp ( items [ 0 ] ) ;
155+ }
156+ } catch ( err ) {
157+ console . error ( '[App] Failed to fetch apps from API:' , err ) ;
158+ }
159+ }
160+
161+ loadApps ( ) ;
162+ return ( ) => { mounted = false ; } ;
163+ } , [ client ] ) ;
164+
138165 function handleEdit ( record : any ) {
139166 setEditingRecord ( record ) ;
140167 setShowForm ( true ) ;
@@ -167,12 +194,12 @@ export default function App() {
167194 client = { client }
168195 selectedObject = { selectedObject }
169196 onSelectObject = { ( name ) => setSelectedObject ( name || null ) }
170- apps = { appPackages }
197+ apps = { apps }
171198 selectedApp = { selectedApp }
172199 onSelectApp = { handleSelectApp }
173200 />
174201 < main className = "flex min-w-0 flex-1 flex-col bg-background" >
175- < SiteHeader selectedObject = { selectedObject } appLabel = { selectedApp ?. label } />
202+ < SiteHeader selectedObject = { selectedObject } appLabel = { selectedApp ?. label || selectedApp ?. name } />
176203 < div className = "flex flex-1 flex-col overflow-hidden" >
177204 { selectedObject ? (
178205 < div className = "flex flex-1 flex-col gap-4 p-4" >
0 commit comments