NetAdmin-moduuli: liittymien listaus ja haku

Kokoaa kaikki asiakkaiden liittymät yhteen näkymään haulla ja suodattimilla.
Sarakkeet: asiakas, osoite, kaupunki, nopeus, VLAN, laite, portti, IP, hinta.
Suodattimet: kaupunki, nopeus, laite. Laitetietojen ping-status näkyvissä.
Klikkaus avaa asiakkaan muokkaukseen.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 16:39:24 +02:00
parent e6fa65165e
commit f05313530f
5 changed files with 237 additions and 2 deletions

105
script.js
View File

@@ -200,7 +200,7 @@ async function showDashboard() {
// Avaa oikea tabi URL-hashin perusteella (tai customers oletuks)
const hash = window.location.hash.replace('#', '');
const [mainHash, subHash] = hash.split('/');
const validTabs = ['customers', 'leads', 'tekniikka', 'ohjeet', 'todo', 'documents', 'laitetilat', 'archive', 'changelog', 'support', 'users', 'settings', 'companies'];
const validTabs = ['customers', 'leads', 'tekniikka', 'ohjeet', 'todo', 'documents', 'laitetilat', 'netadmin', 'archive', 'changelog', 'support', 'users', 'settings', 'companies'];
const startTab = validTabs.includes(mainHash) ? mainHash : 'customers';
switchToTab(startTab, subHash);
}
@@ -265,6 +265,7 @@ function switchToTab(target, subTab) {
if (target === 'support') { loadTickets(); showTicketListView(); if (document.getElementById('ticket-auto-refresh').checked) startTicketAutoRefresh(); }
if (target === 'documents') { loadDocuments(); showDocsListView(); }
if (target === 'laitetilat') { loadLaitetilat(); showLaitetilatListView(); }
if (target === 'netadmin') loadNetadmin();
if (target === 'users') loadUsers();
if (target === 'settings') loadSettings();
if (target === 'companies') loadCompaniesTab();
@@ -4394,6 +4395,106 @@ document.getElementById('btn-time-cancel')?.addEventListener('click', () => {
});
document.getElementById('btn-time-save')?.addEventListener('click', () => addTimeEntry());
// ==================== NETADMIN ====================
let netadminData = { connections: [], devices: [] };
async function loadNetadmin() {
try {
netadminData = await apiCall('netadmin_connections');
populateNetadminFilters();
renderNetadminTable();
} catch (e) { console.error('NetAdmin lataus epäonnistui:', e); }
}
function populateNetadminFilters() {
const conns = netadminData.connections || [];
// Kaupungit
const cities = [...new Set(conns.map(c => c.kaupunki).filter(Boolean))].sort();
const citySel = document.getElementById('netadmin-filter-city');
const cityVal = citySel.value;
citySel.innerHTML = '<option value="">Kaikki kaupungit</option>' +
cities.map(c => `<option value="${c}">${esc(c)}</option>`).join('');
citySel.value = cityVal;
// Nopeudet
const speeds = [...new Set(conns.map(c => c.liittymanopeus).filter(Boolean))].sort();
const speedSel = document.getElementById('netadmin-filter-speed');
const speedVal = speedSel.value;
speedSel.innerHTML = '<option value="">Kaikki nopeudet</option>' +
speeds.map(s => `<option value="${s}">${esc(s)}</option>`).join('');
speedSel.value = speedVal;
// Laitteet
const devs = [...new Set(conns.map(c => c.laite).filter(Boolean))].sort();
const devSel = document.getElementById('netadmin-filter-device');
const devVal = devSel.value;
devSel.innerHTML = '<option value="">Kaikki laitteet</option>' +
devs.map(d => `<option value="${d}">${esc(d)}</option>`).join('');
devSel.value = devVal;
}
function renderNetadminTable() {
const query = (document.getElementById('netadmin-search')?.value || '').toLowerCase().trim();
const filterCity = document.getElementById('netadmin-filter-city')?.value || '';
const filterSpeed = document.getElementById('netadmin-filter-speed')?.value || '';
const filterDevice = document.getElementById('netadmin-filter-device')?.value || '';
let filtered = netadminData.connections || [];
if (query) {
filtered = filtered.filter(c => {
const searchStr = [
c.customer_name, c.asennusosoite, c.kaupunki, c.postinumero,
c.liittymanopeus, c.vlan, c.laite, c.portti, c.ip
].filter(Boolean).join(' ').toLowerCase();
return searchStr.includes(query);
});
}
if (filterCity) filtered = filtered.filter(c => c.kaupunki === filterCity);
if (filterSpeed) filtered = filtered.filter(c => c.liittymanopeus === filterSpeed);
if (filterDevice) filtered = filtered.filter(c => c.laite === filterDevice);
const tbody = document.getElementById('netadmin-tbody');
const noEl = document.getElementById('no-netadmin');
const countEl = document.getElementById('netadmin-count');
countEl.textContent = `${filtered.length} / ${(netadminData.connections || []).length} liittymää`;
if (filtered.length === 0) {
tbody.innerHTML = '';
noEl.style.display = '';
return;
}
noEl.style.display = 'none';
tbody.innerHTML = filtered.map(c => {
const addr = c.asennusosoite || '-';
const deviceInfo = c.device_info;
const pingClass = deviceInfo?.ping_status === 'up' ? 'netadmin-status-up' :
deviceInfo?.ping_status === 'down' ? 'netadmin-status-down' : '';
const deviceDisplay = c.laite ? `<span class="${pingClass}">${esc(c.laite)}</span>` : '-';
return `<tr onclick="editCustomer('${c.customer_id}')" style="cursor:pointer;" title="Avaa asiakas">
<td><strong>${esc(c.customer_name || '-')}</strong></td>
<td>${esc(addr)}</td>
<td>${esc(c.kaupunki || '-')}</td>
<td><span class="netadmin-speed">${esc(c.liittymanopeus || '-')}</span></td>
<td>${esc(c.vlan || '-')}</td>
<td>${deviceDisplay}</td>
<td>${esc(c.portti || '-')}</td>
<td><code>${esc(c.ip || '-')}</code></td>
<td class="price-cell">${c.hinta ? parseFloat(c.hinta).toFixed(2) + ' €' : '-'}</td>
</tr>`;
}).join('');
}
document.getElementById('netadmin-search')?.addEventListener('input', renderNetadminTable);
document.getElementById('netadmin-filter-city')?.addEventListener('change', renderNetadminTable);
document.getElementById('netadmin-filter-speed')?.addEventListener('change', renderNetadminTable);
document.getElementById('netadmin-filter-device')?.addEventListener('change', renderNetadminTable);
// ==================== DOKUMENTIT ====================
let allDocuments = [];
@@ -4910,7 +5011,7 @@ document.getElementById('laitetila-edit-form')?.addEventListener('submit', async
// ==================== MODUULIT ====================
const ALL_MODULES = ['customers', 'support', 'leads', 'tekniikka', 'ohjeet', 'todo', 'documents', 'laitetilat', 'archive', 'changelog', 'settings'];
const ALL_MODULES = ['customers', 'support', 'leads', 'tekniikka', 'ohjeet', 'todo', 'documents', 'laitetilat', 'netadmin', 'archive', 'changelog', 'settings'];
const DEFAULT_MODULES = ['customers', 'support', 'archive', 'changelog', 'settings'];
function applyModules(modules) {