Skip to content

Commit da7934a

Browse files
authored
Merge pull request #518 from objectstack-ai/copilot/fix-console-initialization-issue
2 parents 6bac8bf + 7628557 commit da7934a

2 files changed

Lines changed: 30 additions & 71 deletions

File tree

apps/console/src/App.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { BrowserRouter, Routes, Route, Navigate, useNavigate, useLocation, useSearchParams } from 'react-router-dom';
22
import { useState, useEffect, lazy, Suspense, useMemo, type ReactNode } from 'react';
33
import { ObjectForm } from '@object-ui/plugin-form';
4-
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Empty, EmptyTitle } from '@object-ui/components';
4+
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Empty, EmptyTitle, EmptyDescription } from '@object-ui/components';
55
import { toast } from 'sonner';
66
import { SchemaRendererProvider } from '@object-ui/react';
77
import type { ConnectionState } from './dataSource';
@@ -368,15 +368,24 @@ function findFirstRoute(items: any[]): string {
368368

369369
// Redirect root to default app
370370
function RootRedirect() {
371-
const { apps, loading } = useMetadata();
371+
const { apps, loading, error } = useMetadata();
372372
const activeApps = apps.filter((a: any) => a.active !== false);
373373
const defaultApp = activeApps.find((a: any) => a.isDefault === true) || activeApps[0];
374374

375375
if (loading) return <LoadingScreen />;
376376
if (defaultApp) {
377377
return <Navigate to={`/apps/${defaultApp.name}`} replace />;
378378
}
379-
return <LoadingScreen />;
379+
return (
380+
<div className="h-screen flex items-center justify-center">
381+
<Empty>
382+
<EmptyTitle>{error ? 'Failed to Load Configuration' : 'No Apps Configured'}</EmptyTitle>
383+
<EmptyDescription>
384+
{error ? error.message : 'No applications have been registered. Check your ObjectStack configuration.'}
385+
</EmptyDescription>
386+
</Empty>
387+
</div>
388+
);
380389
}
381390

382391
export function App() {

apps/console/src/mocks/handlers.ts

Lines changed: 18 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -48,98 +48,48 @@ export function createHandlers(baseUrl: string, kernel: ObjectKernel, driver: In
4848
return HttpResponse.json(response, { status: 200 });
4949
}),
5050

51-
// ── Metadata: list objects ───────────────────────────────────────────
52-
http.get(`${prefix}${baseUrl}/meta/objects`, async () => {
53-
const response = await protocol.getMetaItems({ type: 'object' });
51+
// ── Metadata: list items by type ────────────────────────────────────
52+
// The client sends GET /meta/<type> where <type> is singular (e.g. app,
53+
// object, dashboard, report, page). We also keep the legacy plural
54+
// routes (/meta/apps, /meta/objects, …) for backward compatibility.
55+
// A single dynamic handler covers both forms.
56+
http.get(`${prefix}${baseUrl}/meta/:type`, async ({ params }) => {
57+
const metadataType = params.type as string;
58+
const response = await protocol.getMetaItems({ type: metadataType });
5459
return HttpResponse.json(response, { status: 200 });
5560
}),
56-
http.get(`${prefix}${baseUrl}/metadata/objects`, async () => {
57-
const response = await protocol.getMetaItems({ type: 'object' });
61+
http.get(`${prefix}${baseUrl}/metadata/:type`, async ({ params }) => {
62+
const metadataType = params.type as string;
63+
const response = await protocol.getMetaItems({ type: metadataType });
5864
return HttpResponse.json(response, { status: 200 });
5965
}),
6066

61-
// ── Metadata: single object (legacy /meta/objects/:name) ─────────────
62-
http.get(`${prefix}${baseUrl}/meta/objects/:objectName`, async ({ params }) => {
67+
// ── Metadata: single item by type + name ─────────────────────────────
68+
http.get(`${prefix}${baseUrl}/meta/:type/:name`, async ({ params }) => {
6369
try {
6470
const response = await protocol.getMetaItem({
65-
type: 'object',
66-
name: params.objectName as string
67-
});
68-
return HttpResponse.json(response || { error: 'Not found' }, { status: response ? 200 : 404 });
69-
} catch (e) {
70-
return HttpResponse.json({ error: String(e) }, { status: 500 });
71-
}
72-
}),
73-
74-
// ── Metadata: single object (/meta/object/:name & /metadata/object/:name)
75-
http.get(`${prefix}${baseUrl}/meta/object/:objectName`, async ({ params }) => {
76-
try {
77-
const response = await protocol.getMetaItem({
78-
type: 'object',
79-
name: params.objectName as string
71+
type: params.type as string,
72+
name: params.name as string
8073
});
8174
const payload = (response && response.item) ? response.item : response;
8275
return HttpResponse.json(payload || { error: 'Not found' }, { status: payload ? 200 : 404 });
8376
} catch (e) {
84-
console.error('[MSW] error getting meta item', e);
8577
return HttpResponse.json({ error: String(e) }, { status: 500 });
8678
}
8779
}),
88-
89-
http.get(`${prefix}${baseUrl}/metadata/object/:objectName`, async ({ params }) => {
80+
http.get(`${prefix}${baseUrl}/metadata/:type/:name`, async ({ params }) => {
9081
try {
9182
const response = await protocol.getMetaItem({
92-
type: 'object',
93-
name: params.objectName as string
83+
type: params.type as string,
84+
name: params.name as string
9485
});
9586
const payload = (response && response.item) ? response.item : response;
9687
return HttpResponse.json(payload || { error: 'Not found' }, { status: payload ? 200 : 404 });
9788
} catch (e) {
98-
console.error('[MSW] error getting meta item', e);
9989
return HttpResponse.json({ error: String(e) }, { status: 500 });
10090
}
10191
}),
10292

103-
// ── Metadata: apps ──────────────────────────────────────────────────
104-
http.get(`${prefix}${baseUrl}/meta/apps`, async () => {
105-
const response = await protocol.getMetaItems({ type: 'app' });
106-
return HttpResponse.json(response, { status: 200 });
107-
}),
108-
http.get(`${prefix}${baseUrl}/metadata/apps`, async () => {
109-
const response = await protocol.getMetaItems({ type: 'app' });
110-
return HttpResponse.json(response, { status: 200 });
111-
}),
112-
113-
// ── Metadata: dashboards ────────────────────────────────────────────
114-
http.get(`${prefix}${baseUrl}/meta/dashboards`, async () => {
115-
const response = await protocol.getMetaItems({ type: 'dashboard' });
116-
return HttpResponse.json(response, { status: 200 });
117-
}),
118-
http.get(`${prefix}${baseUrl}/metadata/dashboards`, async () => {
119-
const response = await protocol.getMetaItems({ type: 'dashboard' });
120-
return HttpResponse.json(response, { status: 200 });
121-
}),
122-
123-
// ── Metadata: reports ───────────────────────────────────────────────
124-
http.get(`${prefix}${baseUrl}/meta/reports`, async () => {
125-
const response = await protocol.getMetaItems({ type: 'report' });
126-
return HttpResponse.json(response, { status: 200 });
127-
}),
128-
http.get(`${prefix}${baseUrl}/metadata/reports`, async () => {
129-
const response = await protocol.getMetaItems({ type: 'report' });
130-
return HttpResponse.json(response, { status: 200 });
131-
}),
132-
133-
// ── Metadata: pages ─────────────────────────────────────────────────
134-
http.get(`${prefix}${baseUrl}/meta/pages`, async () => {
135-
const response = await protocol.getMetaItems({ type: 'page' });
136-
return HttpResponse.json(response, { status: 200 });
137-
}),
138-
http.get(`${prefix}${baseUrl}/metadata/pages`, async () => {
139-
const response = await protocol.getMetaItems({ type: 'page' });
140-
return HttpResponse.json(response, { status: 200 });
141-
}),
142-
14393
// ── Data: find all ──────────────────────────────────────────────────
14494
http.get(`${prefix}${baseUrl}/data/:objectName`, async ({ params, request }) => {
14595
const url = new URL(request.url);

0 commit comments

Comments
 (0)