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:
@@ -100,209 +100,9 @@
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
<script>
|
||||
const scenarios = {{ scenarios | tojson | safe }};
|
||||
const equipmentByScenario = {{ equipment_by_scenario | tojson | safe }};
|
||||
const maintenanceByScenario = {{ maintenance_by_scenario | tojson | safe }};
|
||||
|
||||
const filterSelect = document.getElementById("maintenance-scenario-filter");
|
||||
const tableWrapper = document.getElementById("maintenance-table-wrapper");
|
||||
const tableBody = document.getElementById("maintenance-table-body");
|
||||
const emptyState = document.getElementById("maintenance-empty");
|
||||
const form = document.getElementById("maintenance-form");
|
||||
const feedbackEl = document.getElementById("maintenance-feedback");
|
||||
const formScenarioSelect = document.getElementById("maintenance-form-scenario");
|
||||
const equipmentSelect = document.getElementById("maintenance-form-equipment");
|
||||
const equipmentEmptyState = document.getElementById("maintenance-equipment-empty");
|
||||
|
||||
function showFeedback(message, type = "success") {
|
||||
if (!feedbackEl) {
|
||||
return;
|
||||
}
|
||||
feedbackEl.textContent = message;
|
||||
feedbackEl.classList.remove("hidden", "success", "error");
|
||||
feedbackEl.classList.add(type);
|
||||
}
|
||||
|
||||
function hideFeedback() {
|
||||
if (!feedbackEl) {
|
||||
return;
|
||||
}
|
||||
feedbackEl.classList.add("hidden");
|
||||
feedbackEl.textContent = "";
|
||||
}
|
||||
|
||||
function formatCost(value) {
|
||||
return Number(value).toLocaleString(undefined, {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
}
|
||||
|
||||
function formatDate(value) {
|
||||
if (!value) {
|
||||
return "—";
|
||||
}
|
||||
const parsed = new Date(value);
|
||||
if (Number.isNaN(parsed.getTime())) {
|
||||
return value;
|
||||
}
|
||||
return parsed.toLocaleDateString();
|
||||
}
|
||||
|
||||
function renderMaintenanceRows(scenarioId) {
|
||||
const key = String(scenarioId);
|
||||
const records = maintenanceByScenario[key] || [];
|
||||
|
||||
tableBody.innerHTML = "";
|
||||
|
||||
if (!records.length) {
|
||||
emptyState.textContent = "No maintenance entries recorded for this scenario yet.";
|
||||
emptyState.classList.remove("hidden");
|
||||
tableWrapper.classList.add("hidden");
|
||||
return;
|
||||
}
|
||||
|
||||
emptyState.classList.add("hidden");
|
||||
tableWrapper.classList.remove("hidden");
|
||||
|
||||
records.forEach((record) => {
|
||||
const row = document.createElement("tr");
|
||||
row.innerHTML = `
|
||||
<td>${formatDate(record.maintenance_date)}</td>
|
||||
<td>${record.equipment_name || "—"}</td>
|
||||
<td>${formatCost(record.cost)}</td>
|
||||
<td>${record.description || "—"}</td>
|
||||
`;
|
||||
tableBody.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
function populateEquipmentOptions(scenarioId) {
|
||||
if (!equipmentSelect) {
|
||||
return;
|
||||
}
|
||||
|
||||
equipmentSelect.innerHTML = '<option value="" disabled selected>Select equipment</option>';
|
||||
equipmentSelect.disabled = true;
|
||||
|
||||
if (equipmentEmptyState) {
|
||||
equipmentEmptyState.classList.add("hidden");
|
||||
}
|
||||
|
||||
if (!scenarioId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const list = equipmentByScenario[String(scenarioId)] || [];
|
||||
if (!list.length) {
|
||||
if (equipmentEmptyState) {
|
||||
equipmentEmptyState.textContent = "Add equipment for this scenario before scheduling maintenance.";
|
||||
equipmentEmptyState.classList.remove("hidden");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
list.forEach((item) => {
|
||||
const option = document.createElement("option");
|
||||
option.value = item.id;
|
||||
option.textContent = item.name || `Equipment ${item.id}`;
|
||||
equipmentSelect.appendChild(option);
|
||||
});
|
||||
|
||||
equipmentSelect.disabled = false;
|
||||
}
|
||||
|
||||
if (filterSelect) {
|
||||
filterSelect.addEventListener("change", (event) => {
|
||||
const value = event.target.value;
|
||||
if (!value) {
|
||||
emptyState.textContent = "Choose a scenario to review upcoming or completed maintenance.";
|
||||
emptyState.classList.remove("hidden");
|
||||
tableWrapper.classList.add("hidden");
|
||||
tableBody.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
renderMaintenanceRows(value);
|
||||
});
|
||||
}
|
||||
|
||||
if (formScenarioSelect) {
|
||||
formScenarioSelect.addEventListener("change", (event) => {
|
||||
const value = event.target.value;
|
||||
populateEquipmentOptions(value);
|
||||
});
|
||||
}
|
||||
|
||||
async function submitMaintenance(event) {
|
||||
event.preventDefault();
|
||||
hideFeedback();
|
||||
|
||||
const formData = new FormData(form);
|
||||
const scenarioId = formData.get("scenario_id");
|
||||
const equipmentId = formData.get("equipment_id");
|
||||
const payload = {
|
||||
scenario_id: scenarioId ? Number(scenarioId) : null,
|
||||
equipment_id: equipmentId ? Number(equipmentId) : null,
|
||||
maintenance_date: formData.get("maintenance_date"),
|
||||
cost: Number(formData.get("cost")),
|
||||
description: formData.get("description") || null,
|
||||
};
|
||||
|
||||
if (!payload.scenario_id || !payload.equipment_id) {
|
||||
showFeedback("Select a scenario and equipment before submitting.", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch("/api/maintenance/", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorDetail = await response.json().catch(() => ({}));
|
||||
throw new Error(errorDetail.detail || "Unable to add maintenance entry.");
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
const mapKey = String(result.scenario_id);
|
||||
|
||||
if (!Array.isArray(maintenanceByScenario[mapKey])) {
|
||||
maintenanceByScenario[mapKey] = [];
|
||||
}
|
||||
const equipmentList = equipmentByScenario[mapKey] || [];
|
||||
const matchedEquipment = equipmentList.find(
|
||||
(item) => Number(item.id) === Number(result.equipment_id)
|
||||
);
|
||||
result.equipment_name = matchedEquipment ? matchedEquipment.name : "";
|
||||
maintenanceByScenario[mapKey].push(result);
|
||||
|
||||
form.reset();
|
||||
populateEquipmentOptions(null);
|
||||
showFeedback("Maintenance entry saved.", "success");
|
||||
|
||||
if (filterSelect && filterSelect.value === String(result.scenario_id)) {
|
||||
renderMaintenanceRows(filterSelect.value);
|
||||
}
|
||||
} catch (error) {
|
||||
showFeedback(error.message || "An unexpected error occurred.", "error");
|
||||
}
|
||||
}
|
||||
|
||||
if (form) {
|
||||
form.addEventListener("submit", submitMaintenance);
|
||||
}
|
||||
|
||||
if (filterSelect && filterSelect.value) {
|
||||
renderMaintenanceRows(filterSelect.value);
|
||||
}
|
||||
|
||||
if (formScenarioSelect && formScenarioSelect.value) {
|
||||
populateEquipmentOptions(formScenarioSelect.value);
|
||||
}
|
||||
{% endblock %} {% block scripts %} {{ super() }}
|
||||
<script id="maintenance-data" type="application/json">
|
||||
{{ {"equipment": equipment_by_scenario, "maintenance": maintenance_by_scenario} | tojson }}
|
||||
</script>
|
||||
<script src="/static/js/maintenance.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user