SUMMARY: Fixed critical bug preventing pressure chart and activity timeline demos from initializing. Both components now work correctly on architecture page. ROOT CAUSE: Scripts loaded at end of body after DOM was already ready. DOMContentLoaded event had already fired, so initialization callback never executed. FIX: Changed initialization to check document.readyState before adding event listener: - If DOM still loading → wait for DOMContentLoaded event - If DOM already ready → initialize immediately FILES FIXED: - public/js/components/pressure-chart.js (lines 213-227) - public/js/components/activity-timeline.js (lines 124-137) IMPACT: Both demos now function correctly: ✓ Pressure chart: Simulate button works, gauge animates, metrics update ✓ Activity timeline: Governance flow displays with service colors TESTING: Verified locally on http://localhost:9000/architecture.html Both demos initialize and respond to user interactions. 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
143 lines
4.1 KiB
JavaScript
143 lines
4.1 KiB
JavaScript
/**
|
|
* Framework Activity Timeline
|
|
* Tractatus Framework - Phase 3: Data Visualization
|
|
*
|
|
* Visual timeline showing framework component interactions
|
|
* Color-coded by service
|
|
*/
|
|
|
|
class ActivityTimeline {
|
|
constructor(containerId) {
|
|
this.container = document.getElementById(containerId);
|
|
if (!this.container) {
|
|
console.error(`[ActivityTimeline] Container #${containerId} not found`);
|
|
return;
|
|
}
|
|
|
|
this.events = [
|
|
{
|
|
time: '0ms',
|
|
service: 'instruction',
|
|
name: 'InstructionPersistence',
|
|
action: 'Load HIGH persistence instructions',
|
|
color: '#6366f1'
|
|
},
|
|
{
|
|
time: '50ms',
|
|
service: 'validator',
|
|
name: 'CrossReferenceValidator',
|
|
action: 'Verify request against instruction history',
|
|
color: '#8b5cf6'
|
|
},
|
|
{
|
|
time: '100ms',
|
|
service: 'boundary',
|
|
name: 'BoundaryEnforcer',
|
|
action: 'Check if request requires human approval',
|
|
color: '#10b981'
|
|
},
|
|
{
|
|
time: '150ms',
|
|
service: 'pressure',
|
|
name: 'ContextPressureMonitor',
|
|
action: 'Calculate current pressure level',
|
|
color: '#f59e0b'
|
|
},
|
|
{
|
|
time: '200ms',
|
|
service: 'metacognitive',
|
|
name: 'MetacognitiveVerifier',
|
|
action: 'Verify operation alignment',
|
|
color: '#ec4899'
|
|
},
|
|
{
|
|
time: '250ms',
|
|
service: 'deliberation',
|
|
name: 'PluralisticDeliberation',
|
|
action: 'Coordinate stakeholder perspectives',
|
|
color: '#14b8a6'
|
|
}
|
|
];
|
|
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
this.render();
|
|
console.log('[ActivityTimeline] Initialized');
|
|
}
|
|
|
|
render() {
|
|
const eventsHTML = this.events.map((event, index) => `
|
|
<div class="timeline-event flex items-start space-x-4 p-4 bg-white rounded-lg border-2 border-gray-200 hover:shadow-md cursor-pointer"
|
|
data-service="${event.service}">
|
|
<div class="flex-shrink-0 w-16 text-right">
|
|
<span class="text-sm font-semibold text-gray-600">${event.time}</span>
|
|
</div>
|
|
<div class="flex-shrink-0">
|
|
<div class="w-3 h-3 rounded-full service-dot" data-color="${event.color}"></div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<div class="text-sm font-semibold text-gray-900 service-name" data-color="${event.color}">
|
|
${event.name}
|
|
</div>
|
|
<div class="text-xs text-gray-600 mt-1">${event.action}</div>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
|
|
this.container.innerHTML = `
|
|
<div class="activity-timeline-container">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h3 class="text-lg font-semibold text-gray-900">Governance Flow</h3>
|
|
<span class="text-xs font-medium text-gray-600 uppercase">Request Processing</span>
|
|
</div>
|
|
|
|
<div class="space-y-3">
|
|
${eventsHTML}
|
|
</div>
|
|
|
|
<div class="mt-6 text-xs text-gray-500 text-center">
|
|
Total processing time: 250ms | All services coordinated
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
// Apply colors via JavaScript (CSP-compliant)
|
|
this.applyColors();
|
|
}
|
|
|
|
applyColors() {
|
|
document.querySelectorAll('.service-dot').forEach(dot => {
|
|
const color = dot.getAttribute('data-color');
|
|
dot.style.backgroundColor = color;
|
|
});
|
|
|
|
document.querySelectorAll('.service-name').forEach(name => {
|
|
const color = name.getAttribute('data-color');
|
|
name.style.color = color;
|
|
});
|
|
}
|
|
}
|
|
|
|
// Auto-initialize if container exists
|
|
if (typeof window !== 'undefined') {
|
|
function initActivityTimeline() {
|
|
const container = document.getElementById('activity-timeline');
|
|
if (container) {
|
|
window.activityTimeline = new ActivityTimeline('activity-timeline');
|
|
}
|
|
}
|
|
|
|
// Initialize immediately if DOM is already loaded, otherwise wait for DOMContentLoaded
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', initActivityTimeline);
|
|
} else {
|
|
initActivityTimeline();
|
|
}
|
|
}
|
|
|
|
// Export for module systems
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = ActivityTimeline;
|
|
}
|