feat: add backend caching and pagination for resources

Co-authored-by: aider (openrouter/thinkingmachines/inkling-small:free) <aider@aider.chat>
This commit is contained in:
Jiří Stachandaider committed 2026-10-09 18:01:48 +02:00
1 parent f8422404d7
commit 77febb993e
3 files changed
+104 -74

No files matched your search

+27 -49
View File
@@ -6,11 +6,11 @@ document.addEventListener('DOMContentLoaded', () => {
const resourceTitle = document.getElementById('resource-title');
const searchInput = document.getElementById('search-input');
const searchBtn = document.getElementById('search-btn');
const refreshBtn = document.getElementById('refresh-btn');
const setDefaultBtn = document.getElementById('set-default');
const actionName = document.getElementById('action-name');
const actionOutput = document.getElementById('action-output');
let currentData = [];
let currentPage = 1;
const pageSize = 10;
@@ -79,49 +79,33 @@ document.addEventListener('DOMContentLoaded', () => {
}
}
async function loadResources() {
async function loadResources(bypass = false, page = 1) {
const resType = resourceSelect.value;
const ns = namespaceSelect.value || 'default';
const ctx = contextSelect.value || null;
const search = searchInput.value.trim();
resourceTitle.textContent = resType.charAt(0).toUpperCase() + resType.slice(1);
resourceList.innerHTML = '<li>Loading...</li>';
currentPage = 1;
currentPage = page;
try {
let url;
if (resType === 'pods') {
url = `http://localhost:8000/pods?namespace=${encodeURIComponent(ns)}${ctx ? '&context=' + encodeURIComponent(ctx) : ''}`;
url = `http://localhost:8000/pods?namespace=${encodeURIComponent(ns)}&page=${page}&page_size=${pageSize}&bypass=${bypass}`;
} else if (resType === 'nodes') {
url = `http://localhost:8000/nodes${ctx ? '?context=' + encodeURIComponent(ctx) : ''}`;
url = `http://localhost:8000/nodes?page=${page}&page_size=${pageSize}&bypass=${bypass}`;
} else if (resType === 'pvcs') {
url = `http://localhost:8000/pvcs?namespace=${encodeURIComponent(ns)}${ctx ? '&context=' + encodeURIComponent(ctx) : ''}`;
url = `http://localhost:8000/pvcs?namespace=${encodeURIComponent(ns)}&page=${page}&page_size=${pageSize}&bypass=${bypass}`;
} else if (resType === 'configmaps') {
url = `http://localhost:8000/configmaps?namespace=${encodeURIComponent(ns)}${ctx ? '&context=' + encodeURIComponent(ctx) : ''}`;
url = `http://localhost:8000/configmaps?namespace=${encodeURIComponent(ns)}&page=${page}&page_size=${pageSize}&bypass=${bypass}`;
} else {
url = `http://localhost:8000/pods?namespace=${encodeURIComponent(ns)}`;
url = `http://localhost:8000/pods?namespace=${encodeURIComponent(ns)}&page=${page}&page_size=${pageSize}&bypass=${bypass}`;
}
if (search) url += `&search=${encodeURIComponent(search)}`;
if (ctx) url += `&context=${encodeURIComponent(ctx)}`;
const res = await fetch(url);
const data = await res.json();
currentData = [];
try {
const obj = JSON.parse(data.raw || '{}');
if (resType === 'pods' || resType === 'pvcs' || resType === 'configmaps') {
const items = obj.items || [];
currentData = items.map(i => ({
name: i.metadata?.name || 'unknown',
namespace: i.metadata?.namespace || ns
}));
} else if (resType === 'nodes') {
const items = obj.items || [];
currentData = items.map(i => ({
name: i.metadata?.name || 'unknown',
namespace: '-'
}));
}
} catch (e) {
currentData = [];
}
renderList();
renderList(data);
updateActionVisibility();
} catch (e) {
console.error('Failed to load resources', e);
@@ -129,21 +113,18 @@ document.addEventListener('DOMContentLoaded', () => {
}
}
function renderList() {
const filter = searchInput.value.toLowerCase();
const filtered = currentData.filter(item => item.name.toLowerCase().includes(filter));
const totalPages = Math.max(1, Math.ceil(filtered.length / pageSize));
if (currentPage > totalPages) currentPage = totalPages;
if (currentPage < 1) currentPage = 1;
const start = (currentPage - 1) * pageSize;
const pageItems = filtered.slice(start, start + pageSize);
function renderList(data) {
const items = data.items || [];
const total = data.total || 0;
const page = data.page || 1;
const pageSize = data.page_size || 10;
const totalPages = Math.max(1, Math.ceil(total / pageSize));
resourceList.innerHTML = '';
if (pageItems.length === 0) {
if (items.length === 0) {
resourceList.innerHTML = '<li>No results</li>';
} else {
pageItems.forEach(item => {
items.forEach(item => {
const li = document.createElement('li');
li.style.cursor = 'pointer';
li.innerHTML = `<strong>${item.name}</strong> <span style="color:#666">(${item.namespace})</span>`;
@@ -162,29 +143,26 @@ document.addEventListener('DOMContentLoaded', () => {
}
const pageInfo = document.getElementById('page-info');
if (pageInfo) pageInfo.textContent = `Page ${currentPage} of ${totalPages} (${filtered.length} total)`;
if (pageInfo) pageInfo.textContent = `Page ${page} of ${totalPages} (${total} total)`;
const prevBtn = document.getElementById('prev-page');
const nextBtn = document.getElementById('next-page');
if (prevBtn) prevBtn.disabled = currentPage <= 1;
if (nextBtn) nextBtn.disabled = currentPage >= totalPages;
if (prevBtn) prevBtn.disabled = page <= 1;
if (nextBtn) nextBtn.disabled = page >= totalPages;
}
contextSelect.addEventListener('change', () => { saveSession(); loadNamespaces(); });
namespaceSelect.addEventListener('change', () => { saveSession(); loadResources(); });
resourceSelect.addEventListener('change', () => { saveSession(); loadResources(); });
searchBtn.addEventListener('click', () => { currentPage = 1; renderList(); });
searchInput.addEventListener('input', () => { currentPage = 1; renderList(); });
searchBtn.addEventListener('click', () => loadResources(false, 1));
refreshBtn.addEventListener('click', () => loadResources(true, 1));
setDefaultBtn.addEventListener('click', () => { saveSession(); alert('Defaults saved for session'); });
document.getElementById('prev-page').addEventListener('click', () => {
if (currentPage > 1) { currentPage--; renderList(); }
if (currentPage > 1) loadResources(false, currentPage - 1);
});
document.getElementById('next-page').addEventListener('click', () => {
const filter = searchInput.value.toLowerCase();
const filtered = currentData.filter(item => item.name.toLowerCase().includes(filter));
const totalPages = Math.max(1, Math.ceil(filtered.length / pageSize));
if (currentPage < totalPages) { currentPage++; renderList(); }
loadResources(false, currentPage + 1);
});
document.getElementById('btn-describe').addEventListener('click', async () => {