Skip to content

Commit 89e707b

Browse files
committed
2 parents eb1b851 + da5c2f1 commit 89e707b

File tree

7 files changed

+36
-14
lines changed

7 files changed

+36
-14
lines changed

apps/studio/src/App.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export default function App() {
6262
const handleSelectPackage = useCallback((pkg: InstalledPackage) => {
6363
setSelectedPackage(pkg);
6464
setSelectedObject(null);
65+
setSelectedMeta(null);
6566
setSelectedView('overview');
6667
}, []);
6768

@@ -126,9 +127,17 @@ export default function App() {
126127
/>
127128
<div className="flex flex-1 flex-col overflow-hidden">
128129
{selectedView === 'object' && selectedObject ? (
129-
<PluginHost metadataType="object" metadataName={selectedObject} />
130+
<PluginHost
131+
metadataType="object"
132+
metadataName={selectedObject}
133+
packageId={selectedPackage?.manifest?.id}
134+
/>
130135
) : selectedView === 'metadata' && selectedMeta ? (
131-
<PluginHost metadataType={selectedMeta.type} metadataName={selectedMeta.name} />
136+
<PluginHost
137+
metadataType={selectedMeta.type}
138+
metadataName={selectedMeta.name}
139+
packageId={selectedPackage?.manifest?.id}
140+
/>
132141
) : selectedView === 'packages' ? (
133142
<PackageManager />
134143
) : selectedView === 'api-console' ? (

apps/studio/src/components/MetadataInspector.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/comp
1818
interface MetadataInspectorProps {
1919
metaType: string;
2020
metaName: string;
21+
packageId?: string;
2122
}
2223

2324
const TYPE_ICONS: Record<string, LucideIcon> = {
@@ -173,7 +174,7 @@ function JsonTree({ data, depth = 0 }: { data: any; depth?: number }) {
173174
}
174175

175176

176-
export function MetadataInspector({ metaType, metaName }: MetadataInspectorProps) {
177+
export function MetadataInspector({ metaType, metaName, packageId }: MetadataInspectorProps) {
177178
const client = useClient();
178179
const [item, setItem] = useState<any>(null);
179180
const [loading, setLoading] = useState(true);
@@ -189,7 +190,7 @@ export function MetadataInspector({ metaType, metaName }: MetadataInspectorProps
189190

190191
async function load() {
191192
try {
192-
const result: any = await client.meta.getItem(metaType, metaName);
193+
const result: any = await client.meta.getItem(metaType, metaName, packageId ? { packageId } : undefined);
193194
if (mounted) {
194195
setItem(result?.item || result);
195196
}
@@ -201,7 +202,7 @@ export function MetadataInspector({ metaType, metaName }: MetadataInspectorProps
201202
}
202203
load();
203204
return () => { mounted = false; };
204-
}, [client, metaType, metaName]);
205+
}, [client, metaType, metaName, packageId]);
205206

206207
if (loading) {
207208
return (

apps/studio/src/plugins/built-in/default-plugin.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import type { StudioPlugin, MetadataViewerProps } from '../types';
1515

1616
// ─── Viewer Component (adapts MetadataInspector to plugin interface) ─
1717

18-
function DefaultViewerComponent({ metadataType, metadataName }: MetadataViewerProps) {
19-
return <MetadataInspector metaType={metadataType} metaName={metadataName} />;
18+
function DefaultViewerComponent({ metadataType, metadataName, packageId }: MetadataViewerProps) {
19+
return <MetadataInspector metaType={metadataType} metaName={metadataName} packageId={packageId} />;
2020
}
2121

2222
// ─── Plugin Definition ───────────────────────────────────────────────

apps/studio/src/plugins/plugin-host.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ interface PluginHostProps {
4848
metadataName: string;
4949
/** Pre-loaded metadata data (optional) */
5050
data?: any;
51+
/** Package ID to filter metadata by (optional) */
52+
packageId?: string;
5153
}
5254

5355
// ─── Component ───────────────────────────────────────────────────────
5456

55-
export function PluginHost({ metadataType, metadataName, data }: PluginHostProps) {
57+
export function PluginHost({ metadataType, metadataName, data, packageId }: PluginHostProps) {
5658
const [activeMode, setActiveMode] = useState<ViewMode>('preview');
5759

5860
// Get available modes and viewers for this metadata type
@@ -176,6 +178,7 @@ export function PluginHost({ metadataType, metadataName, data }: PluginHostProps
176178
metadataName={metadataName}
177179
data={data}
178180
mode={effectiveMode}
181+
packageId={packageId}
179182
/>
180183
</div>
181184
</div>

apps/studio/src/plugins/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export interface MetadataViewerProps {
2626
data?: any;
2727
/** Current view mode */
2828
mode: ViewMode;
29+
/** Package ID to filter metadata by (optional) */
30+
packageId?: string;
2931
}
3032

3133
/** Context passed to action handlers */

packages/client/src/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,10 +359,15 @@ export class ObjectStackClient {
359359
* Get a specific metadata item by type and name
360360
* @param type - Metadata type (e.g., 'object', 'plugin')
361361
* @param name - Item name (snake_case identifier)
362+
* @param options - Optional filters (e.g., packageId to scope by package)
362363
*/
363-
getItem: async (type: string, name: string) => {
364+
getItem: async (type: string, name: string, options?: { packageId?: string }) => {
364365
const route = this.getRoute('metadata');
365-
const res = await this.fetch(`${this.baseUrl}${route}/${type}/${name}`);
366+
const params = new URLSearchParams();
367+
if (options?.packageId) params.set('package', options.packageId);
368+
const qs = params.toString();
369+
const url = `${this.baseUrl}${route}/${type}/${name}${qs ? `?${qs}` : ''}`;
370+
const res = await this.fetch(url);
366371
return this.unwrapResponse(res);
367372
},
368373

packages/runtime/src/http-dispatcher.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,12 +384,14 @@ export class HttpDispatcher {
384384
// /metadata/:type/:name
385385
if (parts.length === 2) {
386386
const [type, name] = parts;
387+
// Extract optional package filter from query string
388+
const packageId = query?.package || undefined;
387389

388390
// PUT /metadata/:type/:name (Save)
389391
if (method === 'PUT' && body) {
390392
// Try to get the protocol service directly
391393
const protocol = await this.resolveService('protocol');
392-
394+
393395
if (protocol && typeof protocol.saveMetaItem === 'function') {
394396
try {
395397
const result = await protocol.saveMetaItem({ type, name, item: body });
@@ -398,7 +400,7 @@ export class HttpDispatcher {
398400
return { handled: true, response: this.error(e.message, 400) };
399401
}
400402
}
401-
403+
402404
// Fallback to broker if protocol not available (legacy)
403405
if (broker) {
404406
try {
@@ -430,12 +432,12 @@ export class HttpDispatcher {
430432
// If type is singular (e.g. 'app'), use it directly
431433
// If plural (e.g. 'apps'), slice it
432434
const singularType = type.endsWith('s') ? type.slice(0, -1) : type;
433-
435+
434436
// Try Protocol Service First (Preferred)
435437
const protocol = await this.resolveService('protocol');
436438
if (protocol && typeof protocol.getMetaItem === 'function') {
437439
try {
438-
const data = await protocol.getMetaItem({ type: singularType, name });
440+
const data = await protocol.getMetaItem({ type: singularType, name, packageId });
439441
return { handled: true, response: this.success(data) };
440442
} catch (e: any) {
441443
// Protocol might throw if not found or not supported

0 commit comments

Comments
 (0)