588 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
			
		
		
	
	
			588 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
<!DOCTYPE html>
 | 
						|
<html lang="en">
 | 
						|
	<head>
 | 
						|
		<meta charset="UTF-8" />
 | 
						|
		<title>PID Log Viewer</title>
 | 
						|
 | 
						|
		<!-- Link to CSS file -->
 | 
						|
		<link rel="stylesheet" href="/css/style.css" />
 | 
						|
	</head>
 | 
						|
	<body>
 | 
						|
		<div id="logToast" class="toast hidden"></div>
 | 
						|
 | 
						|
		<div class="sidebar">
 | 
						|
			<div class="sidebar-header">
 | 
						|
				<h3>PIDs (<span id="pidCount">0</span>)</h3>
 | 
						|
				<input
 | 
						|
					type="text"
 | 
						|
					id="pidSearch"
 | 
						|
					placeholder="🔍 Search PID..."
 | 
						|
				/>
 | 
						|
			</div>
 | 
						|
			<div class="sidebar-list" id="pidListQuick"></div>
 | 
						|
		</div>
 | 
						|
 | 
						|
		<div class="content">
 | 
						|
			<!-- <h3>📊 PID Log Viewer</h3> -->
 | 
						|
			<div
 | 
						|
				style="
 | 
						|
					margin-bottom: 0.5rem;
 | 
						|
					display: flex;
 | 
						|
					justify-content: end;
 | 
						|
				"
 | 
						|
			>
 | 
						|
				<div class="user-dropdown">
 | 
						|
					<button
 | 
						|
						id="welcome-user"
 | 
						|
						class="user-dropdown-toggle"
 | 
						|
					></button>
 | 
						|
 | 
						|
					<div class="user-dropdown-content">
 | 
						|
						<button onclick="logout()">Logout</button>
 | 
						|
					</div>
 | 
						|
				</div>
 | 
						|
			</div>
 | 
						|
 | 
						|
			<div id="selectAndVersionDiv">
 | 
						|
				<div id="selectedPIDDiv">
 | 
						|
					<label for="pidList">PID</label>
 | 
						|
					<select id="pidList" disabled></select>
 | 
						|
				</div>
 | 
						|
				<div id="selectedVersionDiv">
 | 
						|
					<label for="versionList">Select Version</label>
 | 
						|
					<select id="versionList"></select>
 | 
						|
				</div>
 | 
						|
 | 
						|
				<div style="width: 23%; align-items: center">
 | 
						|
					<button id="copyBtn" class="action-btn">📋 Copy</button>
 | 
						|
					<button id="downloadBtn" class="action-btn">
 | 
						|
						⬇️ Download
 | 
						|
					</button>
 | 
						|
				</div>
 | 
						|
 | 
						|
				<button
 | 
						|
					id="logConfirmDeleteBtn"
 | 
						|
					type="button"
 | 
						|
					class="btn-with-badge danger-btn"
 | 
						|
				>
 | 
						|
					Delete
 | 
						|
					<span class="badge" id="logDeleteBadge">0</span>
 | 
						|
				</button>
 | 
						|
			</div>
 | 
						|
 | 
						|
			<div id="errorTableContainer" class="command-section">
 | 
						|
				<h3>⚠️ Error History for PID</h3>
 | 
						|
				<table border="1" cellspacing="0" cellpadding="5" width="100%">
 | 
						|
					<thead>
 | 
						|
						<tr>
 | 
						|
							<th style="text-align: left">Logging</th>
 | 
						|
							<th style="text-align: left">Pattern</th>
 | 
						|
							<th style="text-align: left">Description</th>
 | 
						|
						</tr>
 | 
						|
					</thead>
 | 
						|
					<tbody id="errorTableBody"></tbody>
 | 
						|
				</table>
 | 
						|
			</div>
 | 
						|
			<div id="logSections"></div>
 | 
						|
 | 
						|
			<!-- Log Delete Modal -->
 | 
						|
			<div id="logDeleteModal" class="modal hidden">
 | 
						|
				<div class="modal-content">
 | 
						|
					<h2 class="modal-title">Confirm Deletion</h2>
 | 
						|
 | 
						|
					<table class="delete-table">
 | 
						|
						<thead>
 | 
						|
							<tr>
 | 
						|
								<th>ID</th>
 | 
						|
								<th>PID</th>
 | 
						|
								<th>Version</th>
 | 
						|
								<th>Command</th>
 | 
						|
								<th style="text-align: center">Action</th>
 | 
						|
							</tr>
 | 
						|
						</thead>
 | 
						|
						<tbody id="logDeleteListContainer"></tbody>
 | 
						|
					</table>
 | 
						|
 | 
						|
					<div class="modal-actions">
 | 
						|
						<button id="logCloseModalBtn" class="btn secondary-btn">
 | 
						|
							Cancel
 | 
						|
						</button>
 | 
						|
						<button id="logSubmitDeleteBtn" class="btn danger-btn">
 | 
						|
							Delete
 | 
						|
						</button>
 | 
						|
					</div>
 | 
						|
				</div>
 | 
						|
			</div>
 | 
						|
		</div>
 | 
						|
 | 
						|
		<script>
 | 
						|
			if (!localStorage.getItem("token")) {
 | 
						|
				logout();
 | 
						|
			}
 | 
						|
 | 
						|
			document.getElementById(
 | 
						|
				"welcome-user",
 | 
						|
			).innerHTML = `Welcome, <strong>${
 | 
						|
				JSON.parse(localStorage.getItem("user")).name
 | 
						|
			}</strong> ▼`;
 | 
						|
 | 
						|
			function logout() {
 | 
						|
				localStorage.removeItem("token");
 | 
						|
				localStorage.removeItem("user");
 | 
						|
				window.location.href = "/login";
 | 
						|
			}
 | 
						|
		</script>
 | 
						|
 | 
						|
		<script>
 | 
						|
			// Get param pid, version from URL
 | 
						|
			const params = new URLSearchParams(window.location.search);
 | 
						|
			const pidParam = params.get("pid");
 | 
						|
			const versionParam = params.get("version");
 | 
						|
 | 
						|
			const pidSearchInput = document.getElementById("pidSearch");
 | 
						|
			const pidList = document.getElementById("pidList");
 | 
						|
			const versionList = document.getElementById("versionList");
 | 
						|
			const pidListQuick = document.getElementById("pidListQuick");
 | 
						|
			const logSections = document.getElementById("logSections");
 | 
						|
			const commands = ["inventory", "version", "license", "logging"];
 | 
						|
 | 
						|
			const logsCache = {}; // Store logs and current index for each command
 | 
						|
 | 
						|
			async function loadPIDs(pidParam, versionParam) {
 | 
						|
				const res = await fetch("/api/pids");
 | 
						|
				const pids = await res.json();
 | 
						|
				document.getElementById("pidCount").textContent = pids.length;
 | 
						|
				pidListQuick.innerHTML = "";
 | 
						|
 | 
						|
				pids.forEach((pid) => {
 | 
						|
					const btn = document.createElement("button");
 | 
						|
					btn.className = "pid-button";
 | 
						|
					btn.textContent = pid;
 | 
						|
					btn.onclick = () => selectPID(pid);
 | 
						|
					pidListQuick.appendChild(btn);
 | 
						|
				});
 | 
						|
 | 
						|
				if (pidParam) {
 | 
						|
					selectPID(pidParam, versionParam);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			async function selectPID(pid, versionParam) {
 | 
						|
				document
 | 
						|
					.querySelectorAll(".pid-button")
 | 
						|
					.forEach((b) => b.classList.remove("selected"));
 | 
						|
				const target = [
 | 
						|
					...document.querySelectorAll(".pid-button"),
 | 
						|
				].find((b) => b.textContent === pid);
 | 
						|
				if (target) target.classList.add("selected");
 | 
						|
 | 
						|
				const res = await fetch(
 | 
						|
					`/api/pid/${encodeURIComponent(pid)}/versions`,
 | 
						|
				);
 | 
						|
				const versions = await res.json();
 | 
						|
 | 
						|
				pidList.innerHTML = `<option value="${pid}">${pid}</option>`;
 | 
						|
				versionList.innerHTML = versions
 | 
						|
					.map((v) => {
 | 
						|
						const cmds = Object.entries(v.commands)
 | 
						|
							.filter(([_, count]) => count > 0)
 | 
						|
							.map(([cmd, count]) => `${cmd} (${count})`)
 | 
						|
							.join(", ");
 | 
						|
						return `<option value="${v.version}">${v.version} - ${
 | 
						|
							cmds || "No commands"
 | 
						|
						}</option>`;
 | 
						|
					})
 | 
						|
					.join("");
 | 
						|
 | 
						|
				// Set param pid, version to URL
 | 
						|
				const currentParams = new URLSearchParams(
 | 
						|
					window.location.search,
 | 
						|
				);
 | 
						|
				currentParams.set("pid", pid);
 | 
						|
 | 
						|
				// Có param version thì chọn
 | 
						|
				if (versionParam) {
 | 
						|
					versionList.value = versionParam;
 | 
						|
					versionList.dispatchEvent(new Event("change"));
 | 
						|
					currentParams.set("version", versionParam);
 | 
						|
				} else {
 | 
						|
					// ✅ Default chọn version đầu tiên
 | 
						|
					if (versions.length > 0) {
 | 
						|
						versionList.value = versions[0].version;
 | 
						|
						versionList.dispatchEvent(new Event("change"));
 | 
						|
						currentParams.set("version", versions[0].version);
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				history.replaceState(null, "", `?${currentParams.toString()}`);
 | 
						|
 | 
						|
				await loadErrorTable(pid);
 | 
						|
			}
 | 
						|
 | 
						|
			pidSearchInput.addEventListener("input", async () => {
 | 
						|
				const keyword = pidSearchInput.value.toLowerCase().trim();
 | 
						|
				const res = await fetch("/api/pids");
 | 
						|
				const pids = await res.json();
 | 
						|
				const filtered = pids.filter((pid) =>
 | 
						|
					pid.toLowerCase().includes(keyword),
 | 
						|
				);
 | 
						|
 | 
						|
				pidListQuick.innerHTML = "";
 | 
						|
				filtered.forEach((pid) => {
 | 
						|
					const btn = document.createElement("button");
 | 
						|
					btn.className = "pid-button";
 | 
						|
					btn.textContent = pid;
 | 
						|
					btn.onclick = () => selectPID(pid);
 | 
						|
					pidListQuick.appendChild(btn);
 | 
						|
				});
 | 
						|
 | 
						|
				pidList.innerHTML = filtered
 | 
						|
					.map((pid) => `<option value="${pid}">${pid}</option>`)
 | 
						|
					.join("");
 | 
						|
				if (filtered.length > 0) {
 | 
						|
					pidList.value = filtered[0];
 | 
						|
					selectPID(filtered[0]);
 | 
						|
				}
 | 
						|
			});
 | 
						|
 | 
						|
			pidList.addEventListener("change", () => {
 | 
						|
				const pid = pidList.value;
 | 
						|
				if (pid) selectPID(pid);
 | 
						|
			});
 | 
						|
 | 
						|
			versionList.addEventListener("change", () => {
 | 
						|
				const pid = pidList.value;
 | 
						|
				const version = versionList.value;
 | 
						|
				if (pid && version) {
 | 
						|
					// Set param pid, version to URL
 | 
						|
					const currentParams = new URLSearchParams(
 | 
						|
						window.location.search,
 | 
						|
					);
 | 
						|
					currentParams.set("pid", pid);
 | 
						|
					currentParams.set("version", version);
 | 
						|
					history.replaceState(
 | 
						|
						null,
 | 
						|
						"",
 | 
						|
						`?${currentParams.toString()}`,
 | 
						|
					);
 | 
						|
 | 
						|
					loadLogs(pid, version);
 | 
						|
				}
 | 
						|
			});
 | 
						|
 | 
						|
			async function loadLogs(pid, version) {
 | 
						|
				logSections.innerHTML = "";
 | 
						|
				logsCache[`${pid}_${version}`] = {};
 | 
						|
 | 
						|
				for (const cmd of commands) {
 | 
						|
					const res = await fetch(
 | 
						|
						`/api/device/${encodeURIComponent(
 | 
						|
							pid,
 | 
						|
						)}/${encodeURIComponent(version)}/${cmd}`,
 | 
						|
					);
 | 
						|
					const data = await res.json();
 | 
						|
					if (!data || data.length === 0) continue;
 | 
						|
 | 
						|
					logsCache[`${pid}_${version}`][cmd] = {
 | 
						|
						logs: data,
 | 
						|
						index: 0,
 | 
						|
					};
 | 
						|
 | 
						|
					const section = document.createElement("div");
 | 
						|
					section.className = "command-section";
 | 
						|
					section.id = `section-${cmd}`;
 | 
						|
					section.innerHTML = `
 | 
						|
            <h3>
 | 
						|
                ${"show " + cmd} (${data.length})
 | 
						|
                <div>
 | 
						|
                <button class="next-btn" id="btn-prev-${cmd}">Previous</button>
 | 
						|
                <span id="page-info-${cmd}">Output 1/${data.length}</span>
 | 
						|
                <button class="next-btn" id="btn-next-${cmd}">Next</button>
 | 
						|
                </div>
 | 
						|
            </h3>
 | 
						|
            <div class="log-block" id="log-${cmd}">
 | 
						|
				<button type="button" class="danger-btn trash-btn" title="Add to delete list">🗑</button>
 | 
						|
                <b>${data[0].filename}</b>\n${data[0].output}
 | 
						|
            </div>
 | 
						|
            `;
 | 
						|
 | 
						|
					logSections.appendChild(section);
 | 
						|
 | 
						|
					// Navigation logic
 | 
						|
					const updateDisplay = () => {
 | 
						|
						const info = logsCache[`${pid}_${version}`][cmd];
 | 
						|
						const curr = info.logs[info.index];
 | 
						|
 | 
						|
						const logBlock = document.getElementById(`log-${cmd}`);
 | 
						|
						logBlock.innerHTML = `
 | 
						|
							<button type="button" class="danger-btn trash-btn" title="Add to delete list">🗑</button>
 | 
						|
							<b>${curr.filename}</b>\n${curr.output}
 | 
						|
						`;
 | 
						|
 | 
						|
						document.getElementById(
 | 
						|
							`page-info-${cmd}`,
 | 
						|
						).textContent = `Output ${info.index + 1}/${
 | 
						|
							info.logs.length
 | 
						|
						}`;
 | 
						|
						document.getElementById(`btn-prev-${cmd}`).disabled =
 | 
						|
							info.index === 0;
 | 
						|
					};
 | 
						|
 | 
						|
					document
 | 
						|
						.getElementById(`btn-next-${cmd}`)
 | 
						|
						.addEventListener("click", () => {
 | 
						|
							const info = logsCache[`${pid}_${version}`][cmd];
 | 
						|
							info.index = (info.index + 1) % info.logs.length;
 | 
						|
							updateDisplay();
 | 
						|
						});
 | 
						|
 | 
						|
					document
 | 
						|
						.getElementById(`btn-prev-${cmd}`)
 | 
						|
						.addEventListener("click", () => {
 | 
						|
							const info = logsCache[`${pid}_${version}`][cmd];
 | 
						|
							info.index =
 | 
						|
								(info.index - 1 + info.logs.length) %
 | 
						|
								info.logs.length;
 | 
						|
							updateDisplay();
 | 
						|
						});
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			loadPIDs(pidParam, versionParam);
 | 
						|
 | 
						|
			const copyBtn = document.getElementById("copyBtn");
 | 
						|
			const downloadBtn = document.getElementById("downloadBtn");
 | 
						|
 | 
						|
			function getExportText() {
 | 
						|
				const pid = pidList.value || "";
 | 
						|
				const version = versionList.value || "";
 | 
						|
				const inventory = getCommandOutput("inventory");
 | 
						|
				const versionOut = getCommandOutput("version");
 | 
						|
				const logging = getCommandOutput("logging");
 | 
						|
				const license = getCommandOutput("license");
 | 
						|
 | 
						|
				return `PID: ${pid}
 | 
						|
Version: ${version}
 | 
						|
 | 
						|
${inventory}
 | 
						|
 | 
						|
${versionOut}
 | 
						|
 | 
						|
${logging}
 | 
						|
 | 
						|
${license}`.trim();
 | 
						|
			}
 | 
						|
 | 
						|
			// Assume you store outputs in memory or fetch based on UI state
 | 
						|
			function getCommandOutput(command) {
 | 
						|
				const pid = pidList.value;
 | 
						|
				const version = versionList.value;
 | 
						|
				const key = `${pid}_${version}`;
 | 
						|
 | 
						|
				if (
 | 
						|
					logsCache[key] &&
 | 
						|
					logsCache[key][command] &&
 | 
						|
					logsCache[key][command].logs.length > 0
 | 
						|
				) {
 | 
						|
					const { logs, index } = logsCache[key][command];
 | 
						|
					return logs[index].output || "";
 | 
						|
				}
 | 
						|
 | 
						|
				return "No data";
 | 
						|
			}
 | 
						|
 | 
						|
			copyBtn.addEventListener("click", async () => {
 | 
						|
				try {
 | 
						|
					await navigator.clipboard.writeText(getExportText());
 | 
						|
					alert("Copied to clipboard!");
 | 
						|
				} catch (err) {
 | 
						|
					alert("Failed to copy.");
 | 
						|
				}
 | 
						|
			});
 | 
						|
 | 
						|
			downloadBtn.addEventListener("click", () => {
 | 
						|
				const content = getExportText();
 | 
						|
				const blob = new Blob([content], { type: "text/plain" });
 | 
						|
				const a = document.createElement("a");
 | 
						|
				a.href = URL.createObjectURL(blob);
 | 
						|
				a.download = `log-${pidList.value || "unknown"}.txt`;
 | 
						|
				a.click();
 | 
						|
			});
 | 
						|
 | 
						|
			async function loadErrorTable(pid) {
 | 
						|
				const res = await fetch(
 | 
						|
					`/api/errors/${encodeURIComponent(pid)}`,
 | 
						|
				);
 | 
						|
				const data = await res.json();
 | 
						|
 | 
						|
				const tbody = document.getElementById("errorTableBody");
 | 
						|
				tbody.innerHTML = "";
 | 
						|
 | 
						|
				if (data.length === 0) {
 | 
						|
					tbody.innerHTML = `<tr><td colspan="5">✅ No known issues for this PID</td></tr>`;
 | 
						|
					return;
 | 
						|
				}
 | 
						|
 | 
						|
				for (const err of data) {
 | 
						|
					const tr = document.createElement("tr");
 | 
						|
					tr.innerHTML = `
 | 
						|
      <td><code>${err.highlighted_message}</code></td>
 | 
						|
      <td><code>${err.regex_pattern}</code></td>
 | 
						|
      <td><code>${err.description}</code></td>
 | 
						|
      `;
 | 
						|
					tbody.appendChild(tr);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		</script>
 | 
						|
 | 
						|
		<script>
 | 
						|
			const STORAGE_KEY = "logDeleteList";
 | 
						|
			const logConfirmDeleteBtn = document.getElementById(
 | 
						|
				"logConfirmDeleteBtn",
 | 
						|
			);
 | 
						|
			const logDeleteModal = document.getElementById("logDeleteModal");
 | 
						|
			const logDeleteListContainer = document.getElementById(
 | 
						|
				"logDeleteListContainer",
 | 
						|
			);
 | 
						|
			const logCloseModalBtn =
 | 
						|
				document.getElementById("logCloseModalBtn");
 | 
						|
			const logSubmitDeleteBtn =
 | 
						|
				document.getElementById("logSubmitDeleteBtn");
 | 
						|
 | 
						|
			function getDeleteList() {
 | 
						|
				return JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]");
 | 
						|
			}
 | 
						|
 | 
						|
			function saveDeleteList(list) {
 | 
						|
				localStorage.setItem(STORAGE_KEY, JSON.stringify(list));
 | 
						|
				updateDeleteBtn();
 | 
						|
			}
 | 
						|
 | 
						|
			function updateDeleteBtn() {
 | 
						|
				const deleteList = getDeleteList();
 | 
						|
				const badge = document.getElementById("logDeleteBadge");
 | 
						|
				badge.textContent = deleteList.length;
 | 
						|
			}
 | 
						|
 | 
						|
			document.addEventListener("click", (e) => {
 | 
						|
				if (e.target.classList.contains("trash-btn")) {
 | 
						|
					const section = e.target.closest(".command-section");
 | 
						|
					const pid = pidList.value;
 | 
						|
					const version = versionList.value;
 | 
						|
					const command = section.id.replace("section-", "");
 | 
						|
					const index = logsCache[`${pid}_${version}`][command].index;
 | 
						|
					const log =
 | 
						|
						logsCache[`${pid}_${version}`][command].logs[index];
 | 
						|
 | 
						|
					const currentList = getDeleteList();
 | 
						|
					if (!currentList.some((item) => item.id === log.id)) {
 | 
						|
						currentList.push({
 | 
						|
							id: log.id,
 | 
						|
							pid,
 | 
						|
							version,
 | 
						|
							command,
 | 
						|
						});
 | 
						|
						saveDeleteList(currentList);
 | 
						|
 | 
						|
						showToast("Added to delete list");
 | 
						|
					}
 | 
						|
				}
 | 
						|
			});
 | 
						|
 | 
						|
			function renderDeleteModal() {
 | 
						|
				const deleteList = getDeleteList();
 | 
						|
				logDeleteListContainer.innerHTML = "";
 | 
						|
				deleteList.forEach((item, i) => {
 | 
						|
					const tr = document.createElement("tr");
 | 
						|
					tr.innerHTML = `
 | 
						|
				<td>${item.id}</td>
 | 
						|
				<td>${item.pid}</td>
 | 
						|
				<td>${item.version}</td>
 | 
						|
				<td>${item.command}</td>
 | 
						|
				<td style="text-align: center;"><button type="button" class="danger-btn remove-item-btn" data-index="${i}" title="Remove">🗑</button></td>
 | 
						|
			`;
 | 
						|
					logDeleteListContainer.appendChild(tr);
 | 
						|
				});
 | 
						|
			}
 | 
						|
 | 
						|
			logDeleteListContainer.addEventListener("click", (e) => {
 | 
						|
				if (e.target.classList.contains("remove-item-btn")) {
 | 
						|
					const index = parseInt(e.target.getAttribute("data-index"));
 | 
						|
					const list = getDeleteList();
 | 
						|
					list.splice(index, 1);
 | 
						|
					saveDeleteList(list);
 | 
						|
					renderDeleteModal();
 | 
						|
				}
 | 
						|
			});
 | 
						|
 | 
						|
			// Open delete modal
 | 
						|
			logConfirmDeleteBtn.addEventListener("click", () => {
 | 
						|
				renderDeleteModal();
 | 
						|
				logDeleteModal.classList.remove("hidden");
 | 
						|
			});
 | 
						|
 | 
						|
			// Open close modal
 | 
						|
			logCloseModalBtn.addEventListener("click", () => {
 | 
						|
				logDeleteModal.classList.add("hidden");
 | 
						|
			});
 | 
						|
 | 
						|
			// Submit delete
 | 
						|
			logSubmitDeleteBtn.addEventListener("click", async () => {
 | 
						|
				const deleteList = getDeleteList();
 | 
						|
				if (deleteList.length === 0) {
 | 
						|
					alert("Please select at least one item to delete.");
 | 
						|
					return;
 | 
						|
				}
 | 
						|
 | 
						|
				if (
 | 
						|
					confirm(
 | 
						|
						`Are you sure you want to delete ${deleteList.length} item(s)?`,
 | 
						|
					)
 | 
						|
				) {
 | 
						|
					const deletedItems = deleteList.map((item) => {
 | 
						|
						return {
 | 
						|
							id: item.id,
 | 
						|
							command: item.command,
 | 
						|
						};
 | 
						|
					});
 | 
						|
 | 
						|
					const token = localStorage.getItem("token");
 | 
						|
 | 
						|
					await fetch("/api/delete-logs", {
 | 
						|
						method: "POST",
 | 
						|
						headers: {
 | 
						|
							"Content-Type": "application/json",
 | 
						|
							Authorization: `Bearer ${token}`,
 | 
						|
						},
 | 
						|
						body: JSON.stringify({ items: deletedItems }),
 | 
						|
					})
 | 
						|
						.then((res) => res.json())
 | 
						|
						.then((data) => {
 | 
						|
							alert("Deleted successfully!");
 | 
						|
							localStorage.removeItem(STORAGE_KEY);
 | 
						|
							location.reload();
 | 
						|
						})
 | 
						|
						.catch((err) => {
 | 
						|
							console.error(err);
 | 
						|
							alert("Delete failed.");
 | 
						|
						});
 | 
						|
				}
 | 
						|
			});
 | 
						|
 | 
						|
			updateDeleteBtn();
 | 
						|
 | 
						|
			function showToast(message = "Announce something") {
 | 
						|
				const toast = document.getElementById("logToast");
 | 
						|
				toast.textContent = message;
 | 
						|
				toast.classList.add("show");
 | 
						|
				toast.classList.remove("hidden");
 | 
						|
 | 
						|
				setTimeout(() => {
 | 
						|
					toast.classList.remove("show");
 | 
						|
					toast.classList.add("hidden");
 | 
						|
				}, 2000);
 | 
						|
			}
 | 
						|
		</script>
 | 
						|
	</body>
 | 
						|
</html>
 |