Skip to content

Commit 2796b6d

Browse files
xuyushun441-sysos-zhuangclaude
authored
feat(studio): datasource managed through the metadata-admin engine, not a bespoke page (#1846)
datasource is a metadata type, so it should be administered by the generic metadata-admin engine like every other type — not a hand-written System page. - Register `datasource` as a metadata-admin resource (registry) with a custom ListPage that ports the full manager (list / create / edit / delete / test / sync objects). It's a *side-effectful* type (secret encryption + connection pool + introspection), so writes go through the framework `datasource-admin` REST (`/api/v1/datasources/*`), but it now lives inside the engine: engine route (`…/component/metadata/resource?type=datasource`), registry slot, shell. Form uses the engine's `useMetadataClient`; sync creates objects via it. - Delete the standalone `DatasourceManagerPage` + `system/datasources` route. - Add a "Datasources" item to the console admin nav + repoint the System hub card to the engine route. - Fix MetadataRedirect/ObjectRedirect: they left a stray `system/` segment so `system/metadata/:type` 404'd — also repairs the existing "Object Manager" link. Verified live (showcase + setup apps): list, create (eng_demo), and sync (customers/orders → real object metadata) all work through the engine route. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent e4afa84 commit 2796b6d

8 files changed

Lines changed: 637 additions & 223 deletions

File tree

apps/console/src/AppContent.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
} from '@object-ui/providers';
1919

2020
const SystemHubPage = lazy(() => import('./pages/system/SystemHubPage').then(m => ({ default: m.SystemHubPage })));
21-
const DatasourceManagerPage = lazy(() => import('./pages/system/DatasourceManagerPage').then(m => ({ default: m.DatasourceManagerPage })));
2221
const AppManagementPage = lazy(() => import('./pages/system/AppManagementPage').then(m => ({ default: m.AppManagementPage })));
2322
const ProfilePage = lazy(() => import('./pages/system/ProfilePage').then(m => ({ default: m.ProfilePage })));
2423
const ApprovalsInboxPage = lazy(() => import('./pages/system/ApprovalsInboxPage').then(m => ({ default: m.ApprovalsInboxPage })));
@@ -51,7 +50,7 @@ const DocsLayout = lazy(() => import('./pages/DocsLayout'));
5150
function ObjectRedirect() {
5251
const { objectName } = useParams<{ objectName?: string }>();
5352
const location = useLocation();
54-
const prefix = location.pathname.replace(/\/objects(\/.*)?$/, '');
53+
const prefix = location.pathname.replace(/\/(system\/)?objects(\/.*)?$/, '');
5554
const target = objectName
5655
? `${prefix}/component/metadata/resource/${objectName}?type=object`
5756
: `${prefix}/component/metadata/resource?type=object`;
@@ -67,7 +66,10 @@ function ObjectRedirect() {
6766
function MetadataRedirect() {
6867
const { metadataType, itemName } = useParams<{ metadataType?: string; itemName?: string }>();
6968
const location = useLocation();
70-
const prefix = location.pathname.replace(/\/metadata(\/.*)?$/, '');
69+
// Strip an optional leading `system/` too — legacy nav uses
70+
// `…/system/metadata/:type`, and the engine route lives at the app root
71+
// (`…/component/metadata/resource`), not under `system/`.
72+
const prefix = location.pathname.replace(/\/(system\/)?metadata(\/.*)?$/, '');
7173
const base = `${prefix}/component/metadata/resource`;
7274
const target = !metadataType
7375
? `${prefix}/component/metadata/directory`
@@ -87,7 +89,6 @@ const systemRoutes = (
8789
<Route path="system/audit-log" element={<Suspense fallback={<LoadingScreen />}><AuditLogPage /></Suspense>} />
8890
<Route path="system/settings" element={<Suspense fallback={<LoadingScreen />}><SettingsHub /></Suspense>} />
8991
<Route path="system/settings/:namespace" element={<Suspense fallback={<LoadingScreen />}><SettingsView /></Suspense>} />
90-
<Route path="system/datasources" element={<Suspense fallback={<LoadingScreen />}><DatasourceManagerPage /></Suspense>} />
9192
<Route path="developer" element={<Suspense fallback={<LoadingScreen />}><DeveloperHubPage /></Suspense>} />
9293
<Route path="developer/api-console" element={<Suspense fallback={<LoadingScreen />}><ApiConsolePage /></Suspense>} />
9394
<Route path="developer/flow-runs" element={<Suspense fallback={<LoadingScreen />}><FlowRunsPage /></Suspense>} />

apps/console/src/pages/system/DatasourceManagerPage.tsx

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

apps/console/src/pages/system/SystemHubPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export function SystemHubPage() {
123123
title: 'Datasources',
124124
description: 'Connect external databases and sync their tables in as objects',
125125
icon: Boxes,
126-
href: `${basePath}/system/datasources`,
126+
href: `${basePath}/component/metadata/resource?type=datasource`,
127127
countLabel: '',
128128
count: null,
129129
},

packages/app-shell/src/layout/AppSidebar.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ export function AppSidebar({ activeAppName, onAppChange }: { activeAppName: stri
286286
}
287287
items.push(
288288
{ id: 'sys-objects', label: t('layout.systemNav.objectManager', { defaultValue: 'Object Manager' }), type: 'url' as const, url: '/apps/setup/system/metadata/object', icon: 'database' },
289+
{ id: 'sys-datasources', label: t('layout.systemNav.datasources', { defaultValue: 'Datasources' }), type: 'url' as const, url: '/apps/setup/component/metadata/resource?type=datasource', icon: 'database' },
289290
{ id: 'sys-users', label: t('layout.systemNav.users', { defaultValue: 'Users' }), type: 'url' as const, url: '/apps/setup/system/users', icon: 'users' },
290291
{ id: 'sys-orgs', label: t('layout.systemNav.organizations', { defaultValue: 'Organizations' }), type: 'url' as const, url: '/apps/setup/system/organizations', icon: 'building-2' },
291292
{ id: 'sys-roles', label: t('layout.systemNav.roles', { defaultValue: 'Roles' }), type: 'url' as const, url: '/apps/setup/system/roles', icon: 'shield' },

packages/app-shell/src/layout/UnifiedSidebar.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ export function UnifiedSidebar({ activeAppName }: UnifiedSidebarProps) {
237237
{ id: 'sys-apps', label: t('layout.systemNav.applications', { defaultValue: 'Applications' }), type: 'url' as const, url: '/apps/setup/system/apps', icon: 'layout-grid' },
238238
{ id: 'sys-marketplace', label: t('layout.systemNav.appMarketplace', { defaultValue: 'App Marketplace' }), type: 'url' as const, url: '/apps/setup/system/marketplace', icon: 'store' },
239239
{ id: 'sys-objects', label: t('layout.systemNav.objectManager', { defaultValue: 'Object Manager' }), type: 'url' as const, url: '/apps/setup/system/metadata/object', icon: 'database' },
240+
{ id: 'sys-datasources', label: t('layout.systemNav.datasources', { defaultValue: 'Datasources' }), type: 'url' as const, url: '/apps/setup/component/metadata/resource?type=datasource', icon: 'database' },
240241
{ id: 'sys-users', label: t('layout.systemNav.users', { defaultValue: 'Users' }), type: 'url' as const, url: '/apps/setup/system/users', icon: 'users' },
241242
{ id: 'sys-orgs', label: t('layout.systemNav.organizations', { defaultValue: 'Organizations' }), type: 'url' as const, url: '/apps/setup/system/organizations', icon: 'building-2' },
242243
{ id: 'sys-roles', label: t('layout.systemNav.roles', { defaultValue: 'Roles' }), type: 'url' as const, url: '/apps/setup/system/roles', icon: 'shield' },

0 commit comments

Comments
 (0)