feat: улучшения UI/UX LogBoard+
- Добавлена кнопка Update для управления AJAX auto-update - AJAX auto-update включен по умолчанию - Улучшено управление видимостью кнопки Refresh - Переупорядочены кнопки в header (Update, Refresh) - Унифицированы стили кнопок (высота, шрифт, границы) - Добавлен hover эффект для кнопки options с цветом warning - Позиционирование help-btn в свернутом sidebar - Уменьшена ширина свернутого sidebar на 30% - Добавлена логика разворачивания sidebar при клике на options - Отображение внешнего порта в статусе контейнера - Показ 'standalone' для контейнеров без проекта - Обновлена документация Автор: Сергей Антропов Сайт: https://devops.org.ru
This commit is contained in:
@@ -42,7 +42,7 @@ a{color:var(--link)}
|
||||
}
|
||||
|
||||
.sidebar.collapsed {
|
||||
width: 60px;
|
||||
width: 42px;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .sidebar-header h1,
|
||||
@@ -358,7 +358,7 @@ a{color:var(--link)}
|
||||
}
|
||||
|
||||
.sidebar.collapsed + .sidebar-toggle {
|
||||
left: 60px;
|
||||
left: 42px;
|
||||
}
|
||||
|
||||
.sidebar-toggle:hover {
|
||||
@@ -418,6 +418,16 @@ a{color:var(--link)}
|
||||
.sidebar:not(.collapsed) .help-btn { display: none; }
|
||||
.sidebar.collapsed .help-btn { display: flex; }
|
||||
|
||||
/* При свернутом сайдбаре фиксируем help-btn снизу по центру */
|
||||
.sidebar.collapsed { position: relative; }
|
||||
.sidebar.collapsed .help-btn {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 10px;
|
||||
transform: translateX(-50%);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Компактные контролы в header: по умолчанию скрыты */
|
||||
.header-compact-controls { display: none; align-items: center; gap: 6px; }
|
||||
|
||||
@@ -425,7 +435,6 @@ a{color:var(--link)}
|
||||
|
||||
|
||||
|
||||
.options-btn:hover,
|
||||
.help-btn:hover,
|
||||
.logout-btn:hover {
|
||||
background: var(--tab-active);
|
||||
@@ -433,11 +442,18 @@ a{color:var(--link)}
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
/* Специальный hover эффект для кнопки options с цветом accent */
|
||||
.options-btn:hover {
|
||||
background: var(--accent) !important; /* Цвет логотипа */
|
||||
color: #0b0d12 !important;
|
||||
border-color: var(--accent) !important;
|
||||
}
|
||||
|
||||
/* Кнопка options когда меню открыто (неактивное состояние) */
|
||||
.options-btn:not(.active) {
|
||||
background: var(--accent);
|
||||
background: #e0a800; /* Цвет как у кнопки warning */
|
||||
color: #0b0d12;
|
||||
border-color: var(--accent);
|
||||
border-color: #e0a800;
|
||||
}
|
||||
|
||||
.options-btn.active {
|
||||
@@ -492,6 +508,41 @@ a{color:var(--link)}
|
||||
border-color: #e0af68;
|
||||
}
|
||||
|
||||
/* Кнопка состояния AJAX Update */
|
||||
.ajax-update-btn {
|
||||
background: var(--chip);
|
||||
color: var(--muted);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
padding: 6px 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
font-family: inherit;
|
||||
min-width: 60px;
|
||||
text-align: center;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.ajax-update-btn.ajax-on {
|
||||
background: #7ea855; /* Зеленый цвет */
|
||||
color: white;
|
||||
border-color: #7ea855;
|
||||
}
|
||||
|
||||
.ajax-update-btn.ajax-off {
|
||||
background: #f7768e; /* Красный цвет */
|
||||
color: white;
|
||||
border-color: #f7768e;
|
||||
}
|
||||
|
||||
.ajax-update-btn:hover {
|
||||
opacity: 0.8;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
/* Sidebar Controls */
|
||||
.sidebar-controls {
|
||||
padding: 16px;
|
||||
@@ -808,16 +859,18 @@ a{color:var(--link)}
|
||||
.log-refresh-btn {
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
border: none;
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s ease;
|
||||
padding: 6px 24px;
|
||||
padding: 6px 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: fit-content;
|
||||
min-width: 60px;
|
||||
text-align: center;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.log-refresh-btn:hover {
|
||||
@@ -2140,14 +2193,15 @@ footer{position:fixed;right:10px;bottom:10px;opacity:.6;font-size:11px}
|
||||
<span class="counter-value cother">0</span>
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn btn-small log-refresh-btn" title="Обновить логи и счетчики">
|
||||
<i class="fas fa-sync-alt"></i> Refresh
|
||||
</button>
|
||||
<div class="theme-toggle">
|
||||
<span>Theme</span>
|
||||
<input id="themeSwitch" type="checkbox" />
|
||||
</div>
|
||||
<button id="wsstate" class="ws-status-btn">ws: off</button>
|
||||
<button id="ajaxUpdateBtn" class="ajax-update-btn" title="AJAX Auto-update">update</button>
|
||||
<button class="btn btn-small log-refresh-btn" title="Обновить логи и счетчики">
|
||||
<i class="fas fa-sync-alt"></i> Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2226,6 +2280,7 @@ const els = {
|
||||
|
||||
filter: document.getElementById('filter'),
|
||||
wsstate: document.getElementById('wsstate'),
|
||||
ajaxUpdateBtn: document.getElementById('ajaxUpdateBtn'),
|
||||
projectBadge: document.getElementById('projectBadge'),
|
||||
|
||||
clearBtn: document.getElementById('clear'),
|
||||
@@ -2288,6 +2343,28 @@ function setWsState(s){
|
||||
}
|
||||
}
|
||||
|
||||
function setAjaxUpdateState(enabled) {
|
||||
console.log('setAjaxUpdateState: enabled =', enabled, 'els.ajaxUpdateBtn =', !!els.ajaxUpdateBtn);
|
||||
|
||||
if (els.ajaxUpdateBtn) {
|
||||
// Удаляем все классы состояний
|
||||
els.ajaxUpdateBtn.classList.remove('ajax-on', 'ajax-off');
|
||||
|
||||
// Добавляем соответствующий класс
|
||||
if (enabled) {
|
||||
els.ajaxUpdateBtn.classList.add('ajax-on');
|
||||
els.ajaxUpdateBtn.textContent = 'update';
|
||||
console.log('setAjaxUpdateState: Устанавливаем зеленый цвет (ajax-on)');
|
||||
} else {
|
||||
els.ajaxUpdateBtn.classList.add('ajax-off');
|
||||
els.ajaxUpdateBtn.textContent = 'update';
|
||||
console.log('setAjaxUpdateState: Устанавливаем красный цвет (ajax-off)');
|
||||
}
|
||||
} else {
|
||||
console.error('setAjaxUpdateState: Кнопка ajaxUpdateBtn не найдена!');
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для обновления всех логов при изменении фильтров
|
||||
function refreshAllLogs() {
|
||||
// Обновляем обычный просмотр
|
||||
@@ -2784,11 +2861,12 @@ function buildTabs(){
|
||||
</div>
|
||||
<div class="container-service">
|
||||
${escapeHtml(svc.service || svc.name)}
|
||||
${svc.project ? ` • ${escapeHtml(svc.project)}` : ''}
|
||||
• ${escapeHtml(svc.project || 'standalone')}
|
||||
</div>
|
||||
<div class="container-status">
|
||||
<span class="status-indicator ${statusClass}"></span>
|
||||
${escapeHtml(svc.status)}
|
||||
${svc.status === 'running' && svc.host_port ? ` on ${svc.host_port} port` : ''}
|
||||
${svc.url ? `<a href="${svc.url}" target="_blank" class="container-link" title="Открыть сайт"><i class="fas fa-external-link-alt"></i></a>` : ''}
|
||||
</div>
|
||||
<div class="container-select">
|
||||
@@ -5577,6 +5655,17 @@ els.refreshBtn.onclick = async () => {
|
||||
btn.addEventListener('click', refreshLogsAndCounters);
|
||||
});
|
||||
|
||||
// Обработчик для кнопки update (AJAX autoupdate toggle)
|
||||
if (els.ajaxUpdateBtn) {
|
||||
console.log('Инициализация обработчика клика для кнопки update');
|
||||
els.ajaxUpdateBtn.addEventListener('click', () => {
|
||||
console.log('Клик по кнопке update - вызываем toggleAjaxLogUpdate()');
|
||||
toggleAjaxLogUpdate();
|
||||
});
|
||||
} else {
|
||||
console.error('Кнопка ajaxUpdateBtn не найдена при инициализации обработчика!');
|
||||
}
|
||||
|
||||
// Обработчики для счетчиков
|
||||
function addCounterClickHandlers() {
|
||||
// Назначаем обработчики на все дубликаты кнопок (и в log-header, и в header-compact-controls)
|
||||
@@ -6046,6 +6135,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const isHidden = sidebarControls.classList.contains('hidden');
|
||||
|
||||
if (isHidden) {
|
||||
// Если сайдбар свернут, сначала разворачиваем его
|
||||
if (els.sidebar.classList.contains('collapsed')) {
|
||||
toggleSidebar();
|
||||
}
|
||||
// Показываем настройки
|
||||
sidebarControls.classList.remove('hidden');
|
||||
els.optionsBtn.classList.remove('active');
|
||||
@@ -6708,7 +6801,7 @@ window.addEventListener('keydown', async (e)=>{
|
||||
|
||||
// Глобальные переменные для AJAX обновления
|
||||
let ajaxUpdateInterval = null;
|
||||
let ajaxUpdateEnabled = false;
|
||||
let ajaxUpdateEnabled = true; // По умолчанию включен
|
||||
let ajaxUpdateIntervalMs = 2000; // 2 секунды по умолчанию (будет переопределено из env)
|
||||
|
||||
// Состояние для каждого контейнера (для multi-view)
|
||||
@@ -6741,6 +6834,9 @@ window.addEventListener('keydown', async (e)=>{
|
||||
|
||||
// Обновляем UI
|
||||
updateAjaxUpdateCheckbox();
|
||||
|
||||
// Обновляем видимость кнопки refresh и состояние кнопки update
|
||||
updateRefreshButtonVisibility();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6757,17 +6853,29 @@ window.addEventListener('keydown', async (e)=>{
|
||||
|
||||
// Обновляем UI
|
||||
updateAjaxUpdateCheckbox();
|
||||
|
||||
// Обновляем видимость кнопки refresh и состояние кнопки update
|
||||
updateRefreshButtonVisibility();
|
||||
}
|
||||
|
||||
/**
|
||||
* Переключить состояние AJAX обновления
|
||||
*/
|
||||
function toggleAjaxLogUpdate() {
|
||||
console.log('toggleAjaxLogUpdate: Текущее состояние ajaxUpdateEnabled =', ajaxUpdateEnabled);
|
||||
|
||||
if (ajaxUpdateEnabled) {
|
||||
console.log('toggleAjaxLogUpdate: Отключаем AJAX update');
|
||||
disableAjaxLogUpdate();
|
||||
} else {
|
||||
console.log('toggleAjaxLogUpdate: Включаем AJAX update');
|
||||
enableAjaxLogUpdate(ajaxUpdateIntervalMs);
|
||||
}
|
||||
|
||||
console.log('toggleAjaxLogUpdate: Новое состояние ajaxUpdateEnabled =', ajaxUpdateEnabled);
|
||||
|
||||
// Обновляем видимость кнопки refresh и состояние кнопки update при переключении
|
||||
updateRefreshButtonVisibility();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6979,6 +7087,35 @@ window.addEventListener('keydown', async (e)=>{
|
||||
if (checkbox) {
|
||||
checkbox.checked = ajaxUpdateEnabled;
|
||||
}
|
||||
|
||||
// Обновляем видимость кнопки refresh в зависимости от состояния ajax autoupdate
|
||||
updateRefreshButtonVisibility();
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновить видимость кнопки refresh в header и состояние кнопки update
|
||||
*/
|
||||
function updateRefreshButtonVisibility() {
|
||||
console.log('updateRefreshButtonVisibility: ajaxUpdateEnabled =', ajaxUpdateEnabled);
|
||||
|
||||
const refreshButtons = document.querySelectorAll('.log-refresh-btn');
|
||||
console.log('updateRefreshButtonVisibility: Найдено кнопок refresh =', refreshButtons.length);
|
||||
|
||||
refreshButtons.forEach(btn => {
|
||||
if (ajaxUpdateEnabled) {
|
||||
// Если ajax autoupdate включен, скрываем кнопку refresh
|
||||
btn.style.display = 'none';
|
||||
console.log('updateRefreshButtonVisibility: Скрываем кнопку refresh');
|
||||
} else {
|
||||
// Если ajax autoupdate выключен, показываем кнопку refresh
|
||||
btn.style.display = 'inline-flex';
|
||||
console.log('updateRefreshButtonVisibility: Показываем кнопку refresh');
|
||||
}
|
||||
});
|
||||
|
||||
// Обновляем состояние кнопки update
|
||||
console.log('updateRefreshButtonVisibility: Обновляем состояние кнопки update');
|
||||
setAjaxUpdateState(ajaxUpdateEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7001,12 +7138,18 @@ window.addEventListener('keydown', async (e)=>{
|
||||
} else {
|
||||
disableAjaxLogUpdate();
|
||||
}
|
||||
|
||||
// Обновляем видимость кнопки refresh и состояние кнопки update при изменении состояния чекбокса
|
||||
updateRefreshButtonVisibility();
|
||||
});
|
||||
|
||||
// Устанавливаем начальное состояние (включен по умолчанию)
|
||||
checkbox.checked = true;
|
||||
ajaxUpdateEnabled = true;
|
||||
|
||||
// Обновляем видимость кнопки refresh и состояние кнопки update при инициализации
|
||||
updateRefreshButtonVisibility();
|
||||
|
||||
console.log('AJAX Update Checkbox initialized');
|
||||
}
|
||||
|
||||
@@ -7064,6 +7207,9 @@ window.addEventListener('keydown', async (e)=>{
|
||||
};
|
||||
|
||||
console.log('AJAX обновление логов инициализировано');
|
||||
|
||||
// Обновляем видимость кнопки refresh и состояние кнопки update после инициализации
|
||||
updateRefreshButtonVisibility();
|
||||
}
|
||||
|
||||
// Запускаем инициализацию AJAX обновления
|
||||
|
||||
Reference in New Issue
Block a user