fix delete log #3
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -108,6 +108,10 @@ input[type="text"]:focus {
 | 
			
		|||
	margin-top: 32px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.command-section .log-block.soft-deleted {
 | 
			
		||||
	background-color: #ffd2d2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.command-section h3 {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	justify-content: space-between;
 | 
			
		||||
| 
						 | 
				
			
			@ -370,6 +374,15 @@ mark {
 | 
			
		|||
	text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cancel-trash-btn {
 | 
			
		||||
	font-size: 16px;
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	right: 2px;
 | 
			
		||||
	top: 2px;
 | 
			
		||||
	padding: 8px;
 | 
			
		||||
	text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.remove-item-btn {
 | 
			
		||||
	font-size: 20px;
 | 
			
		||||
	right: 2px;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,7 +115,7 @@
 | 
			
		|||
						<button id="deviceCancelBtn" class="secondary-btn">
 | 
			
		||||
							Cancel
 | 
			
		||||
						</button>
 | 
			
		||||
						<button id="submitDeviceConfirmBtn" class="danger-btn">
 | 
			
		||||
						<button id="submitDeviceConfirmBtn" class="primary-btn">
 | 
			
		||||
							Confirm
 | 
			
		||||
						</button>
 | 
			
		||||
					</div>
 | 
			
		||||
| 
						 | 
				
			
			@ -332,6 +332,9 @@
 | 
			
		|||
			async function loadLogs(pid, version) {
 | 
			
		||||
				logSections.innerHTML = "";
 | 
			
		||||
				logsCache[`${pid}_${version}`] = {};
 | 
			
		||||
				const currentVerUser = versionsUser.find(
 | 
			
		||||
					(verItem) => verItem.version === version,
 | 
			
		||||
				);
 | 
			
		||||
 | 
			
		||||
				for (const cmd of commands) {
 | 
			
		||||
					const res = await fetch(
 | 
			
		||||
| 
						 | 
				
			
			@ -359,8 +362,16 @@
 | 
			
		|||
                <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>
 | 
			
		||||
            <div class="log-block ${
 | 
			
		||||
				data[0].is_deleted ? "soft-deleted" : ""
 | 
			
		||||
			}" id="log-${cmd}">
 | 
			
		||||
		${
 | 
			
		||||
			currentVerUser
 | 
			
		||||
				? ""
 | 
			
		||||
				: data[0].is_deleted
 | 
			
		||||
				? `<button type="button" class="secondary-btn cancel-trash-btn" title="Cancel soft delete">✖️</button>`
 | 
			
		||||
				: `<button type="button" class="danger-btn trash-btn" title="Soft delete">🗑</button>`
 | 
			
		||||
		}
 | 
			
		||||
                <b>${data[0].filename}</b>\n${data[0].output}
 | 
			
		||||
            </div>
 | 
			
		||||
            `;
 | 
			
		||||
| 
						 | 
				
			
			@ -373,10 +384,27 @@
 | 
			
		|||
						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}
 | 
			
		||||
						`;
 | 
			
		||||
						logBlock.className = `log-block ${
 | 
			
		||||
							curr.is_deleted ? "soft-deleted" : ""
 | 
			
		||||
						}`;
 | 
			
		||||
 | 
			
		||||
						const currentVerUser = versionsUser.find(
 | 
			
		||||
							(verItem) => verItem.version === version,
 | 
			
		||||
						);
 | 
			
		||||
 | 
			
		||||
						if (!currentVerUser) {
 | 
			
		||||
							if (curr.is_deleted) {
 | 
			
		||||
								logBlock.innerHTML = `
 | 
			
		||||
									<button type="button" class="secondary-btn cancel-trash-btn" title="Cancel soft delete">✖️</button>
 | 
			
		||||
									<b>${curr.filename}</b>\n${curr.output}
 | 
			
		||||
								`;
 | 
			
		||||
							} else {
 | 
			
		||||
								logBlock.innerHTML = `
 | 
			
		||||
									<button type="button" class="danger-btn trash-btn" title="Soft delete">🗑</button>
 | 
			
		||||
									<b>${curr.filename}</b>\n${curr.output}
 | 
			
		||||
								`;
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						document.getElementById(
 | 
			
		||||
							`page-info-${cmd}`,
 | 
			
		||||
| 
						 | 
				
			
			@ -494,10 +522,15 @@ ${license}`.trim();
 | 
			
		|||
			}
 | 
			
		||||
		</script>
 | 
			
		||||
 | 
			
		||||
		<!-- Handle delete log -->
 | 
			
		||||
		<!-- Handle soft delete log -->
 | 
			
		||||
		<script>
 | 
			
		||||
			let pendingDeleteLog = null;
 | 
			
		||||
 | 
			
		||||
			const logDeleteModal = document.getElementById("logDeleteModal");
 | 
			
		||||
			const logCancelDeleteBtn =
 | 
			
		||||
				document.getElementById("logCancelDeleteBtn");
 | 
			
		||||
			const logDeleteBtn = document.getElementById("logDeleteBtn");
 | 
			
		||||
 | 
			
		||||
			document.addEventListener("click", async (e) => {
 | 
			
		||||
				if (e.target.classList.contains("trash-btn")) {
 | 
			
		||||
					const section = e.target.closest(".command-section");
 | 
			
		||||
| 
						 | 
				
			
			@ -508,19 +541,45 @@ ${license}`.trim();
 | 
			
		|||
					const log =
 | 
			
		||||
						logsCache[`${pid}_${version}`][command].logs[index];
 | 
			
		||||
 | 
			
		||||
					pendingDeleteLog = { id: log.id, command, pid, version };
 | 
			
		||||
					pendingDeleteLog = {
 | 
			
		||||
						id: log.id,
 | 
			
		||||
						command,
 | 
			
		||||
						pid,
 | 
			
		||||
						version,
 | 
			
		||||
						is_deleted: true,
 | 
			
		||||
					};
 | 
			
		||||
 | 
			
		||||
					const text = `Are you sure you want to delete this log? <br /><code>${pid} - ${version} - ${command}</code> <br /> <div style="font-size: 12px; font-weight: 700" >${log.filename}</div>`;
 | 
			
		||||
					const text = `Are you sure you want to <strong>soft delete</strong> this log? <br /><code>${pid} - ${version} - ${command}</code> <br /> <div style="font-size: 12px; font-weight: 700" >${log.filename}</div>`;
 | 
			
		||||
					document.getElementById("deleteLogText").innerHTML = text;
 | 
			
		||||
					logDeleteBtn.innerHTML = "Delete";
 | 
			
		||||
					showDeleteModal();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (e.target.classList.contains("cancel-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];
 | 
			
		||||
 | 
			
		||||
					pendingDeleteLog = {
 | 
			
		||||
						id: log.id,
 | 
			
		||||
						command,
 | 
			
		||||
						pid,
 | 
			
		||||
						version,
 | 
			
		||||
						is_deleted: false,
 | 
			
		||||
					};
 | 
			
		||||
 | 
			
		||||
					const text = `Are you sure you want to <strong>cancel soft delete</strong> this log? <br /><code>${pid} - ${version} - ${command}</code> <br /> <div style="font-size: 12px; font-weight: 700" >${log.filename}</div>`;
 | 
			
		||||
					document.getElementById("deleteLogText").innerHTML = text;
 | 
			
		||||
 | 
			
		||||
					logDeleteBtn.innerHTML = "Cancel Delete";
 | 
			
		||||
					showDeleteModal();
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			const logDeleteModal = document.getElementById("logDeleteModal");
 | 
			
		||||
			const logCancelDeleteBtn =
 | 
			
		||||
				document.getElementById("logCancelDeleteBtn");
 | 
			
		||||
			const logDeleteBtn = document.getElementById("logDeleteBtn");
 | 
			
		||||
 | 
			
		||||
			function showDeleteModal() {
 | 
			
		||||
				logDeleteModal.classList.remove("hidden");
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -536,7 +595,7 @@ ${license}`.trim();
 | 
			
		|||
 | 
			
		||||
				const token = localStorage.getItem("token");
 | 
			
		||||
				try {
 | 
			
		||||
					const res = await fetch("/api/delete-log", {
 | 
			
		||||
					const res = await fetch("/api/soft-delete-log", {
 | 
			
		||||
						method: "POST",
 | 
			
		||||
						headers: {
 | 
			
		||||
							"Content-Type": "application/json",
 | 
			
		||||
| 
						 | 
				
			
			@ -546,10 +605,10 @@ ${license}`.trim();
 | 
			
		|||
					});
 | 
			
		||||
					const data = await res.json();
 | 
			
		||||
					if (data.success) {
 | 
			
		||||
						alert("Deleted successfully!");
 | 
			
		||||
						alert(data.message || "Soft deleted successfully!");
 | 
			
		||||
						location.reload();
 | 
			
		||||
					} else {
 | 
			
		||||
						alert("Delete failed.");
 | 
			
		||||
						alert(data.message || "Delete failed.");
 | 
			
		||||
					}
 | 
			
		||||
				} catch (err) {
 | 
			
		||||
					console.error(err);
 | 
			
		||||
| 
						 | 
				
			
			@ -600,7 +659,7 @@ ${license}`.trim();
 | 
			
		|||
				pendingDevice = { pid, version };
 | 
			
		||||
 | 
			
		||||
				deviceConfirmText.innerHTML = `
 | 
			
		||||
			Are you sure you want to confirm this device?<br />
 | 
			
		||||
			Are you sure you want to <strong>save</strong> these changes?<br />
 | 
			
		||||
			<strong>${pid} - ${version}</strong>
 | 
			
		||||
		`;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										53
									
								
								server.js
								
								
								
								
							
							
						
						
									
										53
									
								
								server.js
								
								
								
								
							| 
						 | 
				
			
			@ -120,6 +120,12 @@ const checkAndInsertAdminUser = async () => {
 | 
			
		|||
        FOREIGN KEY (device_id) REFERENCES devices(id) ON DELETE CASCADE
 | 
			
		||||
      )
 | 
			
		||||
    `);
 | 
			
		||||
 | 
			
		||||
		if (!(await columnExists(`${command}_outputs`, "is_deleted"))) {
 | 
			
		||||
			await db.query(
 | 
			
		||||
				`ALTER TABLE ${command}_outputs ADD COLUMN is_deleted BOOLEAN DEFAULT FALSE`,
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	await createOutputTable("inventory");
 | 
			
		||||
| 
						 | 
				
			
			@ -213,22 +219,23 @@ app.get("/api/device/:pid/:version/:command", async (req, res) => {
 | 
			
		|||
	if (!device) return res.status(404).json({ message: "Not found" });
 | 
			
		||||
 | 
			
		||||
	const [logs] = await db.query(
 | 
			
		||||
		`SELECT id, filename, output, created_at FROM ${command}_outputs WHERE device_id = ? ORDER BY created_at DESC`,
 | 
			
		||||
		`SELECT id, filename, output, created_at, is_deleted FROM ${command}_outputs WHERE device_id = ? ORDER BY created_at DESC`,
 | 
			
		||||
		[device.id],
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	res.json(logs);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
app.post("/api/delete-log", authenticateToken, async (req, res) => {
 | 
			
		||||
app.post("/api/soft-delete-log", authenticateToken, async (req, res) => {
 | 
			
		||||
	const logId = req.body.id;
 | 
			
		||||
	const logCommand = req.body.command;
 | 
			
		||||
	const isDeleted = req.body.is_deleted;
 | 
			
		||||
 | 
			
		||||
	try {
 | 
			
		||||
		if (!logCommand || typeof logId !== "number") {
 | 
			
		||||
			return res
 | 
			
		||||
				.status(400)
 | 
			
		||||
				.json({ success: false, message: "Invalid input" });
 | 
			
		||||
				.json({ success: false, message: "Invalid input." });
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const [rows] = await db.query(
 | 
			
		||||
| 
						 | 
				
			
			@ -239,18 +246,29 @@ app.post("/api/delete-log", authenticateToken, async (req, res) => {
 | 
			
		|||
		if (rows.length === 0) {
 | 
			
		||||
			return res.status(404).json({
 | 
			
		||||
				success: false,
 | 
			
		||||
				message: "Log not found",
 | 
			
		||||
				message: "Log not found.",
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		await db.query(`DELETE FROM \`${logCommand}_outputs\` WHERE id = ?`, [
 | 
			
		||||
			logId,
 | 
			
		||||
		]);
 | 
			
		||||
		await db.query(
 | 
			
		||||
			`UPDATE \`${logCommand}_outputs\` SET is_deleted = ? WHERE id = ?`,
 | 
			
		||||
			[isDeleted, logId],
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		res.json({ success: true });
 | 
			
		||||
		if (isDeleted) {
 | 
			
		||||
			res.json({ success: true, message: "Soft deleted successfully!" });
 | 
			
		||||
		} else {
 | 
			
		||||
			res.json({
 | 
			
		||||
				success: true,
 | 
			
		||||
				message: "Cancel soft deleted successfully!",
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	} catch (error) {
 | 
			
		||||
		console.error("Delete error:", error);
 | 
			
		||||
		res.status(500).json({ success: false, message: "Server error" });
 | 
			
		||||
		res.status(500).json({
 | 
			
		||||
			success: false,
 | 
			
		||||
			message: "Server error, please try again!",
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -268,7 +286,7 @@ app.post("/api/confirm-device", authenticateToken, async (req, res) => {
 | 
			
		|||
	try {
 | 
			
		||||
		// Check if device exists
 | 
			
		||||
		const [rows] = await db.query(
 | 
			
		||||
			`SELECT * FROM devices WHERE pid = ? AND version = ?`,
 | 
			
		||||
			`SELECT id FROM devices WHERE pid = ? AND version = ?`,
 | 
			
		||||
			[pid, version],
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -279,6 +297,7 @@ app.post("/api/confirm-device", authenticateToken, async (req, res) => {
 | 
			
		|||
			});
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const deviceId = rows[0].id;
 | 
			
		||||
		if (rows[0].is_confirmed) {
 | 
			
		||||
			return res.status(400).json({
 | 
			
		||||
				success: false,
 | 
			
		||||
| 
						 | 
				
			
			@ -296,6 +315,20 @@ app.post("/api/confirm-device", authenticateToken, async (req, res) => {
 | 
			
		|||
			[updatedBy, pid, version],
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		// Delete Log
 | 
			
		||||
		const tables = [
 | 
			
		||||
			"inventory_outputs",
 | 
			
		||||
			"version_outputs",
 | 
			
		||||
			"license_outputs",
 | 
			
		||||
			"logging_outputs",
 | 
			
		||||
		];
 | 
			
		||||
		for (const table of tables) {
 | 
			
		||||
			await db.query(
 | 
			
		||||
				`DELETE FROM ${table} WHERE device_id = ? AND is_deleted = TRUE`,
 | 
			
		||||
				[deviceId],
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		await db.query(
 | 
			
		||||
			"UPDATE users SET confirm_count = confirm_count + 1 WHERE id = ?",
 | 
			
		||||
			[updatedBy],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue