linklogger/api/templates/dashboard.html
2024-11-10 16:36:16 -06:00

160 lines
5.3 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LinkLogger | Dashboard</title>
<link rel="stylesheet" href="/static/css/dashboard.css">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
<script src="/static/js/jwt.js"></script>
</head>
<body>
<div>
<!-- Create a table with 4 columns with a total of 1000px width -->
<table>
<tr style="border: 2px solid #ccc;">
<th>Link</th>
<th>Visits</th>
<th>Redirect</th>
<th>Expire Date</th>
</tr>
</table>
</div>
</body>
</html>
<script>
function createRow(index, link, logs) {
// Create the sub-table with the logs
let subTable = `
<table>
<tr>
<th>ID</th>
<th>Timestamp</th>
<th>IP</th>
<th>Location</th>
<th colspan="2">ISP</th>
</tr>
`;
// Loop through the logs and create a row for each one
logs.forEach((log, index) => {
let logTimestamp = new Date(log.timestamp).toLocaleString('en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
}).replace(',', '');
let row = `
<tr id="${log.id}-log">
<td>${logs.length - index}</td>
<td>${logTimestamp}</td>
<td>${log.ip}</td>
<td>${log.location}</td>
<td>${log.isp}</td>
<td><i class="fa-solid fa-trash" id="${log.id}/${link.link}""></i></td>
</tr>
`;
subTable += row;
});
subTable += '</table>';
// Convert the link expire timestamp to a readable date
let date = new Date(link.expire_date);
let expireDate = date.toLocaleTimeString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
});
// Create the HTML for the row with sub-table
let row = `
<tr class="link-table-row">
<td>
<button class="link-button" id="${index}">${link.link}</button>
</td>
<td>${logs.length}</td>
<td>${link.redirect_link}</td>
<td>${expireDate}</td>
</tr>
<tr class="log-table-row" id="${index}-logTR" style="display: none;">
<td colspan="6">
${subTable}
</td>
</tr>
`;
return row;
}
async function getData() {
const links = await accessAPI(`/links`, 'GET')
if (!links) {
throw new Error('Failed to fetch links');
}
// Links is an Array of objects with the link data
// Loop through the links and create a row for each one
// Do not use async because then the order or data in the
// table will change from time to time
for (let i = 0; i < links.length; i++) {
let link = links[i];
let logs = await accessAPI(`/links/${link.link}/logs`, 'GET')
if (!logs) {
throw new Error('Failed to fetch logs');
}
let row = createRow(i, link, logs);
document.querySelector('table').innerHTML += row;
}
}
// hideLogRows to all log-table-rows
function hideLogRows() {
let logTRs = document.querySelectorAll('.log-table-row');
logTRs.forEach(row => {
row.style.display = 'none';
});
}
// Add event listener to all link buttons
document.addEventListener('click', (event) => {
if (event.target.classList.contains('link-button')) {
let id = event.target.id;
let logTR = document.getElementById(`${id}-logTR`);
if (logTR.style.display === 'none') {
// Hide any open log tables
hideLogRows();
logTR.style.display = 'table-row';
} else {
logTR.style.display = 'none';
}
}
});
// Add an event listen to all trash bins
document.addEventListener('click', (event) => {
if (event.target.classList.contains('fa-trash')) {
// Confirm the user wants to delete the log
let confirmDelete = confirm('Are you sure you want to delete this log?');
if (confirmDelete) {
let id = event.target.id;
let link = id.split('/')[1];
let logId = id.split('/')[0];
fetch(`/api/links/${link}/logs/${logId}`, {
method: 'DELETE'
});
let logRow = document.getElementById(`${logId}-log`)
logRow.remove();
}
}
});
getData();
</script>