secubox-openwrt/package/secubox/luci-app-service-registry/htdocs/luci-static/resources/service-registry/api.js
CyberMind-FR ab8e0c44bc feat(service-registry): Add dynamic health checks and URL readiness wizard
- Add health check RPCD methods:
  - check_service_health: Check DNS, cert, firewall for single domain
  - check_all_health: Batch check all published services
- Add URL Readiness Checker wizard card to dashboard:
  - Check if domain DNS resolves correctly
  - Verify firewall ports 80/443 are open
  - Check SSL certificate status
  - Show actionable recommendations
- Display inline health status badges on service rows:
  - DNS resolution status (ok/failed)
  - Certificate expiry (ok/warning/critical/expired)
- Add health summary bar showing overall system status
- Add per-service health check button

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 07:01:27 +01:00

270 lines
6.9 KiB
JavaScript

'use strict';
'require baseclass';
'require rpc';
// RPC method declarations
var callListServices = rpc.declare({
object: 'luci.service-registry',
method: 'list_services'
});
var callGetService = rpc.declare({
object: 'luci.service-registry',
method: 'get_service',
params: ['service_id'],
expect: {}
});
var callPublishService = rpc.declare({
object: 'luci.service-registry',
method: 'publish_service',
params: ['name', 'local_port', 'domain', 'tor_enabled', 'category', 'icon'],
expect: {}
});
var callUnpublishService = rpc.declare({
object: 'luci.service-registry',
method: 'unpublish_service',
params: ['service_id'],
expect: {}
});
var callUpdateService = rpc.declare({
object: 'luci.service-registry',
method: 'update_service',
params: ['service_id', 'name', 'category', 'icon'],
expect: {}
});
var callDeleteService = rpc.declare({
object: 'luci.service-registry',
method: 'delete_service',
params: ['service_id'],
expect: {}
});
var callSyncProviders = rpc.declare({
object: 'luci.service-registry',
method: 'sync_providers',
expect: {}
});
var callGenerateLandingPage = rpc.declare({
object: 'luci.service-registry',
method: 'generate_landing_page',
expect: {}
});
var callGetQrData = rpc.declare({
object: 'luci.service-registry',
method: 'get_qr_data',
params: ['service_id', 'url_type'],
expect: {}
});
var callListCategories = rpc.declare({
object: 'luci.service-registry',
method: 'list_categories'
});
var callGetCertificateStatus = rpc.declare({
object: 'luci.service-registry',
method: 'get_certificate_status',
params: ['service_id'],
expect: {}
});
var callGetLandingConfig = rpc.declare({
object: 'luci.service-registry',
method: 'get_landing_config',
expect: {}
});
var callSaveLandingConfig = rpc.declare({
object: 'luci.service-registry',
method: 'save_landing_config',
params: ['auto_regen'],
expect: {}
});
var callCheckServiceHealth = rpc.declare({
object: 'luci.service-registry',
method: 'check_service_health',
params: ['service_id', 'domain'],
expect: {}
});
var callCheckAllHealth = rpc.declare({
object: 'luci.service-registry',
method: 'check_all_health',
expect: {}
});
// HAProxy status for provider info
var callHAProxyStatus = rpc.declare({
object: 'luci.haproxy',
method: 'status',
expect: {}
});
// Tor Shield status for provider info
var callTorStatus = rpc.declare({
object: 'luci.tor-shield',
method: 'status',
expect: {}
});
return baseclass.extend({
// List all services from all providers
listServices: function() {
return callListServices();
},
// Get single service details
getService: function(serviceId) {
return callGetService(serviceId);
},
// Publish a new service
publishService: function(name, localPort, domain, torEnabled, category, icon) {
return callPublishService(
name,
parseInt(localPort) || 0,
domain || '',
torEnabled ? true : false,
category || 'services',
icon || ''
);
},
// Unpublish a service
unpublishService: function(serviceId) {
return callUnpublishService(serviceId);
},
// Update service metadata
updateService: function(serviceId, name, category, icon) {
return callUpdateService(serviceId, name || '', category || '', icon || '');
},
// Delete a service
deleteService: function(serviceId) {
return callDeleteService(serviceId);
},
// Sync all providers
syncProviders: function() {
return callSyncProviders();
},
// Generate landing page
generateLandingPage: function() {
return callGenerateLandingPage();
},
// Get QR code data for a service URL
getQrData: function(serviceId, urlType) {
return callGetQrData(serviceId, urlType || 'local');
},
// List available categories
listCategories: function() {
return callListCategories();
},
// Get certificate status for a service
getCertificateStatus: function(serviceId) {
return callGetCertificateStatus(serviceId);
},
// Get landing page configuration
getLandingConfig: function() {
return callGetLandingConfig();
},
// Save landing page configuration
saveLandingConfig: function(autoRegen) {
return callSaveLandingConfig(autoRegen ? true : false);
},
// Get dashboard data (services + provider status)
getDashboardData: function() {
return Promise.all([
callListServices().catch(function(e) { console.error('list_services failed:', e); return { services: [], providers: {} }; }),
callListCategories().catch(function(e) { console.error('list_categories failed:', e); return { categories: [] }; }),
callGetLandingConfig().catch(function(e) { console.error('get_landing_config failed:', e); return {}; }),
callHAProxyStatus().catch(function() { return { enabled: false }; }),
callTorStatus().catch(function() { return { enabled: false }; })
]).then(function(results) {
return {
services: results[0].services || [],
providers: results[0].providers || {},
categories: results[1].categories || [],
landing: results[2],
haproxy: results[3],
tor: results[4]
};
});
},
// Get published services only
getPublishedServices: function() {
return callListServices().then(function(data) {
return (data.services || []).filter(function(s) {
return s.published;
});
});
},
// Get unpublished (discoverable) services
getUnpublishedServices: function() {
return callListServices().then(function(data) {
return (data.services || []).filter(function(s) {
return !s.published;
});
});
},
// Quick publish with defaults
quickPublish: function(name, port) {
return this.publishService(name, port, '', false, 'services', '');
},
// Full publish with HAProxy + Tor
fullPublish: function(name, port, domain) {
return this.publishService(name, port, domain, true, 'services', '');
},
// Check health of a single service
checkServiceHealth: function(serviceId, domain) {
return callCheckServiceHealth(serviceId || '', domain || '');
},
// Check health of all published services
checkAllHealth: function() {
return callCheckAllHealth();
},
// Get dashboard data with health status
getDashboardDataWithHealth: function() {
return Promise.all([
callListServices().catch(function(e) { console.error('list_services failed:', e); return { services: [], providers: {} }; }),
callListCategories().catch(function(e) { console.error('list_categories failed:', e); return { categories: [] }; }),
callGetLandingConfig().catch(function(e) { console.error('get_landing_config failed:', e); return {}; }),
callHAProxyStatus().catch(function() { return { enabled: false }; }),
callTorStatus().catch(function() { return { enabled: false }; }),
callCheckAllHealth().catch(function(e) { console.error('check_all_health failed:', e); return { health: {} }; })
]).then(function(results) {
return {
services: results[0].services || [],
providers: results[0].providers || {},
categories: results[1].categories || [],
landing: results[2],
haproxy: results[3],
tor: results[4],
health: results[5].health || {}
};
});
}
});