tractatus/public/js/components/activity-timeline.js
TheFlow bcc4a4e844 fix(demos): resolve initialization timing for pressure chart and activity timeline
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>
2025-10-19 22:10:14 +13:00

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;
}