fcsc_ipi_backend/app/views/logs/viewer.ejs
2025-12-30 11:41:07 +05:30

352 lines
8.5 KiB
Plaintext

<!-- views/logs/viewer.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %></title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: #1e1e1e;
color: #d4d4d4;
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
background: #2d2d30;
padding: 15px 20px;
border-bottom: 1px solid #3e3e42;
display: flex;
justify-content: space-between;
align-items: center;
}
.header h1 {
font-size: 18px;
font-weight: 500;
}
.container {
display: flex;
flex: 1;
overflow: hidden;
}
.sidebar {
width: 300px;
background: #252526;
border-right: 1px solid #3e3e42;
overflow-y: auto;
padding: 10px 0;
}
.file-list {
list-style: none;
}
.file-item {
padding: 10px 20px;
cursor: pointer;
transition: background 0.2s;
border-left: 3px solid transparent;
font-size: 13px;
}
.file-item:hover {
background: #2a2d2e;
}
.file-item.active {
background: #37373d;
border-left-color: #007acc;
}
.content-area {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.toolbar {
background: #2d2d30;
padding: 10px 20px;
border-bottom: 1px solid #3e3e42;
display: flex;
gap: 10px;
align-items: center;
}
.toolbar button {
background: #0e639c;
color: white;
border: none;
padding: 6px 12px;
cursor: pointer;
border-radius: 3px;
font-size: 12px;
transition: background 0.2s;
}
.toolbar button:hover {
background: #1177bb;
}
.toolbar input[type="text"] {
background: #3c3c3c;
border: 1px solid #3e3e42;
color: #d4d4d4;
padding: 6px 10px;
border-radius: 3px;
flex: 1;
max-width: 300px;
font-size: 12px;
}
.toolbar input[type="text"]:focus {
outline: none;
border-color: #007acc;
}
.log-content {
flex: 1;
overflow-y: auto;
padding: 20px;
font-family: 'Consolas', 'Courier New', monospace;
font-size: 12px;
line-height: 1.6;
}
.log-line {
padding: 4px 0;
border-bottom: 1px solid #333;
}
.log-line:hover {
background: #2a2d2e;
}
.log-line.error {
color: #f48771;
}
.log-line.warn {
color: #dcdcaa;
}
.log-line.info {
color: #4ec9b0;
}
.empty-state {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
color: #858585;
font-size: 14px;
}
.info-bar {
background: #2d2d30;
padding: 8px 20px;
border-top: 1px solid #3e3e42;
font-size: 11px;
color: #858585;
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: #1e1e1e;
}
::-webkit-scrollbar-thumb {
background: #424242;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: #4e4e4e;
}
.loading {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
color: #858585;
}
</style>
</head>
<body>
<div class="header">
<h1>📋 <%= title %></h1>
<div style="font-size: 12px; color: #858585;">
FCSC_IPI_BACKEND
</div>
</div>
<div class="container">
<aside class="sidebar">
<ul class="file-list" id="fileList">
<% if (logFiles.length === 0) { %>
<li style="padding: 20px; text-align: center; color: #858585;">
No log files found
</li>
<% } else { %>
<% logFiles.forEach((file, index) => { %>
<li class="file-item" data-filename="<%= file %>">
📄 <%= file %>
</li>
<% }); %>
<% } %>
</ul>
</aside>
<main class="content-area">
<div class="toolbar">
<button id="refreshBtn">🔄 Refresh</button>
<button id="downloadBtn" disabled>⬇️ Download</button>
<button id="clearBtn">🗑️ Clear View</button>
<input type="text" id="searchInput" placeholder="Search logs...">
<button id="searchBtn">🔍 Search</button>
</div>
<div class="log-content" id="logContent">
<div class="empty-state">
Select a log file from the sidebar to view its contents
</div>
</div>
<div class="info-bar" id="infoBar">
Ready
</div>
</main>
</div>
<script>
let currentFile = null;
let allLines = [];
// File selection
document.querySelectorAll('.file-item').forEach(item => {
item.addEventListener('click', () => {
document.querySelectorAll('.file-item').forEach(i => i.classList.remove('active'));
item.classList.add('active');
loadLogFile(item.dataset.filename);
});
});
// Load log file
async function loadLogFile(filename) {
currentFile = filename;
const logContent = document.getElementById('logContent');
const downloadBtn = document.getElementById('downloadBtn');
const infoBar = document.getElementById('infoBar');
logContent.innerHTML = '<div class="loading">Loading...</div>';
downloadBtn.disabled = false;
try {
const response = await fetch(`/logs/content/${filename}`);
const data = await response.json();
allLines = data.lines;
displayLines(allLines);
infoBar.textContent = `${filename} - ${data.lineCount} lines`;
} catch (error) {
logContent.innerHTML = '<div class="empty-state">Error loading log file</div>';
console.error('Error:', error);
}
}
// Display lines
function displayLines(lines) {
const logContent = document.getElementById('logContent');
if (lines.length === 0) {
logContent.innerHTML = '<div class="empty-state">No log entries</div>';
return;
}
const html = lines.map(line => {
let className = 'log-line';
if (line.toLowerCase().includes('error')) className += ' error';
else if (line.toLowerCase().includes('warn')) className += ' warn';
else if (line.toLowerCase().includes('info')) className += ' info';
return `<div class="${className}">${escapeHtml(line)}</div>`;
}).join('');
logContent.innerHTML = html;
}
// Search functionality
document.getElementById('searchBtn').addEventListener('click', performSearch);
document.getElementById('searchInput').addEventListener('keypress', (e) => {
if (e.key === 'Enter') performSearch();
});
function performSearch() {
const query = document.getElementById('searchInput').value.toLowerCase();
if (!query) {
displayLines(allLines);
return;
}
const filtered = allLines.filter(line => line.toLowerCase().includes(query));
displayLines(filtered);
document.getElementById('infoBar').textContent =
`Found ${filtered.length} matching lines in ${currentFile}`;
}
// Refresh
document.getElementById('refreshBtn').addEventListener('click', () => {
if (currentFile) loadLogFile(currentFile);
else location.reload();
});
// Download
document.getElementById('downloadBtn').addEventListener('click', () => {
if (currentFile) {
window.location.href = `/logs/download/${currentFile}`;
}
});
// Clear view
document.getElementById('clearBtn').addEventListener('click', () => {
document.getElementById('logContent').innerHTML =
'<div class="empty-state">Select a log file from the sidebar to view its contents</div>';
document.getElementById('searchInput').value = '';
document.getElementById('infoBar').textContent = 'Ready';
document.getElementById('downloadBtn').disabled = true;
document.querySelectorAll('.file-item').forEach(i => i.classList.remove('active'));
currentFile = null;
allLines = [];
});
// Utility function
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
</script>
</body>
</html>