@@ -226,6 +226,38 @@ body {
|
||||
border-right: 1px solid var(--border-light);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: all var(--transition-normal);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar.collapsed {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .sidebar-header h3 {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .sidebar-header {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .sidebar-controls {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sidebar.collapsed #refresh-files {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .file-list {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar.collapsed #collapse-sidebar i {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
@@ -236,6 +268,12 @@ body {
|
||||
border-bottom: 1px solid var(--border-light);
|
||||
}
|
||||
|
||||
.sidebar-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.sidebar-header h3 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -549,10 +587,58 @@ input:checked+.slider:before {
|
||||
border-radius: var(--radius-sm);
|
||||
transition: all var(--transition-fast);
|
||||
cursor: pointer;
|
||||
white-space: pre-wrap;
|
||||
white-space: nowrap;
|
||||
word-break: break-all;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
border-left: 3px solid transparent;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.log-line::after {
|
||||
content: " ...";
|
||||
opacity: 0.5;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.log-line.expanded::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.log-line:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.log-line.expanded {
|
||||
background: rgba(37, 99, 235, 0.1);
|
||||
border-left-color: var(--primary-color);
|
||||
white-space: pre-wrap;
|
||||
overflow: visible;
|
||||
text-overflow: unset;
|
||||
animation: expandLine var(--transition-normal) ease-out;
|
||||
}
|
||||
|
||||
@keyframes expandLine {
|
||||
from {
|
||||
max-height: 1.5em;
|
||||
}
|
||||
to {
|
||||
max-height: 1000px;
|
||||
}
|
||||
}
|
||||
|
||||
.log-line.auto-collapse {
|
||||
animation: collapseCountdown 30s linear;
|
||||
}
|
||||
|
||||
@keyframes collapseCountdown {
|
||||
0% {
|
||||
box-shadow: inset 0 -3px 0 var(--primary-color);
|
||||
}
|
||||
100% {
|
||||
box-shadow: inset 0 -3px 0 transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.log-line:hover {
|
||||
@@ -722,6 +808,10 @@ input:checked+.slider:before {
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.sidebar.collapsed {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.nav-content {
|
||||
padding: var(--spacing-md);
|
||||
@@ -754,6 +844,20 @@ input:checked+.slider:before {
|
||||
border-right: none;
|
||||
border-bottom: 1px solid var(--border-light);
|
||||
}
|
||||
|
||||
.sidebar.collapsed {
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .sidebar-header {
|
||||
justify-content: flex-start;
|
||||
padding: var(--spacing-md);
|
||||
}
|
||||
|
||||
.sidebar.collapsed .sidebar-controls {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.nav-info {
|
||||
flex-direction: column;
|
||||
|
||||
@@ -38,9 +38,14 @@
|
||||
<aside class="sidebar" id="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h3><i class="fas fa-folder-open"></i> Available Files</h3>
|
||||
<button id="refresh-files" class="btn btn-icon" title="Refresh file list">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
</button>
|
||||
<div class="sidebar-controls">
|
||||
<button id="collapse-sidebar" class="btn btn-icon" title="Collapse sidebar">
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
</button>
|
||||
<button id="refresh-files" class="btn btn-icon" title="Refresh file list">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="file-list" id="file-list">
|
||||
<div class="loading">
|
||||
|
||||
@@ -47,6 +47,8 @@ class LogTailMonitor {
|
||||
// Sidebar
|
||||
fileList: document.getElementById('file-list'),
|
||||
refreshFilesBtn: document.getElementById('refresh-files'),
|
||||
collapseSidebarBtn: document.getElementById('collapse-sidebar'),
|
||||
sidebar: document.getElementById('sidebar'),
|
||||
|
||||
// Controls
|
||||
autoScrollToggle: document.getElementById('auto-scroll'),
|
||||
@@ -74,8 +76,9 @@ class LogTailMonitor {
|
||||
* Bind event listeners
|
||||
*/
|
||||
bindEvents() {
|
||||
// File refresh
|
||||
// File refresh and sidebar collapse
|
||||
this.elements.refreshFilesBtn.addEventListener('click', () => this.loadFiles());
|
||||
this.elements.collapseSidebarBtn.addEventListener('click', () => this.toggleSidebar());
|
||||
|
||||
// Controls
|
||||
this.elements.autoScrollToggle.addEventListener('change', (e) => {
|
||||
@@ -148,6 +151,23 @@ class LogTailMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle sidebar visibility
|
||||
*/
|
||||
toggleSidebar() {
|
||||
this.elements.sidebar.classList.toggle('collapsed');
|
||||
const isCollapsed = this.elements.sidebar.classList.contains('collapsed');
|
||||
const icon = this.elements.collapseSidebarBtn.querySelector('i');
|
||||
|
||||
if (isCollapsed) {
|
||||
icon.className = 'fas fa-chevron-right';
|
||||
this.elements.collapseSidebarBtn.title = 'Expand sidebar';
|
||||
} else {
|
||||
icon.className = 'fas fa-chevron-left';
|
||||
this.elements.collapseSidebarBtn.title = 'Collapse sidebar';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load available files from the server
|
||||
*/
|
||||
@@ -391,18 +411,37 @@ class LogTailMonitor {
|
||||
// Classify log level
|
||||
this.classifyLogLine(logLine, content);
|
||||
|
||||
// Store timeout reference for cleanup
|
||||
let collapseTimeout = null;
|
||||
|
||||
// Add click handler for expansion
|
||||
logLine.addEventListener('click', () => {
|
||||
logLine.classList.toggle('expanded');
|
||||
this.elements.autoScrollToggle.checked = false;
|
||||
this.autoScroll = false;
|
||||
const wasExpanded = logLine.classList.contains('expanded');
|
||||
|
||||
// Auto-collapse after 20 seconds
|
||||
setTimeout(() => {
|
||||
logLine.classList.remove('expanded');
|
||||
this.elements.autoScrollToggle.checked = true;
|
||||
this.autoScroll = true;
|
||||
}, 20000);
|
||||
if (wasExpanded) {
|
||||
// Collapse manually
|
||||
logLine.classList.remove('expanded', 'auto-collapse');
|
||||
if (collapseTimeout) {
|
||||
clearTimeout(collapseTimeout);
|
||||
collapseTimeout = null;
|
||||
}
|
||||
} else {
|
||||
// Expand
|
||||
logLine.classList.add('expanded');
|
||||
this.elements.autoScrollToggle.checked = false;
|
||||
this.autoScroll = false;
|
||||
|
||||
// Add visual countdown indicator
|
||||
logLine.classList.add('auto-collapse');
|
||||
|
||||
// Auto-collapse after 30 seconds
|
||||
collapseTimeout = setTimeout(() => {
|
||||
logLine.classList.remove('expanded', 'auto-collapse');
|
||||
this.elements.autoScrollToggle.checked = true;
|
||||
this.autoScroll = true;
|
||||
collapseTimeout = null;
|
||||
}, 30000);
|
||||
}
|
||||
});
|
||||
|
||||
return logLine;
|
||||
|
||||
Referencia en una nueva incidencia
Block a user