import { services as api } from '../api.js';
import { icons } from '../icons.js';
import { navigate } from '../router.js';
function formatTime(dateStr) {
if (!dateStr) return '–';
const d = new Date(dateStr), diff = Math.floor((Date.now() - d) / 60000);
if (diff < 1) return 'ora';
if (diff < 60) return `${diff}m fa`;
const h = Math.floor(diff / 60);
if (h < 24) return `${h}h fa`;
return `${Math.floor(h / 24)}g fa`;
}
function serviceCardHTML(s) {
const status = s.container?.status || s.status || 'stopped';
const repo = s.gitea_repo_url?.replace(/https?:\/\/[^/]+\//, '').replace('.git', '') || '';
const ld = s.last_deploy;
return `
${icons.gitBranch(12)} ${repo} :${s.gitea_branch}
${s.traefik_domain ? `
${icons.globe(12)} ${s.traefik_domain}
` : ''}
${status === 'running' || status === 'error' ? `` : ''}
`;
}
export function renderDashboard(container) {
let interval;
container.innerHTML = `
`;
async function load() {
const grid = document.getElementById('services-grid');
try {
const list = await api.list();
if (list.length === 0) {
grid.innerHTML = `Nessun servizio configurato
Crea il tuo primo servizio per iniziare
`;
return;
}
grid.innerHTML = list.map(serviceCardHTML).join('');
// Events
grid.querySelectorAll('.service-card').forEach(el => {
el.onclick = (e) => { if (!e.target.closest('button')) navigate(`/services/${el.dataset.id}`); };
});
grid.querySelectorAll('.btn-deploy').forEach(b => {
b.onclick = async (e) => { e.stopPropagation(); await api.deploy(b.dataset.id); load(); };
});
grid.querySelectorAll('.btn-stop').forEach(b => {
b.onclick = async (e) => { e.stopPropagation(); await api.stop(b.dataset.id); load(); };
});
} catch (err) { grid.innerHTML = ``; }
}
document.getElementById('refresh-btn').onclick = load;
document.getElementById('create-btn').onclick = () => showCreateModal(load);
load();
interval = setInterval(load, 10000);
return () => clearInterval(interval);
}
function showCreateModal(onCreated) {
const modal = document.getElementById('create-modal');
modal.innerHTML = `
`;
const close = () => { modal.innerHTML = ''; };
document.getElementById('modal-overlay').onclick = close;
document.getElementById('modal-close').onclick = close;
document.getElementById('modal-cancel').onclick = close;
document.getElementById('cf-name').oninput = (e) => {
document.getElementById('cf-container').value = e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, '-');
};
document.getElementById('create-form').onsubmit = async (e) => {
e.preventDefault();
const errEl = document.getElementById('modal-error');
errEl.classList.add('hidden');
try {
const s = await api.create({
name: document.getElementById('cf-name').value,
container_name: document.getElementById('cf-container').value,
description: document.getElementById('cf-desc').value,
gitea_repo_url: document.getElementById('cf-repo').value,
gitea_branch: document.getElementById('cf-branch').value,
container_port: parseInt(document.getElementById('cf-port').value),
traefik_domain: document.getElementById('cf-domain').value,
traefik_enabled: true, traefik_tls_resolver: 'cloudflare',
traefik_network: 'meb-public', networks: ['meb-public'],
});
close();
onCreated();
navigate(`/services/${s.id}`);
} catch (err) {
errEl.textContent = err.message;
errEl.classList.remove('hidden');
}
};
}