-
-
{run.workflowLabel || run.workflowId}
-
- {t('Status')}: {run.status}
- {run.startedAt && {t('Start')}: {formatUnixTimestamp(run.startedAt)}}
- {run.completedAt && {t('Ende')}: {formatUnixTimestamp(run.completedAt)}}
- {workflow?.targetFeatureInstanceId && {t('Ziel-Instanz')}: {run.targetInstanceLabel || workflow.targetFeatureInstanceId}}
- {(run.costTokens ?? 0) > 0 && Tokens: {run.costTokens}}
-
- {run.error && (
-
- {run.error}
-
- )}
-
{t('Schritte')}
- {steps.length === 0 ? (
-
{t('Keine Schritte protokolliert.')}
- ) : (
-
- {steps.map((step) => (
-
-
-
- {step.status}
-
- {step.nodeType} ({step.nodeId})
- {step.durationMs != null && {step.durationMs}ms}
-
- {step.output && Object.keys(step.output).length > 0 && (
-
- {JSON.stringify(step.output, null, 2)}
-
- )}
- {step.error && {step.error}
}
-
- ))}
-
- )}
- {files.length > 0 && (
- <>
-
{t('Dokumente')}
-
- >
- )}
+
+
{t('Wähle einen Run im Dashboard aus, um die Details anzuzeigen.')}
);
}
+ if (detailLoading || !runDetail) {
+ return
;
+ }
+
+ const { run, steps, files, workflow } = runDetail;
+
return (
-
-
-
-
-
{total} {t('Runs')}
+
+
{run.workflowLabel || run.workflowId}
+
+ {t('Status')}: {run.status}
+ {run.startedAt && {t('Start')}: {_formatTs(run.startedAt)}}
+ {run.completedAt && {t('Ende')}: {_formatTs(run.completedAt)}}
+ {workflow?.targetFeatureInstanceId && {t('Ziel-Instanz')}: {run.targetInstanceLabel || workflow.targetFeatureInstanceId}}
+ {(run.costTokens ?? 0) > 0 && Tokens: {run.costTokens}}
- {loading ? (
-
{t('Laden…')}
- ) : runs.length === 0 ? (
-
{t('Keine Workflow-Runs gefunden.')}
+ {run.error && (
+
+ {run.error}
+
+ )}
+
{t('Schritte')}
+ {steps.length === 0 ? (
+
{t('Keine Schritte protokolliert.')}
) : (
-
-
-
- | {t('Workflow')} |
- {t('Status')} |
- {t('Gestartet')} |
- {t('Ziel-Instanz')} |
- Tokens |
-
-
-
- {runs.map((run) => (
- setSelectedRunId(run.id)}
- style={{ borderBottom: '1px solid var(--border-color)', cursor: 'pointer' }}
- onMouseEnter={(e) => (e.currentTarget.style.background = 'var(--bg-hover, rgba(0,0,0,0.03))')}
- onMouseLeave={(e) => (e.currentTarget.style.background = '')}
+
+ {steps.map((step) => (
+
+
+
+ {step.status}
+
+ {step.nodeType} ({step.nodeId})
+ {step.durationMs != null && {step.durationMs}ms}
+
+ {step.output && Object.keys(step.output).length > 0 && (
+
+ {JSON.stringify(step.output, null, 2)}
+
+ )}
+ {step.error && {step.error}
}
+
+ ))}
+
+ )}
+ {files.length > 0 && (
+ <>
+ {t('Dokumente')}
+
+ {files.map((f) => (
+
- {run.workflowLabel || run.workflowId} |
-
-
- {run.status}
-
- |
-
{run.startedAt ? formatUnixTimestamp(run.startedAt) : '—'} |
-
{run.targetInstanceLabel || '—'} |
-
{run.costTokens ?? 0} |
-
+
+ {f.fileName || f.id}
+
))}
-
-
+
+ >
)}
);
};
// ===========================================================================
-// Main page with Tabs
+// Main page with Tabs (Workflows → Dashboard → Workspace)
// ===========================================================================
export const AutomationsDashboardPage: React.FC = () => {
const { t } = useLanguage();
+ const [searchParams] = useSearchParams();
+
+ const initialTab = searchParams.get('tab') || 'workflows';
+ const initialRunId = searchParams.get('runId') || null;
+
+ const [activeTab, setActiveTab] = useState
(initialRunId ? 'workspace' : initialTab);
+ const [selectedRunId, setSelectedRunId] = useState(initialRunId);
+ const [workflowFilter, setWorkflowFilter] = useState(null);
+
+ const _handleWorkflowClick = useCallback((workflowId: string) => {
+ setWorkflowFilter(workflowId);
+ setActiveTab('dashboard');
+ }, []);
+
+ useEffect(() => {
+ if (workflowFilter) setWorkflowFilter(null);
+ }, [workflowFilter]);
+
+ const _handleRunClick = useCallback((runId: string) => {
+ setSelectedRunId(runId);
+ setActiveTab('workspace');
+ }, []);
+
+ const _handleBackFromWorkspace = useCallback(() => {
+ setSelectedRunId(null);
+ setActiveTab('dashboard');
+ }, []);
const tabs = useMemo(() => [
- {
- id: 'dashboard',
- label: t('Dashboard'),
- content: <_DashboardTab />,
- },
{
id: 'workflows',
label: t('Workflows'),
- content: <_WorkflowsTab />,
+ content: <_WorkflowsTab onWorkflowClick={_handleWorkflowClick} />,
+ },
+ {
+ id: 'dashboard',
+ label: t('Dashboard'),
+ content: <_DashboardTab workflowFilter={workflowFilter} onRunClick={_handleRunClick} />,
},
{
id: 'workspace',
label: t('Workspace'),
- content: <_WorkspaceTab />,
+ content: <_WorkspaceTab runId={selectedRunId} onBack={_handleBackFromWorkspace} />,
},
- ], [t]);
+ ], [t, _handleWorkflowClick, workflowFilter, _handleRunClick, selectedRunId, _handleBackFromWorkspace]);
return (
{t('Automatisierung')}
-
+
);
};
diff --git a/src/pages/views/trustee/TrusteeAnalyseView.tsx b/src/pages/views/trustee/TrusteeAnalyseView.tsx
index 45f8a39..8b12b87 100644
--- a/src/pages/views/trustee/TrusteeAnalyseView.tsx
+++ b/src/pages/views/trustee/TrusteeAnalyseView.tsx
@@ -408,6 +408,9 @@ export const TrusteeAnalyseView: React.FC = () => {
{t('Budget-Excel hochladen')}
+
+ {t('Ergebnis: Excel-Bericht mit Konten-Tabelle, Uebersichts-Chart und Management-Summary.')}
+
{budgetFileName ? (
📄 {budgetFileName}