feat (ui): Light/Dark Theme added Complete
This commit is contained in:
@@ -219,6 +219,9 @@ async function fetchContainers() {
|
||||
|
||||
const list = Array.isArray(containers) ? containers : (containers?.containers || []);
|
||||
document.getElementById('countContainers').textContent = list.length;
|
||||
if (typeof window.updateNavCount === 'function') {
|
||||
window.updateNavCount('countNavContainers', list.length);
|
||||
}
|
||||
|
||||
const podsList = Array.isArray(pods) ? pods : [];
|
||||
const podStatus = {};
|
||||
|
||||
@@ -159,7 +159,19 @@ async function filesRefresh() {
|
||||
const treeEl = document.getElementById('filesTree');
|
||||
treeEl.textContent = 'Laden...';
|
||||
|
||||
const data = await api('/files/tree', 'GET');
|
||||
let data;
|
||||
try {
|
||||
data = await api('/files/tree', 'GET');
|
||||
} catch (e) {
|
||||
if (typeof window.updateNavCount === 'function') {
|
||||
window.updateNavCount('countNavFiles', 0);
|
||||
}
|
||||
treeEl.innerHTML = (typeof window.renderStateBox === 'function')
|
||||
? window.renderStateBox('error', 'Files laden mislukt', e.message || String(e))
|
||||
: 'Files laden mislukt.';
|
||||
filesUpdateEditorStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter alleen systemd subtree
|
||||
const scoped = (data || []).filter(folder => {
|
||||
@@ -168,10 +180,24 @@ async function filesRefresh() {
|
||||
});
|
||||
|
||||
if (!scoped.length) {
|
||||
treeEl.textContent = 'Geen bestanden gevonden onder systemd.';
|
||||
if (typeof window.updateNavCount === 'function') {
|
||||
window.updateNavCount('countNavFiles', 0);
|
||||
}
|
||||
treeEl.innerHTML = (typeof window.renderStateBox === 'function')
|
||||
? window.renderStateBox('empty', 'Geen bestanden', 'Er zijn geen bestanden gevonden onder systemd.')
|
||||
: 'Geen bestanden gevonden onder systemd.';
|
||||
filesUpdateEditorStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
let totalFiles = 0;
|
||||
for (const folder of scoped) {
|
||||
totalFiles += Array.isArray(folder?.files) ? folder.files.length : 0;
|
||||
}
|
||||
if (typeof window.updateNavCount === 'function') {
|
||||
window.updateNavCount('countNavFiles', totalFiles);
|
||||
}
|
||||
|
||||
// Bouw een geneste folder-tree uit de "platte" API response.
|
||||
const folderByPath = new Map();
|
||||
for (const f of scoped) {
|
||||
|
||||
@@ -2,18 +2,44 @@ let imagesData = [];
|
||||
let imagesSort = { field: null, dir: null };
|
||||
|
||||
async function loadImages() {
|
||||
const res = await fetch("/api/images");
|
||||
const images = await res.json();
|
||||
const tbody = document.getElementById("images-tbody");
|
||||
try {
|
||||
const res = await fetch("/api/images");
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const images = await res.json();
|
||||
|
||||
imagesData = images;
|
||||
updateSortIndicators();
|
||||
applyImageSorting();
|
||||
imagesData = Array.isArray(images) ? images : [];
|
||||
if (typeof window.updateNavCount === "function") {
|
||||
window.updateNavCount("countNavImages", imagesData.length);
|
||||
}
|
||||
updateSortIndicators();
|
||||
applyImageSorting();
|
||||
} catch (e) {
|
||||
imagesData = [];
|
||||
if (typeof window.updateNavCount === "function") {
|
||||
window.updateNavCount("countNavImages", 0);
|
||||
}
|
||||
if (tbody) {
|
||||
const box = (typeof window.renderStateBox === "function")
|
||||
? window.renderStateBox("error", "Images laden mislukt", e.message || String(e))
|
||||
: "Images laden mislukt.";
|
||||
tbody.innerHTML = `<tr><td colspan="8">${box}</td></tr>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderImages(images) {
|
||||
const tbody = document.getElementById("images-tbody");
|
||||
tbody.innerHTML = "";
|
||||
|
||||
if (!images.length) {
|
||||
const box = (typeof window.renderStateBox === "function")
|
||||
? window.renderStateBox("empty", "Geen images", "Er zijn momenteel geen images gevonden.")
|
||||
: "Geen images gevonden.";
|
||||
tbody.innerHTML = `<tr><td colspan="8">${box}</td></tr>`;
|
||||
return;
|
||||
}
|
||||
|
||||
images.forEach(img => {
|
||||
const tr = document.createElement("tr");
|
||||
|
||||
|
||||
@@ -96,11 +96,18 @@
|
||||
]);
|
||||
state.usage = usage;
|
||||
state.list = list;
|
||||
if (typeof window.updateNavCount === 'function') {
|
||||
const n = Array.isArray(list?.networks) ? list.networks.length : 0;
|
||||
window.updateNavCount('countNavNetworks', n);
|
||||
}
|
||||
if (statusEl) statusEl.textContent = `Laatst geladen: ${new Date().toLocaleString()}`;
|
||||
renderNetworksSummary();
|
||||
renderNetworks();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (typeof window.updateNavCount === 'function') {
|
||||
window.updateNavCount('countNavNetworks', 0);
|
||||
}
|
||||
if (statusEl) statusEl.textContent = 'Fout: ' + (e?.message || e);
|
||||
}
|
||||
}
|
||||
@@ -620,6 +627,10 @@
|
||||
|
||||
// leeg host (placeholder weg)
|
||||
host.innerHTML = '';
|
||||
const tooltip = document.createElement('div');
|
||||
tooltip.className = 'mapTooltip';
|
||||
tooltip.style.display = 'none';
|
||||
host.appendChild(tooltip);
|
||||
|
||||
const w = Math.max(600, host.clientWidth || 600);
|
||||
const h = Math.max(420, host.clientHeight || 420);
|
||||
@@ -694,11 +705,27 @@
|
||||
d3.select(this).classed('graphActive', false);
|
||||
}
|
||||
});
|
||||
|
||||
const typeLabel = d.type === 'network' ? 'Netwerk' : 'Container';
|
||||
const extra = d.type === 'network'
|
||||
? `Driver: ${d?.meta?.driver || 'onbekend'}`
|
||||
: (d?.pod ? `Pod: ${d.pod}` : 'Pod: -');
|
||||
tooltip.innerHTML = `<strong>${typeLabel}</strong><br>${d.label || d.key}<br>${extra}`;
|
||||
tooltip.style.display = 'block';
|
||||
});
|
||||
|
||||
node.on('mousemove', (ev) => {
|
||||
const rect = host.getBoundingClientRect();
|
||||
const x = (ev.clientX - rect.left) + 14;
|
||||
const y = (ev.clientY - rect.top) + 14;
|
||||
tooltip.style.left = `${x}px`;
|
||||
tooltip.style.top = `${y}px`;
|
||||
});
|
||||
|
||||
node.on('mouseleave', () => {
|
||||
node.classed('graphDim', false);
|
||||
link.classed('graphDim', false).classed('graphActive', false);
|
||||
tooltip.style.display = 'none';
|
||||
});
|
||||
|
||||
node.on('click', (ev, d) => {
|
||||
@@ -822,13 +849,24 @@
|
||||
|
||||
const usage = state.usage;
|
||||
if (!usage || !usage.byNetwork) {
|
||||
tbody.innerHTML = `<tr><td colspan="6" class="muted">Geen data. Klik op Vernieuwen.</td></tr>`;
|
||||
rel.innerHTML = `<div class="muted">Geen data.</div>`;
|
||||
const box = (typeof window.renderStateBox === 'function')
|
||||
? window.renderStateBox('empty', 'Geen netwerkdata', 'Klik op Vernieuwen om netwerkdata op te halen.')
|
||||
: 'Geen data.';
|
||||
tbody.innerHTML = `<tr><td colspan="6">${box}</td></tr>`;
|
||||
rel.innerHTML = box;
|
||||
return;
|
||||
}
|
||||
|
||||
const vmAll = buildNetworksViewModel();
|
||||
const vm = applyFiltersAndSort(vmAll);
|
||||
if (!vm.length) {
|
||||
const box = (typeof window.renderStateBox === 'function')
|
||||
? window.renderStateBox('empty', 'Geen resultaten', 'Pas filters aan of schakel opties uit om netwerken te tonen.')
|
||||
: 'Geen resultaten.';
|
||||
tbody.innerHTML = `<tr><td colspan="6">${box}</td></tr>`;
|
||||
rel.innerHTML = box;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const row of vm) {
|
||||
const netName = row.name;
|
||||
@@ -1137,4 +1175,4 @@
|
||||
|
||||
// Bind when script loads (DOM is already mostly there because script is at end of body)
|
||||
bindUiOnce();
|
||||
})();
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user