Refactor templates to externalize JavaScript: Moved inline scripts to separate JS files and added JSON data attributes for better maintainability and performance. Updated consumption, costs, equipment, maintenance, production, reporting, and simulations templates accordingly.
This commit is contained in:
149
static/js/reporting.js
Normal file
149
static/js/reporting.js
Normal file
@@ -0,0 +1,149 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const dataElement = document.getElementById("reporting-data");
|
||||
let reportingSummaries = [];
|
||||
|
||||
if (dataElement) {
|
||||
try {
|
||||
const parsed = JSON.parse(dataElement.textContent || "[]");
|
||||
if (Array.isArray(parsed)) {
|
||||
reportingSummaries = parsed;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Unable to parse reporting data", error);
|
||||
}
|
||||
}
|
||||
|
||||
const REPORT_FIELDS = [
|
||||
{ key: "iterations", label: "Iterations", decimals: 0 },
|
||||
{ key: "mean", label: "Mean Result", decimals: 2 },
|
||||
{ key: "variance", label: "Variance", decimals: 2 },
|
||||
{ key: "std_dev", label: "Std. Dev", decimals: 2 },
|
||||
{ key: "percentile_5", label: "Percentile 5", decimals: 2 },
|
||||
{ key: "percentile_95", label: "Percentile 95", decimals: 2 },
|
||||
{ key: "value_at_risk_95", label: "Value at Risk (95%)", decimals: 2 },
|
||||
{
|
||||
key: "expected_shortfall_95",
|
||||
label: "Expected Shortfall (95%)",
|
||||
decimals: 2,
|
||||
},
|
||||
];
|
||||
|
||||
const tableWrapper = document.getElementById("reporting-table-wrapper");
|
||||
const tableBody = document.getElementById("reporting-table-body");
|
||||
const emptyState = document.getElementById("reporting-empty");
|
||||
const refreshButton = document.getElementById("report-refresh");
|
||||
const feedbackEl = document.getElementById("report-feedback");
|
||||
|
||||
const formatNumber = (value, decimals = 2) => {
|
||||
if (value === null || value === undefined || Number.isNaN(Number(value))) {
|
||||
return "—";
|
||||
}
|
||||
return Number(value).toLocaleString(undefined, {
|
||||
minimumFractionDigits: decimals,
|
||||
maximumFractionDigits: decimals,
|
||||
});
|
||||
};
|
||||
|
||||
const showFeedback = (message, type = "success") => {
|
||||
if (!feedbackEl) {
|
||||
return;
|
||||
}
|
||||
feedbackEl.textContent = message;
|
||||
feedbackEl.classList.remove("hidden", "success", "error");
|
||||
feedbackEl.classList.add(type);
|
||||
};
|
||||
|
||||
const hideFeedback = () => {
|
||||
if (!feedbackEl) {
|
||||
return;
|
||||
}
|
||||
feedbackEl.classList.add("hidden");
|
||||
feedbackEl.textContent = "";
|
||||
};
|
||||
|
||||
const renderReportingTable = (summaryData) => {
|
||||
if (!tableBody || !tableWrapper || !emptyState) {
|
||||
return;
|
||||
}
|
||||
|
||||
tableBody.innerHTML = "";
|
||||
|
||||
if (!summaryData.length) {
|
||||
emptyState.classList.remove("hidden");
|
||||
tableWrapper.classList.add("hidden");
|
||||
return;
|
||||
}
|
||||
|
||||
emptyState.classList.add("hidden");
|
||||
tableWrapper.classList.remove("hidden");
|
||||
|
||||
summaryData.forEach((entry) => {
|
||||
const row = document.createElement("tr");
|
||||
const scenarioCell = document.createElement("td");
|
||||
scenarioCell.textContent = entry.scenario_name;
|
||||
row.appendChild(scenarioCell);
|
||||
|
||||
REPORT_FIELDS.forEach((field) => {
|
||||
const cell = document.createElement("td");
|
||||
const source = field.key === "iterations" ? entry : entry.summary || {};
|
||||
cell.textContent = formatNumber(source[field.key], field.decimals);
|
||||
row.appendChild(cell);
|
||||
});
|
||||
|
||||
tableBody.appendChild(row);
|
||||
});
|
||||
};
|
||||
|
||||
const refreshMetrics = async () => {
|
||||
hideFeedback();
|
||||
showFeedback("Refreshing metrics…", "success");
|
||||
|
||||
try {
|
||||
const response = await fetch("/ui/reporting", {
|
||||
method: "GET",
|
||||
headers: { "X-Requested-With": "XMLHttpRequest" },
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Unable to refresh reporting data.");
|
||||
}
|
||||
|
||||
const text = await response.text();
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(text, "text/html");
|
||||
const newTable = doc.querySelector("#reporting-table-wrapper");
|
||||
const newFeedback = doc.querySelector("#report-feedback");
|
||||
|
||||
if (!newTable) {
|
||||
throw new Error("Unexpected response while refreshing.");
|
||||
}
|
||||
|
||||
const newEmptyState = doc.querySelector("#reporting-empty");
|
||||
|
||||
if (emptyState && newEmptyState) {
|
||||
emptyState.className = newEmptyState.className;
|
||||
emptyState.textContent = newEmptyState.textContent;
|
||||
}
|
||||
|
||||
if (tableWrapper) {
|
||||
tableWrapper.className = newTable.className;
|
||||
tableWrapper.innerHTML = newTable.innerHTML;
|
||||
}
|
||||
|
||||
if (newFeedback && feedbackEl) {
|
||||
feedbackEl.className = newFeedback.className;
|
||||
feedbackEl.textContent = newFeedback.textContent;
|
||||
}
|
||||
|
||||
showFeedback("Metrics refreshed.", "success");
|
||||
} catch (error) {
|
||||
showFeedback(error.message || "An unexpected error occurred.", "error");
|
||||
}
|
||||
};
|
||||
|
||||
renderReportingTable(reportingSummaries);
|
||||
|
||||
if (refreshButton) {
|
||||
refreshButton.addEventListener("click", refreshMetrics);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user