Implement search functionality for services and add info button for connection details

This commit is contained in:
MayaChat
2025-11-23 23:56:00 -05:00
parent 78240b3895
commit 75b7922517

View File

@@ -10,6 +10,9 @@
<header>
<h1>My Services</h1>
<p class="subtitle">Quick links to the commonly used containers on this host</p>
<div class="search-container">
<input type="text" id="search-input" placeholder="🔍 Search services..." />
</div>
</header>
<main>
@@ -33,7 +36,10 @@
// Fetch services.xml and render the service cards with logos.
(async function(){
const grid = document.getElementById('services-grid');
const searchInput = document.getElementById('search-input');
const host = window.location.hostname;
let allServices = []; // Store all service elements for filtering
try{
const res = await fetch('/services.xml', {cache: 'no-cache'});
if(!res.ok){ throw new Error('Failed to load services.xml'); }
@@ -81,6 +87,7 @@
a.href = href;
a.target = '_blank';
a.rel = 'noreferrer';
a.dataset.serviceName = name.toLowerCase(); // For search filtering
const img = document.createElement('img');
img.className = 'logo';
@@ -93,8 +100,59 @@
a.appendChild(img);
a.appendChild(span);
// Add info button if both hostname and port are available
if((hostAttr || host) && port){
const infoBtn = document.createElement('button');
infoBtn.className = 'info-btn';
infoBtn.title = 'Connection details';
infoBtn.innerHTML = 'ⓘ';
infoBtn.onclick = (e) => {
e.preventDefault();
e.stopPropagation();
const displayHost = hostAttr || host;
const details = `Service: ${name}\nHost: ${displayHost}\nPort: ${port}\nProtocol: ${proto}`;
alert(details);
};
a.appendChild(infoBtn);
}
grid.appendChild(a);
allServices.push(a);
});
// Search functionality
searchInput.addEventListener('input', (e) => {
const searchTerm = e.target.value.toLowerCase().trim();
let visibleCount = 0;
allServices.forEach(card => {
const serviceName = card.dataset.serviceName;
if(serviceName.includes(searchTerm)){
card.style.display = '';
visibleCount++;
} else {
card.style.display = 'none';
}
});
// Show message if no results
const existingMsg = grid.querySelector('.no-results');
if(existingMsg) existingMsg.remove();
if(visibleCount === 0 && searchTerm !== ''){
const msg = document.createElement('p');
msg.className = 'notes no-results';
msg.textContent = `No services found matching "${e.target.value}"`;
grid.appendChild(msg);
}
});
// Focus search on '/' key
document.addEventListener('keydown', (e) => {
if(e.key === '/' && document.activeElement !== searchInput){
e.preventDefault();
searchInput.focus();
}
});
}catch(err){
console.error(err);
grid.innerHTML = '<p class="notes">Error loading services.xml — see console for details.</p>';