117 lines
3.6 KiB
TypeScript
117 lines
3.6 KiB
TypeScript
/**
|
|
* useCatalogObjects Hook
|
|
*
|
|
* Fetches RBAC catalog objects (DATA, UI, RESOURCE) from the backend.
|
|
* Used by AccessRulesEditor to populate object selection dropdowns.
|
|
*/
|
|
|
|
import { useState, useCallback } from 'react';
|
|
import api from '../api';
|
|
import { type RuleContext } from './useAccessRules';
|
|
|
|
// =============================================================================
|
|
// TYPES
|
|
// =============================================================================
|
|
|
|
export interface CatalogObject {
|
|
objectKey: string;
|
|
featureCode: string;
|
|
label: { [lang: string]: string };
|
|
meta?: Record<string, unknown>;
|
|
type: RuleContext;
|
|
}
|
|
|
|
export interface CatalogObjects {
|
|
DATA: CatalogObject[];
|
|
UI: CatalogObject[];
|
|
RESOURCE: CatalogObject[];
|
|
}
|
|
|
|
interface UseCatalogObjectsReturn {
|
|
objects: CatalogObjects;
|
|
loading: boolean;
|
|
error: string | null;
|
|
fetchObjects: (context?: RuleContext, featureCode?: string, mandateId?: string) => Promise<CatalogObjects>;
|
|
getObjectsByContext: (context: RuleContext) => CatalogObject[];
|
|
getObjectByKey: (objectKey: string) => CatalogObject | undefined;
|
|
}
|
|
|
|
// =============================================================================
|
|
// HOOK
|
|
// =============================================================================
|
|
|
|
export function useCatalogObjects(): UseCatalogObjectsReturn {
|
|
const [objects, setObjects] = useState<CatalogObjects>({ DATA: [], UI: [], RESOURCE: [] });
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
/**
|
|
* Fetch catalog objects from the backend.
|
|
*
|
|
* @param context - Optional filter by context type (DATA, UI, RESOURCE)
|
|
* @param featureCode - Optional filter by feature code
|
|
* @param mandateId - Optional filter by mandate's active features
|
|
*/
|
|
const fetchObjects = useCallback(async (
|
|
context?: RuleContext,
|
|
featureCode?: string,
|
|
mandateId?: string
|
|
): Promise<CatalogObjects> => {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
const params = new URLSearchParams();
|
|
if (context) params.append('context', context);
|
|
if (featureCode) params.append('featureCode', featureCode);
|
|
if (mandateId) params.append('mandateId', mandateId);
|
|
|
|
const url = `/api/rbac/catalog/objects${params.toString() ? `?${params}` : ''}`;
|
|
const response = await api.get<CatalogObjects>(url);
|
|
|
|
// Normalize response structure
|
|
const data: CatalogObjects = {
|
|
DATA: response.data.DATA || [],
|
|
UI: response.data.UI || [],
|
|
RESOURCE: response.data.RESOURCE || [],
|
|
};
|
|
|
|
setObjects(data);
|
|
return data;
|
|
} catch (err: unknown) {
|
|
const errorMsg = err instanceof Error
|
|
? err.message
|
|
: (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail || 'Fehler beim Laden der Katalog-Objekte';
|
|
setError(errorMsg);
|
|
return { DATA: [], UI: [], RESOURCE: [] };
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
/**
|
|
* Get objects filtered by context.
|
|
*/
|
|
const getObjectsByContext = useCallback((context: RuleContext): CatalogObject[] => {
|
|
return objects[context] || [];
|
|
}, [objects]);
|
|
|
|
/**
|
|
* Get a specific object by its key.
|
|
*/
|
|
const getObjectByKey = useCallback((objectKey: string): CatalogObject | undefined => {
|
|
const allObjects = [...objects.DATA, ...objects.UI, ...objects.RESOURCE];
|
|
return allObjects.find(obj => obj.objectKey === objectKey);
|
|
}, [objects]);
|
|
|
|
return {
|
|
objects,
|
|
loading,
|
|
error,
|
|
fetchObjects,
|
|
getObjectsByContext,
|
|
getObjectByKey,
|
|
};
|
|
}
|
|
|
|
export default useCatalogObjects;
|