librelad eaafd1bb38 refactor(webui): relocate admin area into features/admin/ + shared extractions
- features/admin/: the 10 admin-owned config controllers, the 5 admin pages
  (overview/system/charts/metric/storage), ssh-page.js, peers-page.js, plus
  admin.css/ip-whitelist.css/ssh.css (eager). config-manager.js kept last in
  the load order (it news the sub-managers).
- shared/js/: config-shared.js + config-options.js (ConfigShared/ConfigOptions
  globals consumed cross-feature by backup/apps/tasks).
- shared/css/: forms.css + config.css (generic form + config-form primitives
  borrowed by apps/backup/admin).
- Updated all path strings in system-loader.js (config component) and
  config-manager.js (lazyLoad of admin/ssh/peers controllers); index.html CSS
  hrefs. No /js/components/{config,admin,ssh,peers}/ refs remain.

js/components/ now holds only shared UI (topbar, notifications, eo-modal,
update-notifier, mobile-menu, confirmation-dialog).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-30 02:10:09 +01:00

249 lines
8.5 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Config Validation System for LibrePortal Web UI
// Validates JSON config files before loading the main interface
// Global validator instance
window.ConfigValidator = function() {
let validationResults = null;
let hasValidated = false;
// Validate all config files
this.validateAllConfigs = async function() {
// Use client-side validation directly
return this.fallbackValidation();
};
// Fallback client-side validation
this.fallbackValidation = async function() {
const results = {
valid: true,
errors: [],
warnings: [],
suggestions: []
};
// Check if unified config file exists (file existence check only)
const configFiles = [
{ name: 'Unified System Config', path: '/data/config/generated/configs.json' }
];
for (const config of configFiles) {
try {
const response = await fetch(config.path, { method: 'HEAD' });
if (!response.ok) {
results.valid = false;
results.errors.push(`Config file '${config.name}' not found: ${config.path}`);
continue;
}
//console.log(`Config file exists: ${config.name}`);
} catch (error) {
results.valid = false;
results.errors.push(`Failed to check ${config.name}: ${error.message}`);
}
}
// Add suggestions if there are issues
if (!results.valid) {
results.suggestions = [
"Run 'libreportal run' to fix configuration issues",
"Check config file permissions and ownership",
"Ensure Docker is running and accessible"
];
}
validationResults = results;
hasValidated = true;
return results;
};
// Show validation error message
this.showValidationError = function() {
if (!hasValidated) {
return;
}
if (validationResults.valid) {
return; // No error to show
}
// Create error overlay
const errorOverlay = document.createElement('div');
errorOverlay.className = 'config-validation-overlay';
errorOverlay.innerHTML = `
<div class="config-validation-dialog">
<div class="validation-header">
<h3>⚠️ Configuration Issues Detected</h3>
<button class="close-btn" onclick="this.parentElement.parentElement.remove()">×</button>
</div>
<div class="validation-content">
<div class="validation-errors">
<h4>Errors:</h4>
<ul>
${validationResults.errors.map(error => `<li>${this.escapeHtml(error)}</li>`).join('')}
</ul>
</div>
${validationResults.warnings.length > 0 ? `
<div class="validation-warnings">
<h4>Warnings:</h4>
<ul>
${validationResults.warnings.map(warning => `<li>${this.escapeHtml(warning)}</li>`).join('')}
</ul>
</div>
` : ''}
<div class="validation-suggestions">
<h4>Suggestions:</h4>
<ul>
${validationResults.suggestions.map(suggestion => `<li>${this.escapeHtml(suggestion)}</li>`).join('')}
</ul>
</div>
<div class="validation-actions">
<button class="primary-btn" onclick="window.location.reload()">Reload</button>
<button class="secondary-btn" onclick="window.open('https://github.com/your-repo/wiki/troubleshooting', '_blank')">Help</button>
</div>
</div>
</div>
`;
// Add styles
errorOverlay.innerHTML += `
<style>
.config-validation-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
}
.config-validation-dialog {
background: var(--surface-color);
border-radius: 12px;
padding: 24px;
max-width: 600px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
}
.validation-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: 1px solid var(--border-color);
}
.validation-header h3 {
margin: 0;
color: var(--error-color);
font-size: 18px;
}
.close-btn {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: var(--text-color);
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.validation-errors h4 {
color: var(--error-color);
margin-bottom: 8px;
}
.validation-warnings h4 {
color: var(--warning-color);
margin-bottom: 8px;
}
.validation-content ul {
margin: 0 0 16px 0;
padding-left: 20px;
}
.validation-content li {
margin-bottom: 8px;
line-height: 1.4;
}
.validation-suggestions {
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid var(--border-color);
}
.validation-suggestions h4 {
color: var(--success-color);
margin-bottom: 8px;
}
.validation-actions {
display: flex;
gap: 12px;
margin-top: 24px;
justify-content: flex-end;
}
.primary-btn, .secondary-btn {
padding: 10px 20px;
border-radius: 6px;
border: none;
cursor: pointer;
font-size: 14px;
font-weight: 500;
}
.primary-btn {
background: var(--primary-color);
color: white;
}
.secondary-btn {
background: var(--surface-color);
color: var(--text-color);
border: 1px solid var(--border-color);
}
</style>
`;
document.body.appendChild(errorOverlay);
};
// Escape HTML to prevent XSS
this.escapeHtml = function(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
};
// Get validation status
this.isValid = function() {
return hasValidated && validationResults.valid;
};
// Get validation errors
this.getErrors = function() {
return hasValidated ? validationResults.errors : [];
};
// Get validation warnings
this.getWarnings = function() {
return hasValidated ? validationResults.warnings : [];
};
};