From e7641e98310dd280ed108f2ac869f4be015da6e5 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 4 May 2026 23:27:10 +0000 Subject: [PATCH] feat(history): enable 'Analysis Report' button in simulation history - ProjectManager._to_dict now scans simulation state files to find last_simulation_id and last_report_id for each project - HistoryDatabase: report button enabled when last_report_id or last_simulation_id available; goToReport looks up report by simulation ID if no direct report_id; report status icon reflects availability - Add getReportBySimulation() to frontend report API Co-Authored-By: Claude Sonnet 4.6 --- backend/app/models/project.py | 37 +++++++++++++++++++++ frontend/src/api/report.js | 8 +++++ frontend/src/components/HistoryDatabase.vue | 28 +++++++++++++--- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/backend/app/models/project.py b/backend/app/models/project.py index e7df539a..f5dad2e4 100644 --- a/backend/app/models/project.py +++ b/backend/app/models/project.py @@ -242,8 +242,43 @@ class ProjectManager: @classmethod def _to_dict(cls, proj: "ProjectModel") -> Dict[str, Any]: + import os, json as _json ontology = cls.get_ontology(proj.id) graph_external_id = cls.get_latest_graph_external_id(proj.id) + + # Find the latest simulation for this project by scanning state.json files + last_simulation_id = None + last_report_id = None + sim_base = Config.OASIS_SIMULATION_DATA_DIR + if os.path.isdir(sim_base): + candidates = [] + for entry in os.scandir(sim_base): + if not entry.is_dir(): + continue + state_path = os.path.join(entry.path, "state.json") + if not os.path.exists(state_path): + continue + try: + with open(state_path, encoding="utf-8") as f: + state = _json.load(f) + if state.get("project_id") == proj.id: + candidates.append((state.get("updated_at", ""), state.get("simulation_id"))) + except Exception: + pass + if candidates: + candidates.sort(reverse=True) + last_simulation_id = candidates[0][1] + + # Find latest report for that simulation + if last_simulation_id: + from ..services.report_agent import ReportManager + try: + report = ReportManager.get_report_by_simulation(last_simulation_id) + if report: + last_report_id = report.report_id + except Exception: + pass + return { "id": proj.id, "project_id": proj.id, @@ -262,4 +297,6 @@ class ProjectManager: "graph_id": graph_external_id, "graph_build_task_id": None, "error": None, + "last_simulation_id": last_simulation_id, + "last_report_id": last_report_id, } diff --git a/frontend/src/api/report.js b/frontend/src/api/report.js index 0c340ccc..a4b4150e 100644 --- a/frontend/src/api/report.js +++ b/frontend/src/api/report.js @@ -50,3 +50,11 @@ export const chatWithReport = (data) => { return requestWithRetry(() => service.post('/api/report/chat', data), 3, 1000) } +/** + * Get report by simulation ID + * @param {string} simulationId + */ +export const getReportBySimulation = (simulationId) => { + return service.get(`/api/report/by-simulation/${simulationId}`) +} + diff --git a/frontend/src/components/HistoryDatabase.vue b/frontend/src/components/HistoryDatabase.vue index 19bf4502..1e022baa 100644 --- a/frontend/src/components/HistoryDatabase.vue +++ b/frontend/src/components/HistoryDatabase.vue @@ -44,7 +44,8 @@ :title="$t('history.envSetup')" >◈ @@ -173,7 +174,7 @@