fix delete log

This commit is contained in:
dbdbd9 2025-07-28 11:30:21 +07:00
parent e8694be0e2
commit 5c12dcf950
3 changed files with 134 additions and 29 deletions

View File

@ -108,6 +108,10 @@ input[type="text"]:focus {
margin-top: 32px; margin-top: 32px;
} }
.command-section .log-block.soft-deleted {
background-color: #ffd2d2;
}
.command-section h3 { .command-section h3 {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -370,6 +374,15 @@ mark {
text-align: center; text-align: center;
} }
.cancel-trash-btn {
font-size: 16px;
position: absolute;
right: 2px;
top: 2px;
padding: 8px;
text-align: center;
}
.remove-item-btn { .remove-item-btn {
font-size: 20px; font-size: 20px;
right: 2px; right: 2px;

View File

@ -115,7 +115,7 @@
<button id="deviceCancelBtn" class="secondary-btn"> <button id="deviceCancelBtn" class="secondary-btn">
Cancel Cancel
</button> </button>
<button id="submitDeviceConfirmBtn" class="danger-btn"> <button id="submitDeviceConfirmBtn" class="primary-btn">
Confirm Confirm
</button> </button>
</div> </div>
@ -332,6 +332,9 @@
async function loadLogs(pid, version) { async function loadLogs(pid, version) {
logSections.innerHTML = ""; logSections.innerHTML = "";
logsCache[`${pid}_${version}`] = {}; logsCache[`${pid}_${version}`] = {};
const currentVerUser = versionsUser.find(
(verItem) => verItem.version === version,
);
for (const cmd of commands) { for (const cmd of commands) {
const res = await fetch( const res = await fetch(
@ -359,8 +362,16 @@
<button class="next-btn" id="btn-next-${cmd}">Next</button> <button class="next-btn" id="btn-next-${cmd}">Next</button>
</div> </div>
</h3> </h3>
<div class="log-block" id="log-${cmd}"> <div class="log-block ${
<button type="button" class="danger-btn trash-btn" title="Add to delete list">🗑</button> 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} <b>${data[0].filename}</b>\n${data[0].output}
</div> </div>
`; `;
@ -373,10 +384,27 @@
const curr = info.logs[info.index]; const curr = info.logs[info.index];
const logBlock = document.getElementById(`log-${cmd}`); const logBlock = document.getElementById(`log-${cmd}`);
logBlock.innerHTML = ` logBlock.className = `log-block ${
<button type="button" class="danger-btn trash-btn" title="Add to delete list">🗑</button> curr.is_deleted ? "soft-deleted" : ""
<b>${curr.filename}</b>\n${curr.output} }`;
`;
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( document.getElementById(
`page-info-${cmd}`, `page-info-${cmd}`,
@ -494,10 +522,15 @@ ${license}`.trim();
} }
</script> </script>
<!-- Handle delete log --> <!-- Handle soft delete log -->
<script> <script>
let pendingDeleteLog = null; let pendingDeleteLog = null;
const logDeleteModal = document.getElementById("logDeleteModal");
const logCancelDeleteBtn =
document.getElementById("logCancelDeleteBtn");
const logDeleteBtn = document.getElementById("logDeleteBtn");
document.addEventListener("click", async (e) => { document.addEventListener("click", async (e) => {
if (e.target.classList.contains("trash-btn")) { if (e.target.classList.contains("trash-btn")) {
const section = e.target.closest(".command-section"); const section = e.target.closest(".command-section");
@ -508,19 +541,45 @@ ${license}`.trim();
const log = const log =
logsCache[`${pid}_${version}`][command].logs[index]; 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; 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(); showDeleteModal();
} }
}); });
const logDeleteModal = document.getElementById("logDeleteModal");
const logCancelDeleteBtn =
document.getElementById("logCancelDeleteBtn");
const logDeleteBtn = document.getElementById("logDeleteBtn");
function showDeleteModal() { function showDeleteModal() {
logDeleteModal.classList.remove("hidden"); logDeleteModal.classList.remove("hidden");
} }
@ -536,7 +595,7 @@ ${license}`.trim();
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
try { try {
const res = await fetch("/api/delete-log", { const res = await fetch("/api/soft-delete-log", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@ -546,10 +605,10 @@ ${license}`.trim();
}); });
const data = await res.json(); const data = await res.json();
if (data.success) { if (data.success) {
alert("Deleted successfully!"); alert(data.message || "Soft deleted successfully!");
location.reload(); location.reload();
} else { } else {
alert("Delete failed."); alert(data.message || "Delete failed.");
} }
} catch (err) { } catch (err) {
console.error(err); console.error(err);
@ -600,7 +659,7 @@ ${license}`.trim();
pendingDevice = { pid, version }; pendingDevice = { pid, version };
deviceConfirmText.innerHTML = ` 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> <strong>${pid} - ${version}</strong>
`; `;

View File

@ -120,6 +120,12 @@ const checkAndInsertAdminUser = async () => {
FOREIGN KEY (device_id) REFERENCES devices(id) ON DELETE CASCADE 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"); 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" }); if (!device) return res.status(404).json({ message: "Not found" });
const [logs] = await db.query( 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], [device.id],
); );
res.json(logs); 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 logId = req.body.id;
const logCommand = req.body.command; const logCommand = req.body.command;
const isDeleted = req.body.is_deleted;
try { try {
if (!logCommand || typeof logId !== "number") { if (!logCommand || typeof logId !== "number") {
return res return res
.status(400) .status(400)
.json({ success: false, message: "Invalid input" }); .json({ success: false, message: "Invalid input." });
} }
const [rows] = await db.query( const [rows] = await db.query(
@ -239,18 +246,29 @@ app.post("/api/delete-log", authenticateToken, async (req, res) => {
if (rows.length === 0) { if (rows.length === 0) {
return res.status(404).json({ return res.status(404).json({
success: false, success: false,
message: "Log not found", message: "Log not found.",
}); });
} }
await db.query(`DELETE FROM \`${logCommand}_outputs\` WHERE id = ?`, [ await db.query(
logId, `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) { } catch (error) {
console.error("Delete error:", 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 { try {
// Check if device exists // Check if device exists
const [rows] = await db.query( const [rows] = await db.query(
`SELECT * FROM devices WHERE pid = ? AND version = ?`, `SELECT id FROM devices WHERE pid = ? AND version = ?`,
[pid, 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) { if (rows[0].is_confirmed) {
return res.status(400).json({ return res.status(400).json({
success: false, success: false,
@ -296,6 +315,20 @@ app.post("/api/confirm-device", authenticateToken, async (req, res) => {
[updatedBy, pid, version], [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( await db.query(
"UPDATE users SET confirm_count = confirm_count + 1 WHERE id = ?", "UPDATE users SET confirm_count = confirm_count + 1 WHERE id = ?",
[updatedBy], [updatedBy],