This repository has been archived on 2026-05-11. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
autodeployer-old-version/dashboard/js/pages/logs.js
Giuseppe Raffa 87d698bc5c feat: add Docker and Gitea services, monitoring, queue, and Telegram notification functionalities
- Implemented Docker operations including image building, container management, and resource stats.
- Added Gitea API client for repository management and webhook handling.
- Introduced monitoring service to collect and store container metrics in InfluxDB.
- Created a queue system using BullMQ for managing deployment jobs with real-time log streaming.
- Developed Telegram notification service for deployment status updates.
- Added Traefik label generation for dynamic reverse proxy configuration.
- Implemented WebSocket endpoints for log streaming and terminal access to containers.
- Created an updater sidecar for self-updating the AutoDeployer container.
2026-04-13 23:23:18 +02:00

138 lines
6.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { deploys as deploysApi, createLogSocket } from '../api.js';
import { icons } from '../icons.js';
export function renderLogs(container) {
let deploysList = [];
let selectedDeploy = null;
let logWs = null;
container.innerHTML = `
<div class="page-header"><div><h2>Log Deploy</h2><p>Storico di tutti i deploy con i relativi log</p></div></div>
<div style="display:grid;grid-template-columns:350px 1fr;gap:16px;min-height:500px">
<div class="card" style="overflow:auto;max-height:70vh" id="deploy-list">
<h3 class="card-title mb-4">${icons.scrollText(16)} Deploy Recenti</h3>
<p class="text-muted">Caricamento...</p>
</div>
<div class="card" id="log-panel">
<div class="empty-state">${icons.scrollText(32)}<h3 class="mt-4">Seleziona un deploy</h3><p>Clicca su un deploy nella lista per visualizzarne i log</p></div>
</div>
</div>`;
async function load() {
try {
deploysList = await deploysApi.list();
renderList();
} catch (err) {
document.getElementById('deploy-list').innerHTML = `<p class="text-muted text-sm">Errore: ${err.message}</p>`;
}
}
function renderList() {
const el = document.getElementById('deploy-list');
el.innerHTML = `<h3 class="card-title mb-4">${icons.scrollText(16)} Deploy Recenti</h3>` +
(deploysList.length === 0 ? '<p class="text-muted text-sm">Nessun deploy trovato</p>' :
`<div class="flex flex-col gap-2">${deploysList.map(d => `
<div class="card deploy-item" data-id="${d.id}" style="cursor:pointer;padding:12px 14px;background:${selectedDeploy?.id === d.id ? 'var(--accent-muted)' : 'var(--bg-glass)'};border-color:${selectedDeploy?.id === d.id ? 'rgba(99,102,241,0.3)' : 'var(--border-primary)'}">
<div class="flex items-center justify-between mb-2">
<span class="font-bold text-sm">${d.service_name}</span>
<span class="status-badge ${d.status}">${d.status}</span>
</div>
<div class="flex items-center gap-3 text-xs text-muted">
${d.commit_sha ? `<span class="text-mono">${icons.gitCommit(10)} ${d.commit_sha}</span>` : ''}
<span>${icons.clock(10)} ${new Date(d.created_at).toLocaleString('it-IT')}</span>
</div>
${d.commit_message ? `<p class="text-xs text-muted mt-1 truncate">${esc(d.commit_message)}</p>` : ''}
</div>`).join('')}</div>`);
el.querySelectorAll('.deploy-item').forEach(item => {
item.onclick = () => {
const did = parseInt(item.dataset.id);
selectedDeploy = deploysList.find(d => d.id === did);
renderList();
renderLogPanel();
};
});
}
function renderLogPanel() {
const panel = document.getElementById('log-panel');
if (!selectedDeploy) {
panel.innerHTML = `<div class="empty-state">${icons.scrollText(32)}<h3 class="mt-4">Seleziona un deploy</h3><p>Clicca su un deploy nella lista per visualizzarne i log</p></div>`;
return;
}
if (logWs) { logWs.close(); logWs = null; }
const d = selectedDeploy;
panel.innerHTML = `
<div class="card-header">
<h3 class="card-title">Log: ${d.service_name}</h3>
<span class="status-badge ${d.status}">${d.status}</span>
</div>
<div class="flex gap-4 text-xs text-muted mb-4">
<span>${icons.user(10)} ${d.commit_author || d.trigger}</span>
<span>${icons.gitCommit(10)} ${d.commit_sha || ''}</span>
${d.duration_ms > 0 ? `<span>${icons.clock(10)} ${(d.duration_ms / 1000).toFixed(1)}s</span>` : ''}
</div>
<div class="flex items-center justify-between mb-2">
<span class="text-xs text-muted" id="lv-count">0 righe</span>
<div class="flex gap-2">
<button class="btn btn-secondary btn-sm" id="lv-pause">${icons.pause(12)} Pause</button>
<button class="btn btn-secondary btn-sm" id="lv-download">${icons.download(12)} Download</button>
</div>
</div>
<div class="log-viewer" id="lv-container"><div class="log-line info">In attesa di log...</div></div>`;
let lines = [];
let paused = false;
const lv = panel.querySelector('#lv-container');
logWs = createLogSocket(`deploy:${d.id}`);
logWs.onmessage = (event) => {
try {
const msg = JSON.parse(event.data);
if (msg.type === 'log' || msg.type === 'info' || msg.type === 'error') {
lines.push(msg);
if (lines.length > 2000) lines = lines.slice(-1500);
if (lv.firstChild?.classList?.contains('info') && lines.length === 1) lv.innerHTML = '';
const div = document.createElement('div');
div.className = `log-line ${msg.type}`;
div.textContent = msg.data;
lv.appendChild(div);
panel.querySelector('#lv-count').textContent = `${lines.length} righe`;
if (!paused) lv.scrollTop = lv.scrollHeight;
}
} catch {}
};
logWs.onerror = () => appendLine('error', 'WebSocket connection error');
logWs.onclose = () => appendLine('info', '— Stream ended —');
function appendLine(type, text) {
lines.push({ type, data: text });
const div = document.createElement('div');
div.className = `log-line ${type}`;
div.textContent = text;
lv.appendChild(div);
if (!paused) lv.scrollTop = lv.scrollHeight;
}
panel.querySelector('#lv-pause').onclick = () => {
paused = !paused;
panel.querySelector('#lv-pause').innerHTML = paused ? `${icons.play(12)} Resume` : `${icons.pause(12)} Pause`;
};
panel.querySelector('#lv-download').onclick = () => {
const blob = new Blob([lines.map(l => l.data).join('\n')], { type: 'text/plain' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = `logs-deploy-${d.id}-${Date.now()}.txt`;
a.click();
URL.revokeObjectURL(a.href);
};
}
load();
return () => { if (logWs) logWs.close(); };
}
function esc(s) { return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }