@jagilber-org/index-server 1.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1218 -0
- package/CODE_OF_CONDUCT.md +49 -0
- package/CONTRIBUTING.md +75 -0
- package/LICENSE +21 -0
- package/README.md +523 -0
- package/SECURITY.md +50 -0
- package/dist/config/configUtils.d.ts +11 -0
- package/dist/config/configUtils.js +87 -0
- package/dist/config/dashboardConfig.d.ts +45 -0
- package/dist/config/dashboardConfig.js +63 -0
- package/dist/config/defaultValues.d.ts +61 -0
- package/dist/config/defaultValues.js +70 -0
- package/dist/config/dirConstants.d.ts +17 -0
- package/dist/config/dirConstants.js +28 -0
- package/dist/config/featureConfig.d.ts +61 -0
- package/dist/config/featureConfig.js +121 -0
- package/dist/config/runtimeConfig.d.ts +145 -0
- package/dist/config/runtimeConfig.js +334 -0
- package/dist/config/serverConfig.d.ts +90 -0
- package/dist/config/serverConfig.js +164 -0
- package/dist/dashboard/analytics/AnalyticsEngine.d.ts +142 -0
- package/dist/dashboard/analytics/AnalyticsEngine.js +373 -0
- package/dist/dashboard/analytics/BusinessIntelligence.d.ts +187 -0
- package/dist/dashboard/analytics/BusinessIntelligence.js +594 -0
- package/dist/dashboard/client/admin.html +2150 -0
- package/dist/dashboard/client/chunks/mermaid-layout-elk.esm.min/chunk-SP2CHFBE.mjs +1 -0
- package/dist/dashboard/client/chunks/mermaid-layout-elk.esm.min/render-T6MDALS3.mjs +27 -0
- package/dist/dashboard/client/css/admin.css +1466 -0
- package/dist/dashboard/client/js/admin.boot.js +359 -0
- package/dist/dashboard/client/js/admin.config.js +196 -0
- package/dist/dashboard/client/js/admin.embeddings.js +425 -0
- package/dist/dashboard/client/js/admin.graph.js +583 -0
- package/dist/dashboard/client/js/admin.instances.js +120 -0
- package/dist/dashboard/client/js/admin.instructions.js +552 -0
- package/dist/dashboard/client/js/admin.logs.js +113 -0
- package/dist/dashboard/client/js/admin.maintenance.js +354 -0
- package/dist/dashboard/client/js/admin.messaging.js +635 -0
- package/dist/dashboard/client/js/admin.monitor.js +181 -0
- package/dist/dashboard/client/js/admin.overview.js +221 -0
- package/dist/dashboard/client/js/admin.performance.js +61 -0
- package/dist/dashboard/client/js/admin.sessions.js +293 -0
- package/dist/dashboard/client/js/admin.sqlite.js +366 -0
- package/dist/dashboard/client/js/admin.utils.js +49 -0
- package/dist/dashboard/client/js/chart.umd.js +14 -0
- package/dist/dashboard/client/js/elk.bundled.js +6696 -0
- package/dist/dashboard/client/js/marked.umd.js +74 -0
- package/dist/dashboard/client/js/mermaid.min.js +3022 -0
- package/dist/dashboard/client/mermaid-layout-elk.esm.min.mjs +1 -0
- package/dist/dashboard/export/DataExporter.d.ts +169 -0
- package/dist/dashboard/export/DataExporter.js +737 -0
- package/dist/dashboard/export/exporters/csvExporter.d.ts +11 -0
- package/dist/dashboard/export/exporters/csvExporter.js +46 -0
- package/dist/dashboard/export/exporters/exportTypes.d.ts +89 -0
- package/dist/dashboard/export/exporters/exportTypes.js +5 -0
- package/dist/dashboard/export/exporters/jsonExporter.d.ts +7 -0
- package/dist/dashboard/export/exporters/jsonExporter.js +22 -0
- package/dist/dashboard/export/exporters/xmlExporter.d.ts +17 -0
- package/dist/dashboard/export/exporters/xmlExporter.js +175 -0
- package/dist/dashboard/integration/APIIntegration.d.ts +41 -0
- package/dist/dashboard/integration/APIIntegration.js +95 -0
- package/dist/dashboard/security/SecurityMonitor.d.ts +167 -0
- package/dist/dashboard/security/SecurityMonitor.js +559 -0
- package/dist/dashboard/server/AdminPanel.d.ts +183 -0
- package/dist/dashboard/server/AdminPanel.js +792 -0
- package/dist/dashboard/server/AdminPanelConfig.d.ts +42 -0
- package/dist/dashboard/server/AdminPanelConfig.js +80 -0
- package/dist/dashboard/server/AdminPanelState.d.ts +47 -0
- package/dist/dashboard/server/AdminPanelState.js +214 -0
- package/dist/dashboard/server/ApiRoutes.d.ts +17 -0
- package/dist/dashboard/server/ApiRoutes.js +149 -0
- package/dist/dashboard/server/DashboardServer.d.ts +49 -0
- package/dist/dashboard/server/DashboardServer.js +159 -0
- package/dist/dashboard/server/FileMetricsStorage.d.ts +49 -0
- package/dist/dashboard/server/FileMetricsStorage.js +195 -0
- package/dist/dashboard/server/HttpTransport.d.ts +23 -0
- package/dist/dashboard/server/HttpTransport.js +116 -0
- package/dist/dashboard/server/InstanceManager.d.ts +53 -0
- package/dist/dashboard/server/InstanceManager.js +284 -0
- package/dist/dashboard/server/KnowledgeStore.d.ts +35 -0
- package/dist/dashboard/server/KnowledgeStore.js +105 -0
- package/dist/dashboard/server/LeaderElection.d.ts +81 -0
- package/dist/dashboard/server/LeaderElection.js +268 -0
- package/dist/dashboard/server/MetricsCollector.d.ts +200 -0
- package/dist/dashboard/server/MetricsCollector.js +803 -0
- package/dist/dashboard/server/SessionPersistenceManager.d.ts +88 -0
- package/dist/dashboard/server/SessionPersistenceManager.js +457 -0
- package/dist/dashboard/server/ThinClient.d.ts +64 -0
- package/dist/dashboard/server/ThinClient.js +237 -0
- package/dist/dashboard/server/WebSocketManager.d.ts +161 -0
- package/dist/dashboard/server/WebSocketManager.js +463 -0
- package/dist/dashboard/server/httpLifecycle.d.ts +17 -0
- package/dist/dashboard/server/httpLifecycle.js +35 -0
- package/dist/dashboard/server/legacyDashboardHtml.d.ts +9 -0
- package/dist/dashboard/server/legacyDashboardHtml.js +618 -0
- package/dist/dashboard/server/legacyDashboardStyles.d.ts +5 -0
- package/dist/dashboard/server/legacyDashboardStyles.js +490 -0
- package/dist/dashboard/server/metricsAggregation.d.ts +252 -0
- package/dist/dashboard/server/metricsAggregation.js +206 -0
- package/dist/dashboard/server/metricsSerializer.d.ts +25 -0
- package/dist/dashboard/server/metricsSerializer.js +195 -0
- package/dist/dashboard/server/routes/admin.routes.d.ts +16 -0
- package/dist/dashboard/server/routes/admin.routes.js +596 -0
- package/dist/dashboard/server/routes/alerts.routes.d.ts +7 -0
- package/dist/dashboard/server/routes/alerts.routes.js +93 -0
- package/dist/dashboard/server/routes/api.feedback.routes.d.ts +73 -0
- package/dist/dashboard/server/routes/api.feedback.routes.js +171 -0
- package/dist/dashboard/server/routes/api.instructions.routes.d.ts +101 -0
- package/dist/dashboard/server/routes/api.instructions.routes.js +213 -0
- package/dist/dashboard/server/routes/api.usage.routes.d.ts +57 -0
- package/dist/dashboard/server/routes/api.usage.routes.js +374 -0
- package/dist/dashboard/server/routes/embeddings.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/embeddings.routes.js +246 -0
- package/dist/dashboard/server/routes/graph.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/graph.routes.js +280 -0
- package/dist/dashboard/server/routes/index.d.ts +38 -0
- package/dist/dashboard/server/routes/index.js +194 -0
- package/dist/dashboard/server/routes/instances.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/instances.routes.js +35 -0
- package/dist/dashboard/server/routes/instructions.routes.d.ts +8 -0
- package/dist/dashboard/server/routes/instructions.routes.js +336 -0
- package/dist/dashboard/server/routes/knowledge.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/knowledge.routes.js +82 -0
- package/dist/dashboard/server/routes/logs.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/logs.routes.js +164 -0
- package/dist/dashboard/server/routes/messaging.routes.d.ts +16 -0
- package/dist/dashboard/server/routes/messaging.routes.js +293 -0
- package/dist/dashboard/server/routes/metrics.routes.d.ts +10 -0
- package/dist/dashboard/server/routes/metrics.routes.js +346 -0
- package/dist/dashboard/server/routes/scripts.routes.d.ts +9 -0
- package/dist/dashboard/server/routes/scripts.routes.js +84 -0
- package/dist/dashboard/server/routes/sqlite.routes.d.ts +9 -0
- package/dist/dashboard/server/routes/sqlite.routes.js +569 -0
- package/dist/dashboard/server/routes/status.routes.d.ts +7 -0
- package/dist/dashboard/server/routes/status.routes.js +183 -0
- package/dist/dashboard/server/routes/synthetic.routes.d.ts +7 -0
- package/dist/dashboard/server/routes/synthetic.routes.js +195 -0
- package/dist/dashboard/server/routes/tools.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/tools.routes.js +46 -0
- package/dist/dashboard/server/routes/usage.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/usage.routes.js +25 -0
- package/dist/dashboard/server/wsInit.d.ts +16 -0
- package/dist/dashboard/server/wsInit.js +35 -0
- package/dist/externalClientLib.d.ts +1 -0
- package/dist/externalClientLib.js +2 -0
- package/dist/minimal/index.d.ts +1 -0
- package/dist/minimal/index.js +140 -0
- package/dist/models/SessionPersistence.d.ts +115 -0
- package/dist/models/SessionPersistence.js +66 -0
- package/dist/models/instruction.d.ts +45 -0
- package/dist/models/instruction.js +2 -0
- package/dist/perf/benchmark.d.ts +1 -0
- package/dist/perf/benchmark.js +50 -0
- package/dist/portableClientWrapper.d.ts +1 -0
- package/dist/portableClientWrapper.js +2 -0
- package/dist/schemas/index.d.ts +128 -0
- package/dist/schemas/index.js +371 -0
- package/dist/scripts/runPerformanceBaseline.d.ts +1 -0
- package/dist/scripts/runPerformanceBaseline.js +17 -0
- package/dist/server/handshakeManager.d.ts +25 -0
- package/dist/server/handshakeManager.js +472 -0
- package/dist/server/index-server.d.ts +56 -0
- package/dist/server/index-server.js +822 -0
- package/dist/server/registry.d.ts +44 -0
- package/dist/server/registry.js +236 -0
- package/dist/server/sdkServer.d.ts +8 -0
- package/dist/server/sdkServer.js +299 -0
- package/dist/server/shutdownGuard.d.ts +41 -0
- package/dist/server/shutdownGuard.js +52 -0
- package/dist/server/thin-client.d.ts +22 -0
- package/dist/server/thin-client.js +111 -0
- package/dist/server/transport.d.ts +41 -0
- package/dist/server/transport.js +312 -0
- package/dist/server/transportFactory.d.ts +21 -0
- package/dist/server/transportFactory.js +429 -0
- package/dist/services/atomicFs.d.ts +22 -0
- package/dist/services/atomicFs.js +103 -0
- package/dist/services/auditLog.d.ts +38 -0
- package/dist/services/auditLog.js +142 -0
- package/dist/services/autoBackup.d.ts +14 -0
- package/dist/services/autoBackup.js +171 -0
- package/dist/services/autoSplit.d.ts +32 -0
- package/dist/services/autoSplit.js +113 -0
- package/dist/services/backupZip.d.ts +25 -0
- package/dist/services/backupZip.js +110 -0
- package/dist/services/bootstrapGating.d.ts +123 -0
- package/dist/services/bootstrapGating.js +221 -0
- package/dist/services/canonical.d.ts +23 -0
- package/dist/services/canonical.js +65 -0
- package/dist/services/categoryRules.d.ts +7 -0
- package/dist/services/categoryRules.js +37 -0
- package/dist/services/classificationService.d.ts +42 -0
- package/dist/services/classificationService.js +168 -0
- package/dist/services/embeddingService.d.ts +62 -0
- package/dist/services/embeddingService.js +259 -0
- package/dist/services/errors.d.ts +22 -0
- package/dist/services/errors.js +31 -0
- package/dist/services/featureFlags.d.ts +25 -0
- package/dist/services/featureFlags.js +89 -0
- package/dist/services/features.d.ts +13 -0
- package/dist/services/features.js +35 -0
- package/dist/services/handlers/instructions.add.d.ts +1 -0
- package/dist/services/handlers/instructions.add.js +496 -0
- package/dist/services/handlers/instructions.groom.d.ts +1 -0
- package/dist/services/handlers/instructions.groom.js +523 -0
- package/dist/services/handlers/instructions.import.d.ts +1 -0
- package/dist/services/handlers/instructions.import.js +173 -0
- package/dist/services/handlers/instructions.patch.d.ts +1 -0
- package/dist/services/handlers/instructions.patch.js +167 -0
- package/dist/services/handlers/instructions.query.d.ts +163 -0
- package/dist/services/handlers/instructions.query.js +522 -0
- package/dist/services/handlers/instructions.reload.d.ts +1 -0
- package/dist/services/handlers/instructions.reload.js +13 -0
- package/dist/services/handlers/instructions.remove.d.ts +1 -0
- package/dist/services/handlers/instructions.remove.js +118 -0
- package/dist/services/handlers/instructions.shared.d.ts +31 -0
- package/dist/services/handlers/instructions.shared.js +124 -0
- package/dist/services/handlers.activation.d.ts +1 -0
- package/dist/services/handlers.activation.js +203 -0
- package/dist/services/handlers.bootstrap.d.ts +1 -0
- package/dist/services/handlers.bootstrap.js +38 -0
- package/dist/services/handlers.dashboardConfig.d.ts +34 -0
- package/dist/services/handlers.dashboardConfig.js +108 -0
- package/dist/services/handlers.diagnostics.d.ts +1 -0
- package/dist/services/handlers.diagnostics.js +64 -0
- package/dist/services/handlers.feedback.d.ts +15 -0
- package/dist/services/handlers.feedback.js +378 -0
- package/dist/services/handlers.gates.d.ts +1 -0
- package/dist/services/handlers.gates.js +46 -0
- package/dist/services/handlers.graph.d.ts +53 -0
- package/dist/services/handlers.graph.js +231 -0
- package/dist/services/handlers.help.d.ts +1 -0
- package/dist/services/handlers.help.js +119 -0
- package/dist/services/handlers.instructionSchema.d.ts +1 -0
- package/dist/services/handlers.instructionSchema.js +227 -0
- package/dist/services/handlers.instructions.d.ts +8 -0
- package/dist/services/handlers.instructions.js +14 -0
- package/dist/services/handlers.instructionsDiagnostics.d.ts +1 -0
- package/dist/services/handlers.instructionsDiagnostics.js +14 -0
- package/dist/services/handlers.integrity.d.ts +1 -0
- package/dist/services/handlers.integrity.js +35 -0
- package/dist/services/handlers.manifest.d.ts +1 -0
- package/dist/services/handlers.manifest.js +24 -0
- package/dist/services/handlers.messaging.d.ts +12 -0
- package/dist/services/handlers.messaging.js +203 -0
- package/dist/services/handlers.metrics.d.ts +1 -0
- package/dist/services/handlers.metrics.js +43 -0
- package/dist/services/handlers.promote.d.ts +1 -0
- package/dist/services/handlers.promote.js +306 -0
- package/dist/services/handlers.prompt.d.ts +1 -0
- package/dist/services/handlers.prompt.js +7 -0
- package/dist/services/handlers.search.d.ts +69 -0
- package/dist/services/handlers.search.js +645 -0
- package/dist/services/handlers.testPrimitive.d.ts +1 -0
- package/dist/services/handlers.testPrimitive.js +5 -0
- package/dist/services/handlers.trace.d.ts +1 -0
- package/dist/services/handlers.trace.js +31 -0
- package/dist/services/handlers.usage.d.ts +1 -0
- package/dist/services/handlers.usage.js +11 -0
- package/dist/services/hotScore.d.ts +137 -0
- package/dist/services/hotScore.js +244 -0
- package/dist/services/indexContext.d.ts +117 -0
- package/dist/services/indexContext.js +968 -0
- package/dist/services/indexLoader.d.ts +44 -0
- package/dist/services/indexLoader.js +921 -0
- package/dist/services/indexRepository.d.ts +32 -0
- package/dist/services/indexRepository.js +71 -0
- package/dist/services/indexingService.d.ts +1 -0
- package/dist/services/indexingService.js +2 -0
- package/dist/services/instructions.dispatcher.d.ts +1 -0
- package/dist/services/instructions.dispatcher.js +231 -0
- package/dist/services/logPrefix.d.ts +1 -0
- package/dist/services/logPrefix.js +30 -0
- package/dist/services/logger.d.ts +52 -0
- package/dist/services/logger.js +268 -0
- package/dist/services/manifestManager.d.ts +82 -0
- package/dist/services/manifestManager.js +200 -0
- package/dist/services/messaging/agentMailbox.d.ts +60 -0
- package/dist/services/messaging/agentMailbox.js +353 -0
- package/dist/services/messaging/messagingPersistence.d.ts +20 -0
- package/dist/services/messaging/messagingPersistence.js +111 -0
- package/dist/services/messaging/messagingTypes.d.ts +150 -0
- package/dist/services/messaging/messagingTypes.js +66 -0
- package/dist/services/ownershipService.d.ts +1 -0
- package/dist/services/ownershipService.js +38 -0
- package/dist/services/performanceBaseline.d.ts +19 -0
- package/dist/services/performanceBaseline.js +210 -0
- package/dist/services/preflight.d.ts +12 -0
- package/dist/services/preflight.js +79 -0
- package/dist/services/promptReviewService.d.ts +44 -0
- package/dist/services/promptReviewService.js +101 -0
- package/dist/services/responseEnvelope.d.ts +6 -0
- package/dist/services/responseEnvelope.js +25 -0
- package/dist/services/seedBootstrap.d.ts +34 -0
- package/dist/services/seedBootstrap.js +427 -0
- package/dist/services/storage/factory.d.ts +17 -0
- package/dist/services/storage/factory.js +35 -0
- package/dist/services/storage/hashUtils.d.ts +11 -0
- package/dist/services/storage/hashUtils.js +35 -0
- package/dist/services/storage/index.d.ts +12 -0
- package/dist/services/storage/index.js +18 -0
- package/dist/services/storage/jsonFileStore.d.ts +32 -0
- package/dist/services/storage/jsonFileStore.js +241 -0
- package/dist/services/storage/migrationEngine.d.ts +35 -0
- package/dist/services/storage/migrationEngine.js +93 -0
- package/dist/services/storage/sqliteMessageStore.d.ts +53 -0
- package/dist/services/storage/sqliteMessageStore.js +146 -0
- package/dist/services/storage/sqliteSchema.d.ts +12 -0
- package/dist/services/storage/sqliteSchema.js +122 -0
- package/dist/services/storage/sqliteStore.d.ts +41 -0
- package/dist/services/storage/sqliteStore.js +339 -0
- package/dist/services/storage/sqliteUsageStore.d.ts +35 -0
- package/dist/services/storage/sqliteUsageStore.js +94 -0
- package/dist/services/storage/types.d.ts +171 -0
- package/dist/services/storage/types.js +12 -0
- package/dist/services/toolHandlers.d.ts +23 -0
- package/dist/services/toolHandlers.js +50 -0
- package/dist/services/toolRegistry.d.ts +20 -0
- package/dist/services/toolRegistry.js +490 -0
- package/dist/services/toolRegistry.zod.d.ts +10 -0
- package/dist/services/toolRegistry.zod.js +323 -0
- package/dist/services/tracing.d.ts +26 -0
- package/dist/services/tracing.js +260 -0
- package/dist/services/usageBuckets.d.ts +161 -0
- package/dist/services/usageBuckets.js +364 -0
- package/dist/services/validationService.d.ts +38 -0
- package/dist/services/validationService.js +125 -0
- package/dist/utils/BufferRing.d.ts +203 -0
- package/dist/utils/BufferRing.js +551 -0
- package/dist/utils/BufferRingExamples.d.ts +55 -0
- package/dist/utils/BufferRingExamples.js +188 -0
- package/dist/utils/envUtils.d.ts +42 -0
- package/dist/utils/envUtils.js +80 -0
- package/dist/utils/memoryMonitor.d.ts +83 -0
- package/dist/utils/memoryMonitor.js +275 -0
- package/dist/versioning/schemaVersion.d.ts +6 -0
- package/dist/versioning/schemaVersion.js +93 -0
- package/package.json +134 -0
- package/schemas/README.md +13 -0
- package/schemas/feedback-entry.schema.json +27 -0
- package/schemas/graph-export-v2.schema.json +60 -0
- package/schemas/index-server.code-schema.json +38477 -0
- package/schemas/instruction.schema.json +262 -0
- package/schemas/json-schema/SessionPersistence-persisted-admin-session.schema.json +54 -0
- package/schemas/json-schema/SessionPersistence-persisted-session-history-entry.schema.json +51 -0
- package/schemas/json-schema/SessionPersistence-persisted-web-socket-connection.schema.json +54 -0
- package/schemas/json-schema/SessionPersistence-session-persistence-config.schema.json +110 -0
- package/schemas/json-schema/SessionPersistence-session-persistence-data.schema.json +229 -0
- package/schemas/json-schema/SessionPersistence-session-persistence-manifest.schema.json +109 -0
- package/schemas/json-schema/SessionPersistence-session-persistence-metadata.schema.json +55 -0
- package/schemas/json-schema/instruction-audience-scope.schema.json +14 -0
- package/schemas/json-schema/instruction-content-type.schema.json +17 -0
- package/schemas/json-schema/instruction-instruction-entry.schema.json +206 -0
- package/schemas/json-schema/instruction-requirement-level.schema.json +16 -0
- package/schemas/manifest.json +78 -0
- package/schemas/manifest.schema.json +33 -0
- package/schemas/usage-batch.schema.json +16 -0
- package/schemas/usage-buckets.schema.json +30 -0
- package/schemas/usage-event.schema.json +17 -0
- package/scripts/copy-dashboard-assets.mjs +170 -0
- package/scripts/setup-hooks.cjs +28 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// admin.boot.js
|
|
3
|
+
(function(){
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
// Minimal bootstrapping for the admin UI. Keep this file small so it can be loaded early.
|
|
7
|
+
function showSection(section){
|
|
8
|
+
document.querySelectorAll('.admin-section').forEach(s => s.classList.add('hidden'));
|
|
9
|
+
let activeSection = document.getElementById(section + '-section');
|
|
10
|
+
// Fallback resolution: allow passing full id (e.g. 'overview-section') or data-section name
|
|
11
|
+
if(!activeSection){
|
|
12
|
+
if(section.endsWith('-section')) activeSection = document.getElementById(section);
|
|
13
|
+
if(!activeSection){
|
|
14
|
+
// Try match by prefix (id starts with section)
|
|
15
|
+
activeSection = Array.from(document.querySelectorAll('.admin-section')).find(s=>s.id === section || s.id === section+'-section' || s.id.startsWith(section));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (activeSection) {
|
|
19
|
+
activeSection.classList.remove('hidden');
|
|
20
|
+
} else {
|
|
21
|
+
// Lightweight debug log; keep from spamming
|
|
22
|
+
if(!(window.__lastMissingSection === section)) {
|
|
23
|
+
console.warn('[admin] section not found', section);
|
|
24
|
+
window.__lastMissingSection = section;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Update nav buttons
|
|
28
|
+
document.querySelectorAll('.nav-btn').forEach(btn => {
|
|
29
|
+
const ds = btn.getAttribute('data-section');
|
|
30
|
+
if(ds === section) btn.classList.add('active'); else btn.classList.remove('active');
|
|
31
|
+
});
|
|
32
|
+
window.currentSection = section;
|
|
33
|
+
// Lazy-load graph module when needed (mermaid + elk heavy). This keeps initial boot small.
|
|
34
|
+
if(section === 'graph'){
|
|
35
|
+
ensureGraphModule().then(()=>{
|
|
36
|
+
if(typeof window.initGraphScopeDefaults === 'function') { try { window.initGraphScopeDefaults(); } catch(_){} }
|
|
37
|
+
// Deterministic ready chain replacing earlier ad-hoc reload
|
|
38
|
+
if(typeof window.graphEnsureReadyAndReload === 'function') {
|
|
39
|
+
try { window.graphEnsureReadyAndReload(); } catch{}
|
|
40
|
+
} else if(typeof window.reloadGraphMermaid === 'function') {
|
|
41
|
+
// Fallback
|
|
42
|
+
try { window.reloadGraphMermaid(); } catch{}
|
|
43
|
+
}
|
|
44
|
+
}).catch(()=>{});
|
|
45
|
+
} else if(section === 'instructions') {
|
|
46
|
+
// Ensure instructions module script loaded and then invoke loadInstructions directly as fail-safe.
|
|
47
|
+
ensureInstructionsModule().then(()=>{
|
|
48
|
+
if(typeof window.loadSectionData === 'function') window.loadSectionData(section);
|
|
49
|
+
if(typeof window.loadInstructions === 'function') {
|
|
50
|
+
try { window.loadInstructions(); } catch(e){ /* ignore */ }
|
|
51
|
+
}
|
|
52
|
+
}).catch(()=>{
|
|
53
|
+
if(typeof window.loadInstructions === 'function') {
|
|
54
|
+
try { window.loadInstructions(); } catch(e){ }
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
} else {
|
|
58
|
+
if (typeof window.loadSectionData === 'function') window.loadSectionData(section);
|
|
59
|
+
}
|
|
60
|
+
// Config panel auto-refresh lifecycle
|
|
61
|
+
if (section === 'config') {
|
|
62
|
+
if (typeof window.startConfigAutoRefresh === 'function') window.startConfigAutoRefresh();
|
|
63
|
+
} else {
|
|
64
|
+
if (typeof window.stopConfigAutoRefresh === 'function') window.stopConfigAutoRefresh();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Ensure graph/drilldown heavy module is loaded only once.
|
|
69
|
+
let __graphModuleLoad = null;
|
|
70
|
+
function loadGraphModule(){
|
|
71
|
+
if(__graphModuleLoad) return __graphModuleLoad;
|
|
72
|
+
__graphModuleLoad = (async ()=>{
|
|
73
|
+
try{
|
|
74
|
+
// Scripts are already referenced with defer in admin.html; they may already have executed.
|
|
75
|
+
if(typeof window.reloadGraphMermaid === 'function' && typeof window.initGraphScopeDefaults === 'function') return;
|
|
76
|
+
// Attempt dynamic import fallback for environments that prefer it.
|
|
77
|
+
try { await import('./admin.graph.js'); } catch(e) { /* ignore import failures */ }
|
|
78
|
+
try { await import('./admin.drilldown.js'); } catch(e) { /* ignore */ }
|
|
79
|
+
}catch(e){ /* swallow */ }
|
|
80
|
+
})();
|
|
81
|
+
return __graphModuleLoad;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Public ensure wrapper for symmetry / future retries
|
|
85
|
+
function ensureGraphModule(){ return loadGraphModule(); }
|
|
86
|
+
|
|
87
|
+
// Lightweight loader for instructions module in case defer script failed to execute before navigation.
|
|
88
|
+
let __instructionsModuleLoad = null;
|
|
89
|
+
function ensureInstructionsModule(){
|
|
90
|
+
if(typeof window.loadInstructions === 'function') return Promise.resolve();
|
|
91
|
+
if(__instructionsModuleLoad) return __instructionsModuleLoad;
|
|
92
|
+
__instructionsModuleLoad = (async ()=>{
|
|
93
|
+
// Attempt dynamic import; ignore errors (the static defer script may already exist or path may differ in dist build)
|
|
94
|
+
try { await import('./admin.instructions.js'); } catch(e) { /* ignore */ }
|
|
95
|
+
})();
|
|
96
|
+
return __instructionsModuleLoad;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function startAutoRefresh(){
|
|
100
|
+
if(window.__adminRefresh) clearInterval(window.__adminRefresh);
|
|
101
|
+
window.__adminRefresh = setInterval(()=>{
|
|
102
|
+
if(window.currentSection === 'overview' && typeof window.loadOverviewData === 'function') window.loadOverviewData();
|
|
103
|
+
if(window.currentSection === 'sessions' && typeof window.loadSessions === 'function') window.loadSessions();
|
|
104
|
+
if(window.currentSection === 'maintenance' && typeof window.loadMaintenanceStatus === 'function') window.loadMaintenanceStatus();
|
|
105
|
+
}, 30000);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
document.addEventListener('DOMContentLoaded', function(){
|
|
109
|
+
// expose showSection for inline handlers expected by existing markup
|
|
110
|
+
window.showSection = showSection;
|
|
111
|
+
window.ensureGraphModule = ensureGraphModule;
|
|
112
|
+
window.startAutoRefresh = startAutoRefresh;
|
|
113
|
+
try { showSection('overview'); } catch(e){ /* ignore */ }
|
|
114
|
+
try { startAutoRefresh(); } catch(e){ /* ignore */ }
|
|
115
|
+
try { wireAdminControls(); } catch(e) { /* ignore wiring errors */ }
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Attach event listeners to commonly interacted controls. This reduces reliance on inline attributes.
|
|
119
|
+
function wireAdminControls(){
|
|
120
|
+
// Set defaults before any list rendering (avoid undefined page size causing slice logic oddities)
|
|
121
|
+
if(!window.instructionPageSize) window.instructionPageSize = 25;
|
|
122
|
+
// Wire nav buttons (previously relied on inline onclick attributes)
|
|
123
|
+
document.querySelectorAll('.nav-btn').forEach((btn) => {
|
|
124
|
+
try {
|
|
125
|
+
btn.addEventListener('click', (ev) => {
|
|
126
|
+
// Determine target section by button text or aria/data attribute if present
|
|
127
|
+
let target = btn.getAttribute('data-section');
|
|
128
|
+
if(!target){
|
|
129
|
+
const txt = (btn.textContent || '').toLowerCase();
|
|
130
|
+
if(txt.includes('overview')) target = 'overview';
|
|
131
|
+
else if(txt.includes('config')) target = 'config';
|
|
132
|
+
else if(txt.includes('session')) target = 'sessions';
|
|
133
|
+
else if(txt.includes('maintenance')) target = 'maintenance';
|
|
134
|
+
else if(txt.includes('monitor')) target = 'monitoring';
|
|
135
|
+
else if(txt.includes('instruction')) target = 'instructions';
|
|
136
|
+
else if(txt.includes('graph')) target = 'graph';
|
|
137
|
+
}
|
|
138
|
+
if(target) {
|
|
139
|
+
try { showSection(target); } catch(e){ /* ignore */ }
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
} catch(e){}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Delegated fallback: if an event bubbles from a button inside .admin-nav, handle it.
|
|
146
|
+
const nav = document.querySelector('.admin-nav');
|
|
147
|
+
if(nav && !nav.__delegatedTabs){
|
|
148
|
+
nav.addEventListener('click', (e) => {
|
|
149
|
+
const targetEl = (e.target instanceof HTMLElement) ? (e.target.closest('.nav-btn')) : null;
|
|
150
|
+
if(!targetEl) return;
|
|
151
|
+
const section = targetEl.getAttribute('data-section');
|
|
152
|
+
if(section){
|
|
153
|
+
e.preventDefault();
|
|
154
|
+
try { showSection(section); } catch(err){ /* ignore */ }
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
Object.defineProperty(nav,'__delegatedTabs',{value:true, enumerable:false});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Expose a small debug utility for manual diagnosis in browser console.
|
|
161
|
+
if(!window._debugTabs){
|
|
162
|
+
window._debugTabs = function(){
|
|
163
|
+
const buttons = Array.from(document.querySelectorAll('.nav-btn')).map(function(b){
|
|
164
|
+
return {
|
|
165
|
+
text: (b.textContent || '').trim(),
|
|
166
|
+
ds: b.getAttribute('data-section'),
|
|
167
|
+
hasClick: !!(b._listenerAttached),
|
|
168
|
+
classes: b.className
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
return { currentSection: window.currentSection, buttons: buttons };
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Ensure active state of nav buttons maps to currentSection correctly
|
|
176
|
+
const updateNavActive = () => {
|
|
177
|
+
document.querySelectorAll('.nav-btn').forEach(btn => {
|
|
178
|
+
const target = btn.getAttribute('data-section');
|
|
179
|
+
if(target === window.currentSection) btn.classList.add('active'); else btn.classList.remove('active');
|
|
180
|
+
});
|
|
181
|
+
};
|
|
182
|
+
// Periodically refresh nav active state in case other code changes currentSection
|
|
183
|
+
setInterval(updateNavActive, 600);
|
|
184
|
+
|
|
185
|
+
// Log tail toggle
|
|
186
|
+
const tailBtn = document.getElementById('log-tail-btn');
|
|
187
|
+
if(tailBtn) tailBtn.addEventListener('click', () => { if(typeof window.toggleLogTail === 'function') window.toggleLogTail(); });
|
|
188
|
+
|
|
189
|
+
// Log reload (if input for lines exists)
|
|
190
|
+
const linesInput = document.getElementById('log-lines');
|
|
191
|
+
if(linesInput) linesInput.addEventListener('change', () => { if(typeof window.loadLogs === 'function') window.loadLogs(); });
|
|
192
|
+
|
|
193
|
+
// Backup filter input
|
|
194
|
+
const backupSearch = document.getElementById('backup-search');
|
|
195
|
+
if(backupSearch) backupSearch.addEventListener('input', () => { if(typeof window.filterBackupRows === 'function') window.filterBackupRows(); });
|
|
196
|
+
|
|
197
|
+
// Delegate maintenance control buttons (enable/disable) inside maintenance-control
|
|
198
|
+
const maint = document.getElementById('maintenance-control');
|
|
199
|
+
if(maint) maint.addEventListener('click', (ev) => {
|
|
200
|
+
const el = ev.target;
|
|
201
|
+
if(!(el instanceof HTMLElement)) return;
|
|
202
|
+
if(el.matches('[data-toggle-maint]')){
|
|
203
|
+
const enable = el.getAttribute('data-toggle-maint') === '1';
|
|
204
|
+
if(typeof window.toggleMaintenanceMode === 'function') window.toggleMaintenanceMode(enable);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// System Operations action buttons delegation
|
|
209
|
+
const sysOps = document.querySelector('#maintenance-section .action-buttons');
|
|
210
|
+
if(sysOps && !sysOps.__sysOpsWired){
|
|
211
|
+
sysOps.addEventListener('click', (ev)=>{
|
|
212
|
+
const el = ev.target instanceof HTMLElement ? ev.target.closest('[data-op]') : null;
|
|
213
|
+
if(!el) return;
|
|
214
|
+
const op = el.getAttribute('data-op');
|
|
215
|
+
if(op === 'create-backup' && typeof window.performBackup === 'function') { try { window.performBackup(); } catch(_){} }
|
|
216
|
+
else if(op === 'clear-caches' && typeof window.clearCaches === 'function') { try { window.clearCaches(); } catch(_){} }
|
|
217
|
+
else if(op === 'restart-server' && typeof window.restartServer === 'function') { try { window.restartServer(); } catch(_){} }
|
|
218
|
+
else if(op === 'restore-backup') {
|
|
219
|
+
const sel = document.getElementById('backup-select');
|
|
220
|
+
if(sel && sel.value){
|
|
221
|
+
if(typeof window.restoreBackup === 'function') { try { window.restoreBackup(sel.value); } catch(_){} }
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
Object.defineProperty(sysOps,'__sysOpsWired',{value:true});
|
|
226
|
+
}
|
|
227
|
+
// Convert existing inline handlers to event listeners and observe future additions
|
|
228
|
+
convertInlineHandlers(document);
|
|
229
|
+
const mo = new MutationObserver((records) => {
|
|
230
|
+
for(const r of records){
|
|
231
|
+
r.addedNodes.forEach(n => {
|
|
232
|
+
if(!(n instanceof HTMLElement)) return;
|
|
233
|
+
convertInlineHandlers(n);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
mo.observe(document.documentElement || document.body, { childList: true, subtree: true });
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Replace inline attributes (onclick, oninput, onsubmit) with proper event listeners.
|
|
241
|
+
// Security: Uses a named function dispatch map instead of new Function() (Issue #34 fix).
|
|
242
|
+
// Inline handlers must reference registered function names (e.g., onclick="handleSave(event)")
|
|
243
|
+
function safeExecInlineCode(el, code, event) {
|
|
244
|
+
// Extract function name and arguments from inline handler
|
|
245
|
+
// e.g., "editInstruction('000-bootstrapper')" or "handleSave(event)"
|
|
246
|
+
const match = code.match(/^([a-zA-Z_$][\w$.]*)\s*\(([^)]*)\)/);
|
|
247
|
+
if (match) {
|
|
248
|
+
const fnPath = match[1];
|
|
249
|
+
const argsStr = match[2].trim();
|
|
250
|
+
const parts = fnPath.split('.');
|
|
251
|
+
let fn = window;
|
|
252
|
+
for (const p of parts) {
|
|
253
|
+
if (fn == null) return;
|
|
254
|
+
fn = fn[p];
|
|
255
|
+
}
|
|
256
|
+
if (typeof fn === 'function') {
|
|
257
|
+
try {
|
|
258
|
+
// Parse inline arguments: resolve string literals, numbers, 'event', booleans, null
|
|
259
|
+
const args = argsStr ? argsStr.split(',').map(a => {
|
|
260
|
+
a = a.trim();
|
|
261
|
+
if (a === 'event' || a === 'e') return event;
|
|
262
|
+
if (a === 'this') return el;
|
|
263
|
+
if (a === 'true') return true;
|
|
264
|
+
if (a === 'false') return false;
|
|
265
|
+
if (a === 'null') return null;
|
|
266
|
+
if (a === 'undefined') return undefined;
|
|
267
|
+
// String literal (single or double quoted)
|
|
268
|
+
const strMatch = a.match(/^(['"])(.*)\1$/);
|
|
269
|
+
if (strMatch) return strMatch[2];
|
|
270
|
+
// Number
|
|
271
|
+
if (!isNaN(Number(a)) && a !== '') return Number(a);
|
|
272
|
+
// Fallback: treat as window property reference
|
|
273
|
+
return window[a];
|
|
274
|
+
}) : [];
|
|
275
|
+
fn.apply(el, args);
|
|
276
|
+
} catch (e) { console.error('inline handler failed:', e); }
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Handle guard pattern: "window.fn && window.fn('arg')" or "fn && fn('arg')"
|
|
281
|
+
const guardMatch = code.match(/^[\w$.]+\s*&&\s*([a-zA-Z_$][\w$.]*)\s*\(([^)]*)\)/);
|
|
282
|
+
if (guardMatch) {
|
|
283
|
+
const fnPath2 = guardMatch[1];
|
|
284
|
+
const argsStr2 = guardMatch[2].trim();
|
|
285
|
+
const parts2 = fnPath2.split('.');
|
|
286
|
+
let fn2 = window;
|
|
287
|
+
for (const p of parts2) { if (fn2 == null) return; fn2 = fn2[p]; }
|
|
288
|
+
if (typeof fn2 === 'function') {
|
|
289
|
+
try {
|
|
290
|
+
const args2 = argsStr2 ? argsStr2.split(',').map(a => {
|
|
291
|
+
a = a.trim();
|
|
292
|
+
if (a === 'event' || a === 'e') return event;
|
|
293
|
+
if (a === 'this') return el;
|
|
294
|
+
const sm = a.match(/^(['"])(.*)\1$/);
|
|
295
|
+
if (sm) return sm[2];
|
|
296
|
+
if (!isNaN(Number(a)) && a !== '') return Number(a);
|
|
297
|
+
return window[a];
|
|
298
|
+
}) : [];
|
|
299
|
+
fn2.apply(el, args2);
|
|
300
|
+
} catch (e) { console.error('inline handler failed:', e); }
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
// Fallback: simple known patterns
|
|
305
|
+
if (/^return\s+false\s*;?\s*$/.test(code)) { event.preventDefault(); return; }
|
|
306
|
+
if (/^(this\.(value|checked|disabled)\s*=)/.test(code)) return; // DOM assignment — skip
|
|
307
|
+
console.warn('[admin.boot] Unrecognized inline handler, skipped for security:', code.substring(0, 60));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function convertInlineHandlers(root){
|
|
311
|
+
if(!root || !(root.querySelectorAll)) return;
|
|
312
|
+
// onclick
|
|
313
|
+
root.querySelectorAll('[onclick]').forEach(el => {
|
|
314
|
+
try {
|
|
315
|
+
const code = el.getAttribute('onclick');
|
|
316
|
+
if(!code) return;
|
|
317
|
+
el.removeAttribute('onclick');
|
|
318
|
+
el.addEventListener('click', function(event){
|
|
319
|
+
safeExecInlineCode(this, code, event);
|
|
320
|
+
});
|
|
321
|
+
} catch(e){ /* ignore */ }
|
|
322
|
+
});
|
|
323
|
+
// oninput
|
|
324
|
+
root.querySelectorAll('[oninput]').forEach(el => {
|
|
325
|
+
try {
|
|
326
|
+
const code = el.getAttribute('onput') || el.getAttribute('oninput');
|
|
327
|
+
if(!code) return;
|
|
328
|
+
el.removeAttribute('oninput');
|
|
329
|
+
el.removeAttribute('onput');
|
|
330
|
+
el.addEventListener('input', function(event){
|
|
331
|
+
safeExecInlineCode(this, code, event);
|
|
332
|
+
});
|
|
333
|
+
} catch(e){ /* ignore */ }
|
|
334
|
+
});
|
|
335
|
+
// onchange
|
|
336
|
+
root.querySelectorAll('[onchange]').forEach(el => {
|
|
337
|
+
try {
|
|
338
|
+
const code = el.getAttribute('onchange');
|
|
339
|
+
if(!code) return;
|
|
340
|
+
el.removeAttribute('onchange');
|
|
341
|
+
el.addEventListener('change', function(event){
|
|
342
|
+
safeExecInlineCode(this, code, event);
|
|
343
|
+
});
|
|
344
|
+
} catch(e){ /* ignore */ }
|
|
345
|
+
});
|
|
346
|
+
// onsubmit (for forms) - execute and honor returned false
|
|
347
|
+
root.querySelectorAll('form[onsubmit]').forEach(form => {
|
|
348
|
+
try {
|
|
349
|
+
const code = form.getAttribute('onsubmit');
|
|
350
|
+
if(!code) return;
|
|
351
|
+
form.removeAttribute('onsubmit');
|
|
352
|
+
form.addEventListener('submit', function(event){
|
|
353
|
+
safeExecInlineCode(this, code, event);
|
|
354
|
+
});
|
|
355
|
+
} catch(e){ /* ignore */ }
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
})();
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// Configuration panel – dynamic flags grouped by category with search, auto-refresh, and doc links
|
|
3
|
+
(function(){
|
|
4
|
+
var _configRefreshTimer = null;
|
|
5
|
+
var _collapsedCategories = {};
|
|
6
|
+
|
|
7
|
+
function escapeHtml(s) { return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); }
|
|
8
|
+
|
|
9
|
+
function buildFlagRow(f, featureFlags) {
|
|
10
|
+
var isBool = f.type === 'boolean';
|
|
11
|
+
var currentVal = (f.enabled !== undefined ? (f.enabled ? 'on' : 'off') : (f.value !== undefined ? f.value : '')) || '';
|
|
12
|
+
var control = isBool
|
|
13
|
+
? '<select data-flag="' + escapeHtml(f.name.toLowerCase()) + '" class="form-input cfg-flag-select">'
|
|
14
|
+
+ '<option value="1"' + ((featureFlags[f.name.toLowerCase()] ?? f.enabled) ? ' selected' : '') + '>On</option>'
|
|
15
|
+
+ '<option value="0"' + (!(featureFlags[f.name.toLowerCase()] ?? f.enabled) ? ' selected' : '') + '>Off</option>'
|
|
16
|
+
+ '</select>'
|
|
17
|
+
: '<span class="cfg-flag-ro">' + escapeHtml(currentVal) + '</span>';
|
|
18
|
+
var stabClass = 'cfg-stab-' + (f.stability || 'stable');
|
|
19
|
+
var docHref = f.docAnchor ? ('https://github.com/jagilber-org/index-server/blob/main/docs/configuration.md#' + encodeURIComponent(f.docAnchor)) : '';
|
|
20
|
+
var docIcon = docHref ? ' <a class="cfg-doc-link" href="' + docHref + '" target="_blank" rel="noopener" title="Documentation for ' + escapeHtml(f.name) + '">📖</a>' : '';
|
|
21
|
+
return '<tr class="cfg-flag-row" data-flagname="' + escapeHtml(f.name.toLowerCase()) + '">'
|
|
22
|
+
+ '<td class="cfg-flag-name">' + escapeHtml(f.name) + docIcon + '</td>'
|
|
23
|
+
+ '<td>' + control + '</td>'
|
|
24
|
+
+ '<td class="cfg-flag-default">' + escapeHtml(f.default || '') + '</td>'
|
|
25
|
+
+ '<td class="' + stabClass + '">' + escapeHtml(f.stability || '') + '</td>'
|
|
26
|
+
+ '<td class="cfg-flag-desc">' + escapeHtml(f.description || '') + '</td>'
|
|
27
|
+
+ '</tr>';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function groupByCategory(flags) {
|
|
31
|
+
var groups = {};
|
|
32
|
+
var order = [];
|
|
33
|
+
flags.forEach(function(f) {
|
|
34
|
+
if (!groups[f.category]) { groups[f.category] = []; order.push(f.category); }
|
|
35
|
+
groups[f.category].push(f);
|
|
36
|
+
});
|
|
37
|
+
return { groups: groups, order: order };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function buildFlagsHtml(allFlags, featureFlags) {
|
|
41
|
+
if (!allFlags.length) return '<div class="cfg-no-flags">No feature flags detected</div>';
|
|
42
|
+
var catData = groupByCategory(allFlags);
|
|
43
|
+
var html = '<div class="cfg-flag-filter"><input type="text" id="cfg-flag-search" class="form-input" placeholder="Filter flags..." /></div>';
|
|
44
|
+
catData.order.forEach(function(cat) {
|
|
45
|
+
var collapsed = _collapsedCategories[cat];
|
|
46
|
+
var flags = catData.groups[cat];
|
|
47
|
+
html += '<div class="cfg-category-group" data-category="' + escapeHtml(cat) + '">';
|
|
48
|
+
html += '<div class="cfg-category-header" onclick="toggleConfigCategory(\'' + escapeHtml(cat) + '\')">';
|
|
49
|
+
html += '<span class="cfg-category-chevron">' + (collapsed ? 'â–¶' : 'â–¼') + '</span> ';
|
|
50
|
+
html += '<span class="cfg-category-name">' + escapeHtml(cat.charAt(0).toUpperCase() + cat.slice(1)) + '</span>';
|
|
51
|
+
html += ' <span class="cfg-category-count">(' + flags.length + ')</span>';
|
|
52
|
+
html += '</div>';
|
|
53
|
+
html += '<table class="cfg-flag-table"' + (collapsed ? ' style="display:none"' : '') + '>';
|
|
54
|
+
html += '<thead><tr><th>Flag</th><th>Value</th><th>Default</th><th>Stability</th><th>Description</th></tr></thead>';
|
|
55
|
+
html += '<tbody>';
|
|
56
|
+
flags.forEach(function(f) { html += buildFlagRow(f, featureFlags); });
|
|
57
|
+
html += '</tbody></table>';
|
|
58
|
+
html += '</div>';
|
|
59
|
+
});
|
|
60
|
+
return html;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function loadConfiguration() {
|
|
64
|
+
try {
|
|
65
|
+
var res = await fetch('/api/admin/config');
|
|
66
|
+
var data = await res.json();
|
|
67
|
+
if (!data.success) throw new Error('Failed to load config');
|
|
68
|
+
var cfg = data.config;
|
|
69
|
+
var featureFlags = data.featureFlags || {};
|
|
70
|
+
var allFlags = Array.isArray(data.allFlags) ? data.allFlags : [];
|
|
71
|
+
if (!allFlags.length) {
|
|
72
|
+
try {
|
|
73
|
+
var fres = await fetch('/api/admin/flags');
|
|
74
|
+
var fdata = await fres.json();
|
|
75
|
+
if (fdata.success && Array.isArray(fdata.allFlags)) allFlags = fdata.allFlags;
|
|
76
|
+
} catch(e) { /* ignore */ }
|
|
77
|
+
}
|
|
78
|
+
var refreshedAt = data.timestamp ? new Date(data.timestamp).toLocaleTimeString() : new Date().toLocaleTimeString();
|
|
79
|
+
|
|
80
|
+
var html = '<div class="cfg-panel">'
|
|
81
|
+
+ '<form onsubmit="return updateConfiguration(event)" class="cfg-server-form">'
|
|
82
|
+
+ '<div class="cfg-server-grid">'
|
|
83
|
+
+ '<div class="form-group"><label class="form-label">Max Connections</label>'
|
|
84
|
+
+ '<input class="form-input" type="number" id="cfg-maxConnections" value="' + cfg.serverSettings.maxConnections + '" /></div>'
|
|
85
|
+
+ '<div class="form-group"><label class="form-label">Request Timeout (ms)</label>'
|
|
86
|
+
+ '<input class="form-input" type="number" id="cfg-requestTimeout" value="' + cfg.serverSettings.requestTimeout + '" /></div>'
|
|
87
|
+
+ '<div class="form-group"><label class="form-label">Verbose Logging</label>'
|
|
88
|
+
+ '<select class="form-input" id="cfg-verbose"><option value="1"' + (cfg.serverSettings.enableVerboseLogging ? ' selected' : '') + '>Enabled</option>'
|
|
89
|
+
+ '<option value="0"' + (!cfg.serverSettings.enableVerboseLogging ? ' selected' : '') + '>Disabled</option></select></div>'
|
|
90
|
+
+ '<div class="form-group"><label class="form-label">Enable Mutation</label>'
|
|
91
|
+
+ '<select class="form-input" id="cfg-mutation"><option value="1"' + (cfg.serverSettings.enableMutation ? ' selected' : '') + '>Enabled</option>'
|
|
92
|
+
+ '<option value="0"' + (!cfg.serverSettings.enableMutation ? ' selected' : '') + '>Disabled</option></select></div>'
|
|
93
|
+
+ '<div class="form-group"><label class="form-label">Rate Limit Window (ms)</label>'
|
|
94
|
+
+ '<input class="form-input" type="number" id="cfg-windowMs" value="' + cfg.serverSettings.rateLimit.windowMs + '" /></div>'
|
|
95
|
+
+ '<div class="form-group"><label class="form-label">Rate Limit Max Requests</label>'
|
|
96
|
+
+ '<input class="form-input" type="number" id="cfg-maxRequests" value="' + cfg.serverSettings.rateLimit.maxRequests + '" /></div>'
|
|
97
|
+
+ '</div>'
|
|
98
|
+
+ '<div class="cfg-save-row"><button class="action-btn" type="submit">💾 Save Config</button></div>'
|
|
99
|
+
+ '</form>'
|
|
100
|
+
+ '<div class="cfg-flags-section">'
|
|
101
|
+
+ '<div class="cfg-flags-header">'
|
|
102
|
+
+ '<h3 class="cfg-flags-title">Feature Flags</h3>'
|
|
103
|
+
+ '<span class="cfg-refreshed">Last refreshed: ' + escapeHtml(refreshedAt) + '</span>'
|
|
104
|
+
+ '</div>'
|
|
105
|
+
+ '<div class="cfg-flags-note">All recognized flags grouped by category. Edit boolean flags inline – changes persist to file. Non-boolean flags are read-only.</div>'
|
|
106
|
+
+ buildFlagsHtml(allFlags, featureFlags)
|
|
107
|
+
+ '</div></div>';
|
|
108
|
+
|
|
109
|
+
var target = document.getElementById('config-form');
|
|
110
|
+
if (target) {
|
|
111
|
+
target.innerHTML = html;
|
|
112
|
+
target.classList.remove('loading');
|
|
113
|
+
var searchInput = document.getElementById('cfg-flag-search');
|
|
114
|
+
if (searchInput) searchInput.addEventListener('input', filterConfigFlags);
|
|
115
|
+
}
|
|
116
|
+
} catch (e) {
|
|
117
|
+
var target = document.getElementById('config-form');
|
|
118
|
+
if (target) target.innerHTML = '<div class="error">Failed to load configuration</div>';
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function filterConfigFlags() {
|
|
123
|
+
var term = (document.getElementById('cfg-flag-search') || {}).value;
|
|
124
|
+
if (term === undefined) return;
|
|
125
|
+
term = term.toLowerCase();
|
|
126
|
+
var rows = document.querySelectorAll('.cfg-flag-row');
|
|
127
|
+
rows.forEach(function(row) {
|
|
128
|
+
var name = row.getAttribute('data-flagname') || '';
|
|
129
|
+
var desc = (row.querySelector('.cfg-flag-desc') || {}).textContent || '';
|
|
130
|
+
row.style.display = (name.indexOf(term) !== -1 || desc.toLowerCase().indexOf(term) !== -1) ? '' : 'none';
|
|
131
|
+
});
|
|
132
|
+
// Show all category groups when filtering
|
|
133
|
+
if (term) {
|
|
134
|
+
document.querySelectorAll('.cfg-flag-table').forEach(function(t) { t.style.display = ''; });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function toggleConfigCategory(cat) {
|
|
139
|
+
_collapsedCategories[cat] = !_collapsedCategories[cat];
|
|
140
|
+
var group = document.querySelector('.cfg-category-group[data-category="' + cat + '"]');
|
|
141
|
+
if (!group) return;
|
|
142
|
+
var table = group.querySelector('.cfg-flag-table');
|
|
143
|
+
var chevron = group.querySelector('.cfg-category-chevron');
|
|
144
|
+
if (table) table.style.display = _collapsedCategories[cat] ? 'none' : '';
|
|
145
|
+
if (chevron) chevron.textContent = _collapsedCategories[cat] ? 'â–¶' : 'â–¼';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function startConfigAutoRefresh() {
|
|
149
|
+
stopConfigAutoRefresh();
|
|
150
|
+
_configRefreshTimer = setInterval(function() {
|
|
151
|
+
// Only auto-refresh if config section is visible
|
|
152
|
+
var section = document.getElementById('config-section');
|
|
153
|
+
if (section && !section.classList.contains('hidden')) loadConfiguration();
|
|
154
|
+
}, 15000);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function stopConfigAutoRefresh() {
|
|
158
|
+
if (_configRefreshTimer) { clearInterval(_configRefreshTimer); _configRefreshTimer = null; }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function updateConfiguration(ev) {
|
|
162
|
+
ev.preventDefault();
|
|
163
|
+
var flagSelects = document.querySelectorAll('[data-flag]');
|
|
164
|
+
var featureFlags = {};
|
|
165
|
+
flagSelects.forEach(function(sel) {
|
|
166
|
+
var name = sel.getAttribute('data-flag');
|
|
167
|
+
if (name) featureFlags[name] = sel.value === '1';
|
|
168
|
+
});
|
|
169
|
+
var updates = {
|
|
170
|
+
serverSettings: {
|
|
171
|
+
maxConnections: parseInt(document.getElementById('cfg-maxConnections').value),
|
|
172
|
+
requestTimeout: parseInt(document.getElementById('cfg-requestTimeout').value),
|
|
173
|
+
enableVerboseLogging: document.getElementById('cfg-verbose').value === '1',
|
|
174
|
+
enableMutation: document.getElementById('cfg-mutation').value === '1',
|
|
175
|
+
rateLimit: {
|
|
176
|
+
windowMs: parseInt(document.getElementById('cfg-windowMs').value),
|
|
177
|
+
maxRequests: parseInt(document.getElementById('cfg-maxRequests').value)
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
featureFlags: featureFlags
|
|
181
|
+
};
|
|
182
|
+
try {
|
|
183
|
+
var res = await fetch('/api/admin/config', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(updates)});
|
|
184
|
+
var data = await res.json();
|
|
185
|
+
if (data.success) { if (typeof showSuccess === 'function') showSuccess('Configuration updated'); loadConfiguration(); }
|
|
186
|
+
else { if (typeof showError === 'function') showError(data.error || 'Update failed'); }
|
|
187
|
+
} catch (e) { if (typeof showError === 'function') showError('Update failed'); }
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
window.loadConfiguration = loadConfiguration;
|
|
192
|
+
window.updateConfiguration = updateConfiguration;
|
|
193
|
+
window.toggleConfigCategory = toggleConfigCategory;
|
|
194
|
+
window.startConfigAutoRefresh = startConfigAutoRefresh;
|
|
195
|
+
window.stopConfigAutoRefresh = stopConfigAutoRefresh;
|
|
196
|
+
})();
|