summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorRutger Broekhoff2026-09-22 22:28:10 +0200
committerRutger Broekhoff2026-09-22 22:28:10 +0200
commitecf1be3f834c7187312f8eee71f77e448c995388 (patch)
treeb7018285b815c356c49535c97ace67ac43deeb2d /web
parentae652cab3cf0541173b31273bcec5746a9a81e68 (diff)
downloadroutemon-ecf1be3f834c7187312f8eee71f77e448c995388.tar.gz
routemon-ecf1be3f834c7187312f8eee71f77e448c995388.zip
Check period selection
Diffstat (limited to 'web')
-rw-r--r--web/index.html55
-rw-r--r--web/index.js97
-rw-r--r--web/style.css21
3 files changed, 156 insertions, 17 deletions
diff --git a/web/index.html b/web/index.html
index 877da14..42a61ff 100644
--- a/web/index.html
+++ b/web/index.html
@@ -14,11 +14,57 @@
14 14
15 <form name="gpx-upload-form" class="box"> 15 <form name="gpx-upload-form" class="box">
16 <div> 16 <div>
17 <label for="gpx-file">Upload een GPX-bestand:</label> 17 <label for="gpx-file">GPX-bestand:</label>
18 <input type="file" id="gpx-file-input" name="gpx-file" accept="application/gpx+xml,.gpx" autofocus /> 18 <input type="file" id="gpx-file-input" name="gpx-file" accept="application/gpx+xml,.gpx" required autofocus />
19 </div> 19 </div>
20 <fieldset>
21 <legend>Controleer werkzaamheden gepland in periode</legend>
22 <table class="borderless">
23 <tr>
24 <td>
25 <label for="check-period-begin-preset">Vanaf (incl.):</label>
26 </td>
27 <td>
28 <select name="check-period-begin-preset" id="check-period-begin-preset-select">
29 <option value="-1m">1 maand geleden</option>
30 <option value="-2w">2 weken geleden</option>
31 <option value="-1w" selected>1 week geleden</option>
32 <option value="0">nu</option>
33 <option value="+1w">over 1 week</option>
34 <option value="+2w">over 2 weken</option>
35 <option value="+1m">over 1 maand</option>
36 <option value="custom">een ander moment</option>
37 </select>
38 </td>
39 <td>
40 <input type="datetime-local" id="check-period-begin-input" name="check-period-begin" class="hidden" />
41 </td>
42 </tr>
43 <tr>
44 <td>
45 <label for="check-period-end-preset">Tot (excl.):</label>
46 </td>
47 <td>
48 <select name="check-period-end-preset" id="check-period-end-preset-select">
49 <option value="">aanpassen naar…</option>
50 <option value="-1m">1 maand geleden</option>
51 <option value="+2w">2 weken geleden</option>
52 <option value="-1w">1 week geleden</option>
53 <option value="0">nu</option>
54 <option value="+1w" selected>over 1 week</option>
55 <option value="+2w">over 2 weken</option>
56 <option value="+1m">over 1 maand</option>
57 <option value="custom">een ander moment</option>
58 </select>
59 </td>
60 <td>
61 <input type="datetime-local" id="check-period-end-input" name="check-period-end" class="hidden" />
62 </td>
63 </tr>
64 </table>
65 </fieldset>
20 <div> 66 <div>
21 <input type="submit" value="Opsturen" /> 67 <input type="submit" value="Aanvraag versturen" />
22 </div> 68 </div>
23 </form> 69 </form>
24 70
@@ -38,7 +84,7 @@
38 <dialog class="box"> 84 <dialog class="box">
39 <h3 id="dialog-title"></h3> 85 <h3 id="dialog-title"></h3>
40 <p id="dialog-message"></p> 86 <p id="dialog-message"></p>
41 <details> 87 <details id="dialog-more-info-container">
42 <summary>Meer informatie</summary> 88 <summary>Meer informatie</summary>
43 <small id="dialog-more-info"></small> 89 <small id="dialog-more-info"></small>
44 </details> 90 </details>
@@ -46,6 +92,7 @@
46 </dialog> 92 </dialog>
47 93
48 <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin="anonymous" referrerpolicy="no-referrer"></script> 94 <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
95 <script src="https://cdn.jsdelivr.net/npm/[email protected]/global.min.js"></script>
49 <script src="index.js"></script> 96 <script src="index.js"></script>
50 </body> 97 </body>
51</html> 98</html>
diff --git a/web/index.js b/web/index.js
index e8accf0..63292aa 100644
--- a/web/index.js
+++ b/web/index.js
@@ -7,6 +7,50 @@ closeButton.addEventListener("click", () => {
7 dialog.close(); 7 dialog.close();
8}); 8});
9 9
10function handlePeriodLimitPresetSelInput(selEl, inputEl) {
11 selEl.addEventListener("input", (event) => {
12 if (selEl.value === "custom") {
13 inputEl.classList.remove("hidden");
14 } else {
15 inputEl.classList.add("hidden");
16 }
17 });
18}
19
20function getPeriodLimitPresetSelInput(selEl, inputEl) {
21 const relativeDateTime = (durationArgs) => Temporal.Now.plainDateTimeISO().add(durationArgs);
22
23 let durationArgs = {};
24 switch (selEl.value) {
25 case "-1m": return relativeDateTime({ months: -1 });
26 case "-2w": return relativeDateTime({ weeks: -2 });
27 case "-1w": return relativeDateTime({ weeks: -1 });
28 case "0": return relativeDateTime({ seconds: 0 });
29 case "+1w": return relativeDateTime({ weeks: 1 });
30 case "+2w": return relativeDateTime({ weeks: 2 });
31 case "+1m": return relativeDateTime({ months: 1 });
32 case "custom": return Temporal.PlainDateTime.from(inputEl.value);
33 }
34}
35
36handlePeriodLimitPresetSelInput(
37 document.getElementById("check-period-begin-preset-select"),
38 document.getElementById("check-period-begin-input"));
39handlePeriodLimitPresetSelInput(
40 document.getElementById("check-period-end-preset-select"),
41 document.getElementById("check-period-end-input"));
42
43window.addEventListener("load", (event) => {
44 const oneWeek = Temporal.Duration.from({ weeks: 1 });
45 const now = Temporal.Now.plainDateTimeISO();
46 document.getElementById("check-period-begin-input").value = now.subtract(oneWeek).toString({
47 smallestUnit: "minute",
48 });
49 document.getElementById("check-period-end-input").value = now.add(oneWeek).toString({
50 smallestUnit: "minute",
51 });
52});
53
10let map = L.map("map"); 54let map = L.map("map");
11 55
12L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", { 56L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
@@ -19,10 +63,27 @@ document.forms["gpx-upload-form"].addEventListener("submit", (event) => {
19 event.preventDefault(); 63 event.preventDefault();
20 const gpxFileInput = document.getElementById("gpx-file-input"); 64 const gpxFileInput = document.getElementById("gpx-file-input");
21 if (gpxFileInput.files.length !== 1) { 65 if (gpxFileInput.files.length !== 1) {
22 alert("Voor de upload moet er exact één GPX-bestand zijn geselecteerd"); 66 showDialog({
67 title: "Geen bestand geselecteerd",
68 detail: "Voor de upload moet er exact één GPX-bestand zijn geselecteerd",
69 moreInfoEl: null,
70 });
23 return; 71 return;
24 } 72 }
25 load(gpxFileInput.files[0]); 73
74 const tzidHere = Temporal.Now.timeZoneId();
75 const cpBegin = getPeriodLimitPresetSelInput(document.getElementById("check-period-begin-preset-select"),
76 document.getElementById("check-period-begin-input")).toZonedDateTime(tzidHere).toInstant();
77 const cpEnd = getPeriodLimitPresetSelInput(document.getElementById("check-period-end-preset-select"),
78 document.getElementById("check-period-end-input")).toZonedDateTime(tzidHere).toInstant();
79
80 load({
81 gpxFile: gpxFileInput.files[0],
82 checkPeriod: {
83 begin: cpBegin,
84 end: cpEnd,
85 },
86 });
26}); 87});
27 88
28function el(name, attrs, ...children) { 89function el(name, attrs, ...children) {
@@ -47,15 +108,22 @@ function tbl(rowcols) {
47 )))); 108 ))));
48} 109}
49 110
50async function showProblem(rsp) { 111function showDialog({ title, detail, moreInfoEl }) {
51 const problem = await rsp.json(); 112 document.getElementById("dialog-title").innerText = title;
113 document.getElementById("dialog-message").innerText = detail !== null ? detail : "";
114 if (moreInfoEl !== null) {
115 document.getElementById("dialog-more-info").replaceChildren(moreInfoEl);
116 document.getElementById("dialog-more-info-container").classList.remove("hidden");
117 } else {
118 document.getElementById("dialog-more-info").replaceChildren();
119 document.getElementById("dialog-more-info-container").classList.add("hidden");
120 }
52 121
53 document.getElementById("dialog-title").innerText = problem.title;
54 if (problem.detail)
55 document.getElementById("dialog-message").innerText = problem.detail;
56 else
57 document.getElementById("dialog-message").innerText = "";
58 dialog.showModal(); 122 dialog.showModal();
123}
124
125async function showProblem(rsp) {
126 const problem = await rsp.json();
59 127
60 let rows = [ 128 let rows = [
61 [txt("HTTP-statuscode"), 129 [txt("HTTP-statuscode"),
@@ -70,9 +138,12 @@ async function showProblem(rsp) {
70 rows.push([txt("Instantie"), 138 rows.push([txt("Instantie"),
71 el("code", {}, txt(problem.instance))]); 139 el("code", {}, txt(problem.instance))]);
72 } 140 }
73 document.getElementById("dialog-more-info").replaceChildren(tbl(rows));
74 141
75 return; 142 showDialog({
143 title: problem.title,
144 detail: problem.detail ? problem.detail : null,
145 moreInfoEl: tbl(rows),
146 });
76} 147}
77 148
78async function getSysinfo() { 149async function getSysinfo() {
@@ -101,7 +172,7 @@ async function getSysinfo() {
101 document.getElementById("sysinfo-details").replaceChildren(tbl(rows)); 172 document.getElementById("sysinfo-details").replaceChildren(tbl(rows));
102} 173}
103 174
104async function load(gpxFile) { 175async function load({ gpxFile, checkPeriod }) {
105 let compressedParts = []; 176 let compressedParts = [];
106 const compressedReader = gpxFile.stream().pipeThrough(new CompressionStream("deflate-raw")).getReader(); 177 const compressedReader = gpxFile.stream().pipeThrough(new CompressionStream("deflate-raw")).getReader();
107 while (true) { 178 while (true) {
@@ -113,7 +184,7 @@ async function load(gpxFile) {
113 } 184 }
114 } 185 }
115 186
116 const rsp = await fetch(apiBaseUrl + "/gpx", { 187 const rsp = await fetch(apiBaseUrl + `/gpx?cpbegin=${encodeURI(checkPeriod.begin.toString({ smallestUnit: "minute" }))}&cpend=${encodeURI(checkPeriod.end.toString({ smallestUnit: "minute" }))}`, {
117 method: "POST", 188 method: "POST",
118 headers: { 189 headers: {
119 "Accept-Language": "nl-NL", 190 "Accept-Language": "nl-NL",
diff --git a/web/style.css b/web/style.css
index a96354c..49cc502 100644
--- a/web/style.css
+++ b/web/style.css
@@ -34,15 +34,32 @@ th, td {
34 padding: 5px 5px; 34 padding: 5px 5px;
35} 35}
36 36
37table.borderless,
38table.borderless th,
39table.borderless td {
40 border: none;
41}
42
37form[name="gpx-upload-form"] { 43form[name="gpx-upload-form"] {
38 z-index: 1000; 44 z-index: 1000;
39 display: flex; 45 display: flex;
46 flex-direction: column;
40 gap: 16pt; 47 gap: 16pt;
41 position: absolute; 48 position: absolute;
42 top: 10px; 49 top: 10px;
43 right: 10px; 50 right: 10px;
44} 51}
45 52
53form fieldset {
54 display: flex;
55 flex-direction: column;
56 gap: 5px;
57}
58
59form[name="gpx-upload-form"] input[type="submit"] {
60 float: right;
61}
62
46#sysinfo { 63#sysinfo {
47 z-index: 1000; 64 z-index: 1000;
48 display: flex; 65 display: flex;
@@ -60,3 +77,7 @@ form[name="gpx-upload-form"] {
60.help-cursor { 77.help-cursor {
61 cursor: help; 78 cursor: help;
62} 79}
80
81.hidden {
82 display: none;
83}