1
0
Fork 0
mirror of https://git.sr.ht/~ashkeel/strimertul-website synced 2024-12-21 23:12:19 +00:00
strimertul-website/static/logviewer.html

127 lines
3.8 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Online log viewer</title>
<style>
@import url("https://rsms.me/inter/inter.css");
@import url("https://iosevka-webfonts.github.io/iosevka/iosevka.css");
:root {
--site-bg: #171717;
--white: #ededed;
background-color: var(--site-bg);
color: var(--white);
font-family: "Inter", "Gill Sans", "Gill Sans MT", "Segoe UI",
sans-serif;
}
html,
body {
margin: 0;
}
main {
display: flex;
}
#starting {
height: 100vh;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
code {
display: inline-block;
font-family: "Iosevka", monospace;
background-color: #222;
border-radius: 3px;
padding: 3px 6px;
}
.hidden {
display: none !important;
}
</style>
</head>
<body>
<main id="app">
<section id="starting">
<h1>Online log viewer</h1>
<p>
Drag a <code>strimertul.log</code> in this window to view it (or click
anywhere to open a file dialog).<br />
The contents will not be uploaded anywhere, this webpage is fully
local.
</p>
</section>
<table id="logs" class="hidden">
<thead>
<tr>
<th>Level</th>
<th>Time</th>
<th>Caller</th>
<th>Message</th>
<th>Data</th>
</tr>
</thead>
<tbody></tbody>
</table>
</main>
<script>
// @ts-check
const mainEl = document.getElementById("app");
const startingEl = document.getElementById("starting");
const tableEl = document.getElementById("logs");
// Click handler (open file select)
startingEl?.addEventListener("click", (ev) => {
// Create temporary file input and click it
const fileSelect = document.createElement("input");
fileSelect.type = "file";
fileSelect.accept = ".log";
fileSelect.addEventListener("change", (ev) => {
if (ev.target instanceof HTMLInputElement && ev.target.files) {
const file = ev.target.files[0];
startingEl.innerHTML = "Loading...";
if (file) {
const reader = new FileReader();
reader.addEventListener("load", (ev) => {
const logs =
ev.target?.result
?.toString()
.split("\n")
.map((line) => line.trim())
.filter((line) => line.length > 0)
.map((line) => {
return makeLog(JSON.parse(line));
}) || [];
tableEl?.querySelector("tbody")?.replaceChildren(...logs);
tableEl?.classList.remove("hidden");
startingEl.classList.add("hidden");
});
reader.readAsText(file);
}
}
});
fileSelect.click();
});
function makeLog(log) {
const tr = document.createElement("tr");
const { level, ts, caller, msg, ...data } = log;
tr.appendChild(makeCell(level));
tr.appendChild(makeCell(new Date(ts * 1000).toISOString()));
tr.appendChild(makeCell(caller));
tr.appendChild(makeCell(msg));
tr.appendChild(makeCell(JSON.stringify(data)));
return tr;
}
function makeCell(text) {
const td = document.createElement("td");
td.appendChild(document.createTextNode(text));
return td;
}
</script>
</body>
</html>