Auto-commit local changes before build (2026-03-20 11:04:11)

This commit is contained in:
Ivo Oskamp 2026-03-20 11:04:11 +01:00
parent af84039daf
commit 44214cc2c6
3 changed files with 113 additions and 5 deletions

View File

@ -184,6 +184,54 @@ def inbox_message_detail(message_id: int):
for obj in MailObject.query.filter_by(mail_message_id=msg.id).order_by(MailObject.object_name.asc()).all()
]
# Optional run_id: if provided and the run is a Cloud Connect run, return
# per-run objects (from run_object_links) and a structured CC summary instead
# of the raw MailObject list which contains all tenants from the shared report email.
cloud_connect_summary = None
run_id_param = request.args.get("run_id", type=int)
if run_id_param:
try:
from ..models import JobRun, CloudConnectAccount
from ..database import db
from sqlalchemy import text as _sql_text
_run = JobRun.query.get(run_id_param)
if _run and getattr(_run, "source_type", None) == "cloud_connect" and _run.job_id:
_cc_acc = CloudConnectAccount.query.filter_by(job_id=_run.job_id).first()
if _cc_acc:
cloud_connect_summary = {
"user": _cc_acc.user or "",
"section": _cc_acc.section or "",
"repo_name": _cc_acc.repo_name or "",
"repo_type": _cc_acc.repo_type or "",
"used_space": _cc_acc.used_space or "",
"total_quota": _cc_acc.total_quota or "",
"free_space": _cc_acc.free_space or "",
"last_active": _cc_acc.last_active_raw or "",
"status": _cc_acc.last_status or "",
}
# Replace MailObject list with per-run objects from run_object_links
cc_rows = db.session.execute(
_sql_text("""
SELECT co.object_name AS name, rol.status, rol.error_message
FROM run_object_links rol
JOIN customer_objects co ON co.id = rol.customer_object_id
WHERE rol.run_id = :run_id
ORDER BY co.object_name ASC
"""),
{"run_id": run_id_param},
).mappings().all()
objects = [
{
"name": r["name"] or "",
"type": "",
"status": r["status"] or "",
"error_message": r["error_message"] or "",
}
for r in cc_rows
]
except Exception:
pass # keep MailObject objects as fallback
# VSPC multi-company emails (e.g. "Active alarms summary") may not store parsed objects yet.
# Extract company names from the stored body so the UI can offer a dedicated mapping workflow.
vspc_companies: list[str] = []
@ -227,6 +275,7 @@ def inbox_message_detail(message_id: int):
"meta": meta,
"body_html": body_html,
"objects": objects,
"cloud_connect_summary": cloud_connect_summary,
"vspc_companies": vspc_companies,
"vspc_company_defaults": vspc_company_defaults,
})

View File

@ -258,9 +258,37 @@
<h6 class="mb-1">Details</h6>
<div id="run_msg_overall_message" class="border rounded p-2" style="white-space: pre-wrap; max-height: 20vh; overflow: auto;"></div>
</div>
<div class="border rounded p-2 p-0" style="overflow:hidden;">
<!-- Cloud Connect summary panel (shown instead of raw email for CC runs) -->
<div id="jdm_cc_summary_panel" class="mb-3" style="display:none;">
<h6>Cloud Connect</h6>
<dl class="row mb-0 dl-compact">
<dt class="col-4">User</dt> <dd class="col-8" id="jdm_cc_user"></dd>
<dt class="col-4">Section</dt> <dd class="col-8" id="jdm_cc_section"></dd>
<dt class="col-4">Repository</dt> <dd class="col-8" id="jdm_cc_repo"></dd>
<dt class="col-4">Used / Quota</dt><dd class="col-8" id="jdm_cc_used"></dd>
<dt class="col-4">Free</dt> <dd class="col-8" id="jdm_cc_free"></dd>
<dt class="col-4">Last active</dt> <dd class="col-8" id="jdm_cc_last_active"></dd>
<dt class="col-4">Status</dt> <dd class="col-8" id="jdm_cc_status"></dd>
</dl>
</div>
<div class="mb-3">
<div class="d-flex align-items-center gap-2 mb-1">
<h6 class="mb-0" id="jdm_mail_heading">Mail</h6>
<a href="#" class="small text-muted" id="jdm_mail_toggle" style="display:none;"
onclick="(function(){
var b=document.getElementById('jdm_mail_iframe_body');
var lnk=document.getElementById('jdm_mail_toggle');
var collapsed=b.style.display==='none';
b.style.display=collapsed?'':'none';
lnk.textContent=collapsed?'hide':'show';
})();return false;">show</a>
</div>
<div id="jdm_mail_iframe_body" class="border rounded p-0" style="overflow:hidden;">
<iframe id="run_msg_body_container_iframe" class="w-100" style="height:55vh; border:0; background:transparent;" sandbox="allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation"></iframe>
</div>
</div>
<div class="mt-3">
<div id="run_msg_objects_container">
@ -665,7 +693,9 @@ function renderObjects(objects) {
if (!messageId) return;
currentRunId = runId ? parseInt(runId, 10) : null;
fetch("{{ url_for('main.inbox_message_detail', message_id=0) }}".replace("0", messageId))
var detailUrl = "{{ url_for('main.inbox_message_detail', message_id=0) }}".replace("0", messageId);
if (runId) detailUrl += "?run_id=" + encodeURIComponent(runId);
fetch(detailUrl)
.then(function (resp) {
if (!resp.ok) throw new Error("Failed to load message details");
return resp.json();
@ -727,8 +757,33 @@ function renderObjects(objects) {
}
}
var ccPanel = document.getElementById("jdm_cc_summary_panel");
var mailHeading = document.getElementById("jdm_mail_heading");
var mailToggle = document.getElementById("jdm_mail_toggle");
var mailBody = document.getElementById("jdm_mail_iframe_body");
var bodyFrame = document.getElementById("run_msg_body_container_iframe");
if (data.cloud_connect_summary) {
var s = data.cloud_connect_summary;
document.getElementById("jdm_cc_user").textContent = s.user || "";
document.getElementById("jdm_cc_section").textContent = s.section || "";
document.getElementById("jdm_cc_repo").textContent = s.repo_name + (s.repo_type ? " (" + s.repo_type + ")" : "");
document.getElementById("jdm_cc_used").textContent = (s.used_space || "—") + " / " + (s.total_quota || "—");
document.getElementById("jdm_cc_free").textContent = s.free_space || "—";
document.getElementById("jdm_cc_last_active").textContent = s.last_active || "—";
document.getElementById("jdm_cc_status").textContent = s.status || "—";
if (ccPanel) ccPanel.style.display = "";
if (mailHeading) mailHeading.textContent = "Source report email";
if (mailToggle) { mailToggle.style.display = ""; mailToggle.textContent = "show"; }
if (mailBody) mailBody.style.display = "none";
if (bodyFrame) bodyFrame.srcdoc = wrapMailHtml(data.body_html || "");
} else {
if (ccPanel) ccPanel.style.display = "none";
if (mailHeading) mailHeading.textContent = "Mail";
if (mailToggle) mailToggle.style.display = "none";
if (mailBody) mailBody.style.display = "";
if (bodyFrame) bodyFrame.srcdoc = wrapMailHtml(data.body_html || "");
}
renderObjects(data.objects || []);

View File

@ -5,6 +5,10 @@ This file documents all changes made to this project via Claude Code.
## [2026-03-20]
### Fixed
- Cloud Connect runs in job detail page popup now show a structured CC summary instead of the raw report email with all tenants:
- `routes_inbox.py` (`inbox_message_detail`): accepts optional `?run_id=` parameter; when the run has `source_type = "cloud_connect"`, returns `cloud_connect_summary` dict and per-run objects from `run_object_links` instead of MailObjects
- `job_detail.html`: passes `run_id` to the detail API; if `cloud_connect_summary` is returned, shows the CC summary panel, collapses the raw email (accessible via "show" toggle), and shows only the single per-run repository object
- "Delete all jobs" in Settings → Maintenance no longer times out on large datasets:
- Replaced ORM-based deletion (loaded all jobs/runs into Python memory, deleted object by object) with direct SQL `DELETE FROM` statements in FK order — handles 650K+ rows in seconds
- Added `job_run_review_events` to the FK cleanup sequence (was causing a FK violation)