Skip to content

Commit 226bd8e

Browse files
committed
2 parents 12a60ce + 53e18e4 commit 226bd8e

48 files changed

Lines changed: 20786 additions & 195 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/console/src/App.tsx

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import { SiteHeader } from "@/components/site-header"
55
import { SidebarProvider } from "@/components/ui/sidebar"
66
import { ObjectDataTable } from './components/ObjectDataTable';
77
import { ObjectDataForm } from './components/ObjectDataForm';
8+
import { PackageManager } from './components/PackageManager';
89
import { Toaster } from "@/components/ui/toaster"
910
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
1011
import { Database, Layers, Sparkles, Zap } from 'lucide-react';
1112
import { getApiBaseUrl, config } from './lib/config';
12-
import { appPackages, type AppPackage } from './mocks/browser';
13+
import type { AppPackage } from './mocks/browser';
1314

1415
function DashboardWelcome() {
1516
return (
@@ -119,13 +120,15 @@ function DashboardWelcome() {
119120

120121
export default function App() {
121122
const [client, setClient] = useState<ObjectStackClient | null>(null);
123+
const [apps, setApps] = useState<AppPackage[]>([]);
124+
const [selectedApp, setSelectedApp] = useState<AppPackage | null>(null);
122125
const [selectedObject, setSelectedObject] = useState<string | null>(null);
126+
const [selectedView, setSelectedView] = useState<'dashboard' | 'packages' | 'object'>('dashboard');
123127
const [editingRecord, setEditingRecord] = useState<any>(null);
124128
const [showForm, setShowForm] = useState(false);
125-
const [selectedApp, setSelectedApp] = useState<AppPackage>(appPackages[0]);
126129

130+
// 1. Create client
127131
useEffect(() => {
128-
// Use the configured API base URL based on runtime mode (MSW or Server)
129132
const baseUrl = getApiBaseUrl();
130133
console.log(`[App] Connecting to API: ${baseUrl} (mode: ${config.mode})`);
131134

@@ -135,6 +138,32 @@ export default function App() {
135138
setClient(newClient);
136139
}, []);
137140

141+
// 2. Fetch app list from the server API (not hardcoded)
142+
useEffect(() => {
143+
if (!client) return;
144+
let mounted = true;
145+
146+
async function loadApps() {
147+
try {
148+
// Spec: GET /api/v1/meta/apps → GetMetaItemsResponse = { type: 'apps', items: AppSchema[] }
149+
const result: any = await client!.meta.getItems('apps');
150+
const items: AppPackage[] = result?.items || result?.value || (Array.isArray(result) ? result : []);
151+
152+
console.log('[App] Fetched apps from API:', items.map((a: any) => a.label || a.name));
153+
154+
if (mounted && items.length > 0) {
155+
setApps(items);
156+
setSelectedApp(items[0]);
157+
}
158+
} catch (err) {
159+
console.error('[App] Failed to fetch apps from API:', err);
160+
}
161+
}
162+
163+
loadApps();
164+
return () => { mounted = false; };
165+
}, [client]);
166+
138167
function handleEdit(record: any) {
139168
setEditingRecord(record);
140169
setShowForm(true);
@@ -157,6 +186,24 @@ export default function App() {
157186
function handleSelectApp(app: AppPackage) {
158187
setSelectedApp(app);
159188
setSelectedObject(null);
189+
setSelectedView('dashboard');
190+
setShowForm(false);
191+
setEditingRecord(null);
192+
}
193+
194+
function handleSelectObject(name: string) {
195+
if (name) {
196+
setSelectedObject(name);
197+
setSelectedView('object');
198+
} else {
199+
setSelectedObject(null);
200+
setSelectedView('dashboard');
201+
}
202+
}
203+
204+
function handleSelectView(view: 'dashboard' | 'packages') {
205+
setSelectedView(view);
206+
setSelectedObject(null);
160207
setShowForm(false);
161208
setEditingRecord(null);
162209
}
@@ -166,15 +213,17 @@ export default function App() {
166213
<AppSidebar
167214
client={client}
168215
selectedObject={selectedObject}
169-
onSelectObject={(name) => setSelectedObject(name || null)}
170-
apps={appPackages}
216+
onSelectObject={handleSelectObject}
217+
apps={apps}
171218
selectedApp={selectedApp}
172219
onSelectApp={handleSelectApp}
220+
onSelectView={handleSelectView}
221+
selectedView={selectedView}
173222
/>
174223
<main className="flex min-w-0 flex-1 flex-col bg-background">
175-
<SiteHeader selectedObject={selectedObject} appLabel={selectedApp?.label} />
224+
<SiteHeader selectedObject={selectedObject} appLabel={selectedApp?.label || selectedApp?.name} />
176225
<div className="flex flex-1 flex-col overflow-hidden">
177-
{selectedObject ? (
226+
{selectedView === 'object' && selectedObject ? (
178227
<div className="flex flex-1 flex-col gap-4 p-4">
179228
{client && (
180229
<ObjectDataTable
@@ -184,6 +233,8 @@ export default function App() {
184233
/>
185234
)}
186235
</div>
236+
) : selectedView === 'packages' ? (
237+
client && <PackageManager client={client} />
187238
) : (
188239
<DashboardWelcome />
189240
)}

apps/console/src/components/MetadataExplorer.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ export function MetadataExplorer({ client, selectedObject, onSelectObject }: Met
2222
// Use plural 'objects' to ensure HttpDispatcher treats it as a list request
2323
// Singular 'object' is interpreted as getObject('object')
2424
const result: any = await client.meta.getItems('objects');
25-
// Support Standard Envelope { success, data } or direct array
25+
// Spec: GetMetaItemsResponse = { type, items: any[] }
2626
let items = [];
27-
if (Array.isArray(result)) {
27+
if (result && Array.isArray(result.items)) {
28+
items = result.items;
29+
} else if (Array.isArray(result)) {
2830
items = result;
29-
} else if (result && result.success && Array.isArray(result.data)) {
30-
items = result.data;
3131
} else if (result && Array.isArray(result.value)) {
3232
items = result.value;
3333
}

apps/console/src/components/ObjectDataForm.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ export function ObjectDataForm({ client, objectApiName, record, onSuccess, onCan
3232
try {
3333
const found: any = await client.meta.getItem('object', objectApiName);
3434
if (mounted && found) {
35-
const resolved = found.data || found;
35+
// Spec: GetMetaItemResponse = { type, name, item }
36+
const resolved = found.item || found;
3637
setDef(resolved);
3738
if (record) {
3839
setFormData({ ...record });

apps/console/src/components/ObjectDataTable.tsx

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ export function ObjectDataTable({ client, objectApiName, onEdit }: ObjectDataTab
9494
try {
9595
const found: any = await client.meta.getItem('object', objectApiName);
9696
if (mounted && found) {
97-
const def = found.data || found;
97+
// Spec: GetMetaItemResponse = { type, name, item }
98+
const def = found.item || found;
9899
setDef(def);
99100
}
100101
} catch (err) {
@@ -121,17 +122,11 @@ export function ObjectDataTable({ client, objectApiName, onEdit }: ObjectDataTab
121122
});
122123

123124
if (mounted) {
124-
if (result && Array.isArray(result.value)) {
125-
setRecords(result.value);
126-
if (typeof result.count === 'number') setTotal(result.count);
127-
} else if (result && result.success && Array.isArray(result.data)) {
128-
setRecords(result.data);
129-
if (result.meta && typeof result.meta.count === 'number') setTotal(result.meta.count);
130-
} else if (Array.isArray(result)) {
131-
setRecords(result);
132-
} else if (result && typeof result === 'object' && result?.data && Array.isArray(result.data)) {
133-
setRecords(result.data);
134-
}
125+
// Spec: FindDataResponse = { object, records, total?, hasMore? }
126+
const records = result?.records || result?.value || (Array.isArray(result) ? result : []);
127+
setRecords(records);
128+
if (typeof result?.total === 'number') setTotal(result.total);
129+
else if (typeof result?.count === 'number') setTotal(result.count);
135130
}
136131
} catch (err) {
137132
console.error('Failed to load data', err);
@@ -153,9 +148,9 @@ export function ObjectDataTable({ client, objectApiName, onEdit }: ObjectDataTab
153148
skip: (page - 1) * pageSize
154149
}
155150
});
156-
if (result && (result.value || Array.isArray(result))) {
157-
setRecords(result.value || result);
158-
}
151+
// Spec: FindDataResponse = { object, records, total? }
152+
const records = result?.records || result?.value || (Array.isArray(result) ? result : []);
153+
setRecords(records);
159154
} catch (err) {
160155
alert('Failed to delete: ' + err);
161156
}
@@ -171,14 +166,11 @@ export function ObjectDataTable({ client, objectApiName, onEdit }: ObjectDataTab
171166
count: true
172167
}
173168
});
174-
if (result && Array.isArray(result.value)) {
175-
setRecords(result.value);
176-
if (typeof result.count === 'number') setTotal(result.count);
177-
} else if (result && result.success && Array.isArray(result.data)) {
178-
setRecords(result.data);
179-
} else if (Array.isArray(result)) {
180-
setRecords(result);
181-
}
169+
// Spec: FindDataResponse = { object, records, total? }
170+
const records = result?.records || result?.value || (Array.isArray(result) ? result : []);
171+
setRecords(records);
172+
if (typeof result?.total === 'number') setTotal(result.total);
173+
else if (typeof result?.count === 'number') setTotal(result.count);
182174
} catch (err) {
183175
console.error('Failed to refresh', err);
184176
} finally {

0 commit comments

Comments
 (0)