Enhance service card creation with Tailscale IP support and update services.xml to include tailscale-ip configuration
This commit is contained in:
@@ -18,6 +18,11 @@
|
|||||||
throw new Error('XML parsing error: ' + parseError.textContent);
|
throw new Error('XML parsing error: ' + parseError.textContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get Tailscale IP from root services element
|
||||||
|
const servicesRoot = doc.getElementsByTagName('services')[0];
|
||||||
|
const tailscaleIP = servicesRoot ? servicesRoot.getAttribute('tailscale-ip') : null;
|
||||||
|
console.log('Tailscale IP:', tailscaleIP || 'not configured');
|
||||||
|
|
||||||
// Check if we have groups or just services
|
// Check if we have groups or just services
|
||||||
const groups = Array.from(doc.getElementsByTagName('group'));
|
const groups = Array.from(doc.getElementsByTagName('group'));
|
||||||
const hasGroups = groups.length > 0;
|
const hasGroups = groups.length > 0;
|
||||||
@@ -47,7 +52,7 @@
|
|||||||
grid.className = 'grid';
|
grid.className = 'grid';
|
||||||
|
|
||||||
services.forEach(s => {
|
services.forEach(s => {
|
||||||
const card = createServiceCard(s, host, allServices);
|
const card = createServiceCard(s, host, allServices, tailscaleIP);
|
||||||
grid.appendChild(card);
|
grid.appendChild(card);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -67,7 +72,7 @@
|
|||||||
grid.id = 'services-grid';
|
grid.id = 'services-grid';
|
||||||
|
|
||||||
services.forEach(s => {
|
services.forEach(s => {
|
||||||
const card = createServiceCard(s, host, allServices);
|
const card = createServiceCard(s, host, allServices, tailscaleIP);
|
||||||
grid.appendChild(card);
|
grid.appendChild(card);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -75,7 +80,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function to create a service card
|
// Function to create a service card
|
||||||
function createServiceCard(s, host, allServices) {
|
function createServiceCard(s, host, allServices, tailscaleIP) {
|
||||||
const name = s.getAttribute('name') || s.getAttribute('id') || 'unknown';
|
const name = s.getAttribute('name') || s.getAttribute('id') || 'unknown';
|
||||||
const proto = s.getAttribute('proto') || 'http';
|
const proto = s.getAttribute('proto') || 'http';
|
||||||
const port = s.getAttribute('port') || '';
|
const port = s.getAttribute('port') || '';
|
||||||
@@ -86,21 +91,30 @@
|
|||||||
|
|
||||||
// Build href: prefer explicit host attribute when present.
|
// Build href: prefer explicit host attribute when present.
|
||||||
let href = '';
|
let href = '';
|
||||||
|
let healthCheckUrl = ''; // Separate URL for health checks
|
||||||
|
|
||||||
if(hostAttr){
|
if(hostAttr){
|
||||||
|
// Service has a public hostname or URL
|
||||||
if(/^https?:\/\//i.test(hostAttr)){
|
if(/^https?:\/\//i.test(hostAttr)){
|
||||||
href = hostAttr;
|
href = hostAttr;
|
||||||
|
healthCheckUrl = hostAttr;
|
||||||
} else {
|
} else {
|
||||||
const hasPortInHost = /:\d+$/.test(hostAttr);
|
const hasPortInHost = /:\d+$/.test(hostAttr);
|
||||||
if(hasPortInHost){
|
if(hasPortInHost){
|
||||||
href = `${proto}://${hostAttr}`;
|
href = `${proto}://${hostAttr}`;
|
||||||
|
healthCheckUrl = `${proto}://${hostAttr}`;
|
||||||
} else {
|
} else {
|
||||||
href = `https://${hostAttr}`;
|
href = `https://${hostAttr}`;
|
||||||
|
healthCheckUrl = `https://${hostAttr}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Local service - use Tailscale IP if configured, otherwise current hostname
|
||||||
|
const targetHost = tailscaleIP || host;
|
||||||
let portPart = '';
|
let portPart = '';
|
||||||
if(port && !((proto==='http'&&port==='80')||(proto==='https'&&port==='443'))){ portPart = ':'+port; }
|
if(port && !((proto==='http'&&port==='80')||(proto==='https'&&port==='443'))){ portPart = ':'+port; }
|
||||||
href = `${proto}://${host}${portPart}`;
|
href = `${proto}://${targetHost}${portPart}`;
|
||||||
|
healthCheckUrl = `${proto}://${targetHost}${portPart}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
@@ -134,17 +148,17 @@
|
|||||||
statusDot.title = 'Status: maintenance';
|
statusDot.title = 'Status: maintenance';
|
||||||
currentStatus = 'maintenance';
|
currentStatus = 'maintenance';
|
||||||
a.appendChild(statusDot);
|
a.appendChild(statusDot);
|
||||||
} else if(checkHealth && href){
|
} else if(checkHealth && healthCheckUrl){
|
||||||
// Show checking indicator initially
|
// Show checking indicator initially
|
||||||
a.appendChild(statusDot);
|
a.appendChild(statusDot);
|
||||||
|
|
||||||
// Perform health check
|
// Perform health check using healthCheckUrl (Tailscale IP for local services)
|
||||||
(async function performHealthCheck(){
|
(async function performHealthCheck(){
|
||||||
try {
|
try {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout
|
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout
|
||||||
|
|
||||||
const response = await fetch(href, {
|
const response = await fetch(healthCheckUrl, {
|
||||||
method: 'HEAD',
|
method: 'HEAD',
|
||||||
mode: 'no-cors', // Allow cross-origin requests
|
mode: 'no-cors', // Allow cross-origin requests
|
||||||
cache: 'no-cache',
|
cache: 'no-cache',
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
<!--
|
<!--
|
||||||
services.xml - simple list of services for the homepage
|
services.xml - simple list of services for the homepage
|
||||||
|
|
||||||
|
Configuration:
|
||||||
|
- tailscale-ip: IP address to use for local services (optional, default: auto-detect)
|
||||||
|
|
||||||
Structure:
|
Structure:
|
||||||
- Use <group> elements to organize services into categories
|
- Use <group> elements to organize services into categories
|
||||||
- Each group has a 'name' attribute for the category title
|
- Each group has a 'name' attribute for the category title
|
||||||
@@ -25,7 +28,7 @@
|
|||||||
* Red dot if offline/unreachable
|
* Red dot if offline/unreachable
|
||||||
- Set check-health="false" to disable automatic checking
|
- Set check-health="false" to disable automatic checking
|
||||||
-->
|
-->
|
||||||
<services>
|
<services tailscale-ip="100.124.17.41">
|
||||||
<group name="Management">
|
<group name="Management">
|
||||||
<service id="portainer" name="Portainer" proto="https" port="9443" logo="portainer.svg" />
|
<service id="portainer" name="Portainer" proto="https" port="9443" logo="portainer.svg" />
|
||||||
<service id="uptime-kuma" name="Uptime Kuma" proto="http" port="3001" logo="uptime-kuma.svg" />
|
<service id="uptime-kuma" name="Uptime Kuma" proto="http" port="3001" logo="uptime-kuma.svg" />
|
||||||
|
|||||||
Reference in New Issue
Block a user