From 1f458004ee2a018cff176c9939a9e8b03425dbfa Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Fri, 25 Sep 2026 20:43:27 +0200 Subject: mass-graduation: add list of submitted changes --- src/graduation-mock.ts | 6 +++- src/graduation-prod.ts | 4 +++ src/mass-graduation.js | 97 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/mock.ts | 12 ++++++- 4 files changed, 115 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/graduation-mock.ts b/src/graduation-mock.ts index 8ddd7ef..a43ab36 100644 --- a/src/graduation-mock.ts +++ b/src/graduation-mock.ts @@ -1,6 +1,9 @@ import { LEVEL_NAMES, GraduationChange, Graduation } from "./graduation-common.ts"; -import { fetchGraduationMock as fetchGraduation } from "./mock.ts"; +import { + fetchGraduationMock as fetchGraduation, + fetchGraduationChangesMock as fetchGraduationChanges, +} from "./mock.ts"; async function submitGraduationChange(c: GraduationChange, g?: Graduation) { if (typeof g !== "undefined") g.addChange(c); @@ -15,6 +18,7 @@ export { GraduationChange, Graduation, fetchGraduation, + fetchGraduationChanges, submitGraduationChange, deleteGraduationChange, }; diff --git a/src/graduation-prod.ts b/src/graduation-prod.ts index 9ded9a8..0e20f8d 100644 --- a/src/graduation-prod.ts +++ b/src/graduation-prod.ts @@ -22,6 +22,10 @@ const _graduationChangesPromise = (async function () { return [studentChanges, universalChanges]; })(); +export async function fetchGraduationChanges() { + return await _graduationChangesPromise; +} + const graduations: Map = new Map(); export async function fetchGraduation(student: Student): Promise { diff --git a/src/mass-graduation.js b/src/mass-graduation.js index 3bce288..ff30675 100644 --- a/src/mass-graduation.js +++ b/src/mass-graduation.js @@ -1,6 +1,11 @@ -import { GraduationChange, submitGraduationChange } from "./graduation-ENV.ts"; +import { + GraduationChange, + fetchGraduationChanges, + submitGraduationChange, + deleteGraduationChange, +} from "./graduation-ENV.ts"; import { fetchStudents } from "./student-ENV.ts"; -import { CourseLocalStorage, getName, splitmix32 } from "./utils-ENV.js"; +import { CourseLocalStorage, DATETIME_FMT, getName, splitmix32 } from "./utils-ENV.js"; let name; @@ -197,11 +202,99 @@ function submitMassGraduation() { }); } +async function loadChanges() { + // TODO(muhq): deduplicate code with cockpit + const changesTbl = document.getElementById("graduation-changes"); + const changes = await fetchGraduationChanges(); + + for (const change of changes) { + if (change.coach !== name) continue; + + const changeTr = document.createElement("tr"); + + switch (change.change) { + case "Grün": + changeTr.style.background = "rgb(from green r g b / 50%)"; + break; + case "Rot": + changeTr.style.background = "rgb(from red r g b / 50%)"; + break; + case "Orange": + changeTr.style.background = "rgb(from orange r g b / 50%)"; + break; + } + + const tds = []; + const addTd = (s) => { + const changeTd = document.createElement("td"); + changeTd.innerHTML = s; + changeTr.appendChild(changeTd); + tds.push(changeTd); + }; + + addTd(change.change); + addTd(DATETIME_FMT.format(change.date)); + addTd(change.reason); + let ctxFmt = ""; + switch (change.change) { + case "CoachZuweisung": + ctxFmt = change.context.zuweisungen[student.id]; + break; + case "LevelÄnderung": + ctxFmt = LEVEL_NAMES[change.context.level]; + break; + case "Grün": + case "Orange": + case "Rot": + ctxFmt = change.context.mandatory ? "erforderlich" : ""; + break; + default: + ctxFmt = JSON.stringify(change.context); + break; + } + addTd(ctxFmt); + + const delBtn = document.createElement("button"); + delBtn.innerHTML = "Löschen"; + + delBtn.addEventListener("click", () => { + const state = document.createElement("span"); + state.classList.add("graduation-delete-state"); + + const inprogress = document.createElement("span"); + inprogress.classList.add("graduation-delete-inprogress"); + state.appendChild(inprogress); + + delBtn.replaceWith(state); + deleteGraduationChange(graduation, change) + .then(() => { + updateStudentInfo(); + state.style.display = "inline"; + state.innerHTML = "✓"; + for (const td of tds) { + td.style["text-decoration"] = "line-through"; + } + }) + .catch(() => { + state.style.display = "inline"; + state.innerHTML = "X"; + }) + .finally(() => { + inprogress.remove(); + }); + }); + changeTr.appendChild(delBtn); + + changesTbl.appendChild(changeTr); + } +} + async function init() { document.getElementById("submit-mass-graduation").addEventListener("click", submitMassGraduation); name = getName(); loadGroup(); + loadChanges(); } if (document.readyState === "loading") { diff --git a/src/mock.ts b/src/mock.ts index f81e901..14d408d 100644 --- a/src/mock.ts +++ b/src/mock.ts @@ -94,4 +94,14 @@ async function fetchGraduationMock(s: Student) { return graduations.get(s); } -export { fetchStudentsMock, fetchSubjectsMock, fetchProgressMock, fetchGraduationMock }; +async function fetchGraduationChangesMock() { + return Array.from(graduations.values().map((g) => g.changes)).flat(); +} + +export { + fetchStudentsMock, + fetchSubjectsMock, + fetchProgressMock, + fetchGraduationMock, + fetchGraduationChangesMock, +}; -- cgit v1.2.3