>({
)}
>
{selectable && (
- |
+ |
{
try {
- const perms = await checkPermission('DATA', 'AutomationDefinition');
+ const perms = await checkPermission('DATA', 'data.automation.AutomationDefinition');
setPermissions(perms);
return perms;
} catch (error: any) {
@@ -507,7 +507,7 @@ export function useAutomationTemplates() {
const fetchPermissions = useCallback(async () => {
try {
- const perms = await checkPermission('DATA', 'AutomationTemplate');
+ const perms = await checkPermission('DATA', 'data.automation.AutomationTemplate');
setPermissions(perms);
return perms;
} catch (e: any) {
diff --git a/src/hooks/usePrompts.ts b/src/hooks/usePrompts.ts
index 6d0cabb..3818047 100644
--- a/src/hooks/usePrompts.ts
+++ b/src/hooks/usePrompts.ts
@@ -524,15 +524,12 @@ export function usePromptOperations() {
}
};
- const handlePromptUpdate = async (promptId: string, updateData: { name: string; content: string }, _originalData?: any) => {
+ const handlePromptUpdate = async (promptId: string, updateData: Record, _originalData?: any) => {
setUpdateError(null);
try {
- // mandateId wird nicht mehr vom Client gesendet
- const requestBody = {
- name: updateData.name,
- content: updateData.content
- };
+ // Pass all provided fields (supports partial inline updates like isSystem toggle)
+ const { id, mandateId, _createdBy, _createdAt, _modifiedAt, _permissions, ...requestBody } = updateData;
const updatedPrompt = await updatePromptApi(request, promptId, requestBody);
@@ -555,8 +552,8 @@ export function usePromptOperations() {
};
// Generic inline update handler for FormGeneratorTable
- const handleInlineUpdate = async (promptId: string, changes: Partial<{ name: string; content: string }>) => {
- const result = await handlePromptUpdate(promptId, changes as { name: string; content: string });
+ const handleInlineUpdate = async (promptId: string, changes: Record) => {
+ const result = await handlePromptUpdate(promptId, changes);
if (!result.success) {
throw new Error(result.error || 'Failed to update');
}
diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx
index a94a979..686d86f 100644
--- a/src/pages/Dashboard.tsx
+++ b/src/pages/Dashboard.tsx
@@ -3,55 +3,44 @@
*
* System-Übersicht für den User.
* Zeigt alle verfügbaren Feature-Instanzen als Karten an.
+ * Daten kommen vom Backend via GET /api/navigation.
*/
import React from 'react';
import { Link } from 'react-router-dom';
-import { useMandates, useFeatureStore } from '../stores/featureStore';
-import { getLabel, FEATURE_REGISTRY } from '../types/mandate';
-import type { FeatureInstance } from '../types/mandate';
-import { FaBriefcase, FaRobot, FaPlay, FaArrowRight } from 'react-icons/fa';
+import useNavigation from '../hooks/useNavigation';
+import type { NavigationMandate, MandateFeature, FeatureInstance as NavFeatureInstance } from '../hooks/useNavigation';
+import { getPageIcon } from '../config/pageRegistry';
+import { FaArrowRight } from 'react-icons/fa';
import styles from './Dashboard.module.css';
-// =============================================================================
-// FEATURE ICONS
-// =============================================================================
-
-const FEATURE_ICONS: Record = {
- trustee: ,
- chatbot: ,
- chatworkflow: ,
-};
-
// =============================================================================
// INSTANCE CARD
// =============================================================================
interface InstanceCardProps {
- instance: FeatureInstance;
- featureLabel: string;
+ instance: NavFeatureInstance;
+ feature: MandateFeature;
+ mandateLabel: string;
}
-const InstanceCard: React.FC = ({ instance, featureLabel }) => {
- const basePath = `/mandates/${instance.mandateId}/${instance.featureCode}/${instance.id}`;
-
- // Ersten verfügbaren View finden
- const featureConfig = FEATURE_REGISTRY[instance.featureCode];
- const firstView = featureConfig?.views?.[0];
- const targetPath = firstView ? `${basePath}/${firstView.path}` : basePath;
-
+const InstanceCard: React.FC = ({ instance, feature, mandateLabel }) => {
+ // Ersten verfügbaren View-Pfad vom Backend nehmen
+ const targetPath = instance.views.length > 0 ? instance.views[0].uiPath : undefined;
+
+ if (!targetPath) return null;
+
return (
- {FEATURE_ICONS[instance.featureCode] || }
+ {getPageIcon(feature.uiComponent)}
- {featureLabel}
- {instance.userRoles?.join(', ') || '-'}
+ {feature.uiLabel}
- {instance.instanceLabel}
- {instance.mandateName}
+ {instance.uiLabel}
+ {mandateLabel}
@@ -78,59 +67,80 @@ const EmptyState: React.FC = () => (
// =============================================================================
export const DashboardPage: React.FC = () => {
- const mandates = useMandates();
- const { hasAnyInstance, getAllInstances } = useFeatureStore();
-
- // Alle Instanzen sammeln für Übersicht
- const allInstances = getAllInstances();
-
- // Gruppiere nach Feature
- const instancesByFeature = allInstances.reduce((acc, instance) => {
- const featureCode = instance.featureCode;
- if (!acc[featureCode]) {
- acc[featureCode] = [];
- }
- acc[featureCode].push(instance);
- return acc;
- }, {} as Record );
-
- if (!hasAnyInstance()) {
+ const { dynamicBlock, loading } = useNavigation();
+
+ // Alle Mandate und deren Features/Instanzen aus der Navigation
+ const mandates: NavigationMandate[] = dynamicBlock?.mandates || [];
+
+ // Gesamtzahl Instanzen und Mandate berechnen
+ let totalInstances = 0;
+ const totalMandates = mandates.length;
+ mandates.forEach(m => m.features.forEach(f => {
+ totalInstances += f.instances.length;
+ }));
+
+ if (loading) {
+ return (
+
+ );
+ }
+
+ if (totalInstances === 0) {
return ;
}
-
+
+ // Gruppiere Instanzen nach Feature (über alle Mandate)
+ const featureGroups: { feature: MandateFeature; instances: { instance: NavFeatureInstance; mandateLabel: string }[] }[] = [];
+ const featureMap = new Map();
+
+ for (const mandate of mandates) {
+ for (const feature of mandate.features) {
+ const key = feature.uiComponent;
+ let group = featureMap.get(key);
+ if (!group) {
+ group = { feature, instances: [] };
+ featureMap.set(key, group);
+ featureGroups.push(group);
+ }
+ for (const instance of feature.instances) {
+ group.instances.push({ instance, mandateLabel: mandate.uiLabel });
+ }
+ }
+ }
+
return (
Übersicht
- Du hast Zugriff auf {allInstances.length} Feature-Instanz{allInstances.length !== 1 ? 'en' : ''}
- in {mandates.length} Mandant{mandates.length !== 1 ? 'en' : ''}.
+ Du hast Zugriff auf {totalInstances} Feature-Instanz{totalInstances !== 1 ? 'en' : ''} in {totalMandates} Mandant{totalMandates !== 1 ? 'en' : ''}.
-
+
- {Object.entries(instancesByFeature).map(([featureCode, instances]) => {
- const featureConfig = FEATURE_REGISTRY[featureCode];
- const featureLabel = featureConfig ? getLabel(featureConfig.label) : featureCode;
-
- return (
-
-
- {FEATURE_ICONS[featureCode]}
- {featureLabel}
-
-
- {instances.map(instance => (
-
- ))}
-
-
- );
- })}
+ {featureGroups.map(({ feature, instances }) => (
+
+
+ {getPageIcon(feature.uiComponent)}
+ {feature.uiLabel}
+
+
+ {instances.map(({ instance, mandateLabel }) => (
+
+ ))}
+
+
+ ))}
);
diff --git a/src/pages/FeatureView.tsx b/src/pages/FeatureView.tsx
index d1ce616..7314af7 100644
--- a/src/pages/FeatureView.tsx
+++ b/src/pages/FeatureView.tsx
@@ -8,7 +8,7 @@
import React from 'react';
import { useCurrentInstance } from '../hooks/useCurrentInstance';
import { useCanViewFeatureView } from '../hooks/useInstancePermissions';
-import { getLabel, FEATURE_REGISTRY } from '../types/mandate';
+import useNavigation from '../hooks/useNavigation';
// Trustee Views
// Note: TrusteeOrganisationsView and TrusteeContractsView removed - Feature-Instanz = Organisation
@@ -129,31 +129,13 @@ interface FeatureViewPageProps {
}
export const FeatureViewPage: React.FC = ({ view }) => {
- const { instance, featureCode, isValid } = useCurrentInstance();
+ const { instance, featureCode, mandateId, isValid } = useCurrentInstance();
+ const { dynamicBlock } = useNavigation();
// Berechtigungs-Check
const viewCode = `${featureCode}-${view}`;
const canView = useCanViewFeatureView(viewCode);
- // DEBUG: Log permission check for chatbot
- if (featureCode === 'chatbot') {
- console.log('🔍 [DEBUG] FeatureView Permission Check:', {
- featureCode,
- view,
- viewCode,
- instanceId: instance?.id,
- instanceLabel: instance?.instanceLabel,
- isValid,
- canView,
- permissions: instance?.permissions,
- views: instance?.permissions?.views,
- viewKeys: instance?.permissions?.views ? Object.keys(instance.permissions.views) : [],
- hasLegacyView: instance?.permissions?.views?.[viewCode],
- hasFullObjectKey: instance?.permissions?.views?.[`ui.feature.${featureCode}.${view}`],
- hasWildcard: instance?.permissions?.views?.['_all'],
- });
- }
-
// Nicht valider Kontext
if (!isValid || !featureCode || !instance) {
return ;
@@ -175,10 +157,17 @@ export const FeatureViewPage: React.FC = ({ view }) => {
return ;
}
- // View-Info aus Registry
- const featureConfig = FEATURE_REGISTRY[featureCode];
- const viewConfig = featureConfig?.views?.find(v => v.code === view);
- const viewLabel = viewConfig ? getLabel(viewConfig.label) : view;
+ // View-Label aus Backend-Navigation ermitteln
+ let viewLabel = view;
+ if (dynamicBlock) {
+ const navMandate = dynamicBlock.mandates.find(m => m.id === mandateId);
+ const navFeature = navMandate?.features.find(f => f.uiComponent.includes(featureCode));
+ const navInstance = navFeature?.instances.find(i => i.id === instance.id);
+ const navView = navInstance?.views.find(v => v.uiComponent.includes(view));
+ if (navView) {
+ viewLabel = navView.uiLabel;
+ }
+ }
return (
diff --git a/src/pages/admin/AdminFeatureAccessPage.tsx b/src/pages/admin/AdminFeatureAccessPage.tsx
index 682e171..b266af9 100644
--- a/src/pages/admin/AdminFeatureAccessPage.tsx
+++ b/src/pages/admin/AdminFeatureAccessPage.tsx
@@ -439,6 +439,7 @@ export const AdminFeatureAccessPage: React.FC = () => {
{
{
{
{
{
{
{overview.mandates.length === 0 ? (
Keine Mandate-Zuordnungen vorhanden.
) : (
-
+
{overview.mandates.map(mandate => (
{
{overview.roles.length === 0 ? (
Keine Rollen zugewiesen.
) : (
-
+
{overview.roles.map(role => (
{
) : overview ? (
<>
{/* User Info */}
-
+
{overview.user.fullName || overview.user.username}
|
{overview.user.email}
@@ -610,7 +610,8 @@ export const AdminUserAccessOverviewPage: React.FC = () => {
gap: '0.5rem',
marginBottom: '1rem',
borderBottom: '1px solid var(--border-color)',
- paddingBottom: '0.5rem'
+ paddingBottom: '0.5rem',
+ flexShrink: 0
}}>
|