Skip to content

Commit bfc5ef0

Browse files
committed
2 parents e2bb099 + 0448313 commit bfc5ef0

21 files changed

Lines changed: 206 additions & 1485 deletions

apps/console/src/App.legacy.tsx

Lines changed: 0 additions & 149 deletions
This file was deleted.

apps/console/src/App.tsx

Lines changed: 54 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,31 @@
1-
import { useState, useEffect } from 'react';
1+
import { useState, useEffect, useCallback } from 'react';
22
import { ObjectStackClient } from '@objectstack/client';
3+
import { ObjectStackProvider } from '@objectstack/client-react';
4+
import { ErrorBoundary } from './components/ErrorBoundary';
35
import { AppSidebar } from "./components/app-sidebar"
46
import { SiteHeader } from "@/components/site-header"
57
import { SidebarProvider } from "@/components/ui/sidebar"
68
import { DeveloperOverview } from './components/DeveloperOverview';
79
import { ObjectExplorer } from './components/ObjectExplorer';
8-
import { ObjectDataForm } from './components/ObjectDataForm';
910
import { PackageManager } from './components/PackageManager';
1011
import { Toaster } from "@/components/ui/toaster"
1112
import { getApiBaseUrl, config } from './lib/config';
1213
import type { InstalledPackage } from '@objectstack/spec/kernel';
1314

15+
type ViewType = 'overview' | 'packages' | 'object';
16+
1417
export default function App() {
1518
const [client, setClient] = useState<ObjectStackClient | null>(null);
1619
const [packages, setPackages] = useState<InstalledPackage[]>([]);
1720
const [selectedPackage, setSelectedPackage] = useState<InstalledPackage | null>(null);
1821
const [selectedObject, setSelectedObject] = useState<string | null>(null);
19-
const [selectedView, setSelectedView] = useState<'overview' | 'packages' | 'object'>('overview');
20-
const [editingRecord, setEditingRecord] = useState<any>(null);
21-
const [showForm, setShowForm] = useState(false);
22+
const [selectedView, setSelectedView] = useState<ViewType>('overview');
2223

23-
// 1. Create client
24+
// 1. Create client once
2425
useEffect(() => {
2526
const baseUrl = getApiBaseUrl();
2627
console.log(`[App] Connecting to API: ${baseUrl} (mode: ${config.mode})`);
27-
28-
const newClient = new ObjectStackClient({
29-
baseUrl,
30-
});
31-
setClient(newClient);
28+
setClient(new ObjectStackClient({ baseUrl }));
3229
}, []);
3330

3431
// 2. Fetch installed packages from the server API
@@ -38,125 +35,85 @@ export default function App() {
3835

3936
async function loadPackages() {
4037
try {
41-
// Spec: GET /api/v1/packages → ListPackagesResponse = { packages: InstalledPackage[], total }
4238
const result = await client!.packages.list();
4339
const items: InstalledPackage[] = result?.packages || [];
44-
45-
console.log('[App] Fetched packages from API:', items.map((p) => p.manifest?.name || p.manifest?.id));
46-
40+
console.log('[App] Fetched packages:', items.map((p) => p.manifest?.name || p.manifest?.id));
4741
if (mounted && items.length > 0) {
4842
setPackages(items);
4943
setSelectedPackage(items[0]);
5044
}
5145
} catch (err) {
52-
console.error('[App] Failed to fetch packages from API:', err);
46+
console.error('[App] Failed to fetch packages:', err);
5347
}
5448
}
5549

5650
loadPackages();
5751
return () => { mounted = false; };
5852
}, [client]);
5953

60-
function handleEdit(record: any) {
61-
setEditingRecord(record);
62-
setShowForm(true);
63-
}
64-
65-
function handleFormSuccess() {
66-
setShowForm(false);
67-
setEditingRecord(null);
68-
// Force a re-render of the table by toggling selected object
69-
const current = selectedObject;
70-
setSelectedObject(null);
71-
setTimeout(() => setSelectedObject(current), 0);
72-
}
73-
74-
function handleFormCancel() {
75-
setShowForm(false);
76-
setEditingRecord(null);
77-
}
78-
79-
function handleSelectPackage(pkg: InstalledPackage) {
54+
const handleSelectPackage = useCallback((pkg: InstalledPackage) => {
8055
setSelectedPackage(pkg);
8156
setSelectedObject(null);
8257
setSelectedView('overview');
83-
setShowForm(false);
84-
setEditingRecord(null);
85-
}
58+
}, []);
8659

87-
function handleSelectObject(name: string) {
60+
const handleSelectObject = useCallback((name: string) => {
8861
if (name) {
8962
setSelectedObject(name);
9063
setSelectedView('object');
9164
} else {
9265
setSelectedObject(null);
9366
setSelectedView('overview');
9467
}
95-
}
68+
}, []);
9669

97-
function handleSelectView(view: 'overview' | 'packages') {
70+
const handleSelectView = useCallback((view: ViewType) => {
9871
setSelectedView(view);
9972
setSelectedObject(null);
100-
setShowForm(false);
101-
setEditingRecord(null);
102-
}
73+
}, []);
74+
75+
const handleNavigate = useCallback((view: string, detail?: string) => {
76+
if (view === 'packages') handleSelectView('packages');
77+
else if (detail) handleSelectObject(detail);
78+
}, [handleSelectView, handleSelectObject]);
79+
80+
if (!client) return null;
10381

10482
return (
105-
<SidebarProvider>
106-
<AppSidebar
107-
client={client}
108-
selectedObject={selectedObject}
109-
onSelectObject={handleSelectObject}
110-
packages={packages}
111-
selectedPackage={selectedPackage}
112-
onSelectPackage={handleSelectPackage}
113-
onSelectView={handleSelectView}
114-
selectedView={selectedView}
115-
/>
116-
<main className="flex min-w-0 flex-1 flex-col bg-background">
117-
<SiteHeader
118-
selectedObject={selectedObject}
83+
<ObjectStackProvider client={client}>
84+
<ErrorBoundary>
85+
<SidebarProvider>
86+
<AppSidebar
87+
selectedObject={selectedObject}
88+
onSelectObject={handleSelectObject}
89+
packages={packages}
90+
selectedPackage={selectedPackage}
91+
onSelectPackage={handleSelectPackage}
92+
onSelectView={handleSelectView}
11993
selectedView={selectedView}
120-
packageLabel={selectedPackage?.manifest?.name || selectedPackage?.manifest?.id}
12194
/>
122-
<div className="flex flex-1 flex-col overflow-hidden">
123-
{selectedView === 'object' && selectedObject ? (
124-
client && (
125-
<ObjectExplorer
126-
client={client}
127-
objectApiName={selectedObject}
128-
onEdit={handleEdit}
129-
/>
130-
)
131-
) : selectedView === 'packages' ? (
132-
client && <PackageManager client={client} />
133-
) : (
134-
client && (
95+
<main className="flex min-w-0 flex-1 flex-col bg-background">
96+
<SiteHeader
97+
selectedObject={selectedObject}
98+
selectedView={selectedView}
99+
packageLabel={selectedPackage?.manifest?.name || selectedPackage?.manifest?.id}
100+
/>
101+
<div className="flex flex-1 flex-col overflow-hidden">
102+
{selectedView === 'object' && selectedObject ? (
103+
<ObjectExplorer objectApiName={selectedObject} />
104+
) : selectedView === 'packages' ? (
105+
<PackageManager />
106+
) : (
135107
<DeveloperOverview
136-
client={client}
137108
packages={packages}
138-
onNavigate={(view, detail) => {
139-
if (view === 'packages') handleSelectView('packages');
140-
else if (detail) handleSelectObject(detail);
141-
}}
109+
onNavigate={handleNavigate}
142110
/>
143-
)
144-
)}
145-
</div>
146-
</main>
147-
148-
{/* Form Dialog */}
149-
{showForm && client && selectedObject && (
150-
<ObjectDataForm
151-
client={client}
152-
objectApiName={selectedObject}
153-
record={editingRecord && Object.keys(editingRecord).length > 0 ? editingRecord : undefined}
154-
onSuccess={handleFormSuccess}
155-
onCancel={handleFormCancel}
156-
/>
157-
)}
158-
159-
<Toaster />
160-
</SidebarProvider>
161-
)
111+
)}
112+
</div>
113+
</main>
114+
<Toaster />
115+
</SidebarProvider>
116+
</ErrorBoundary>
117+
</ObjectStackProvider>
118+
);
162119
}

0 commit comments

Comments
 (0)