Advanced Dashboard Integration
This guide demonstrates advanced dashboard integration patterns for building sophisticated compliance monitoring and management interfaces with custom widgets and multi-framework support.
Advanced Dashboard Architecture
Multi-Framework Dashboard
interface AdvancedDashboardConfig {
frameworks: string[];
// realTimeUpdates: boolean; // Aspirational - not yet implemented
customWidgets: WidgetConfig[];
userPreferences: UserPreferences;
alerting: AlertConfig;
reporting: ReportConfig;
}
class AdvancedComplianceDashboard {
private config: AdvancedDashboardConfig;
// private wsConnections: Map<string, WebSocket> = new Map(); // Aspirational - WebSocket not yet implemented
private widgetRegistry: Map<string, Widget> = new Map();
private eventBus: EventBus;
constructor(config: AdvancedDashboardConfig) {
this.config = config;
this.eventBus = new EventBus();
this.initializeFrameworks();
// this.setupRealTimeConnections(); // Aspirational - WebSocket not yet implemented
this.registerDefaultWidgets();
}
private async initializeFrameworks(): Promise<void> {
for (const framework of this.config.frameworks) {
const frameworkData = await this.loadFrameworkData(framework);
this.eventBus.emit('framework:loaded', {
framework,
data: frameworkData,
});
}
}
/* Aspirational - WebSocket not yet implemented
private setupRealTimeConnections(): void {
if (!this.config.realTimeUpdates) return;
this.config.frameworks.forEach((framework) => {
const ws = new WebSocket(
`wss://api.supernal-coding.com/v1/ws/${framework}`
);
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleRealTimeUpdate(framework, data);
};
this.wsConnections.set(framework, ws);
});
}
*/
public addCustomWidget(widget: Widget): void {
this.widgetRegistry.set(widget.id, widget);
this.eventBus.emit('widget:registered', widget);
}
public createDashboardLayout(): DashboardLayout {
return {
header: this.createHeaderSection(),
sidebar: this.createSidebarNavigation(),
main: this.createMainContent(),
footer: this.createFooterSection(),
};
}
}
Custom Widget System
abstract class Widget {
abstract id: string;
abstract title: string;
abstract render(): HTMLElement;
abstract update(data: any): void;
protected eventBus: EventBus;
protected config: WidgetConfig;
constructor(config: WidgetConfig, eventBus: EventBus) {
this.config = config;
this.eventBus = eventBus;
}
}
class ComplianceScoreWidget extends Widget {
id = 'compliance-score';
title = 'Compliance Score';
private currentScore = 0;
private targetScore = 90;
private trend: 'up' | 'down' | 'stable' = 'stable';
render(): HTMLElement {
const container = document.createElement('div');
container.className = 'compliance-score-widget';
container.innerHTML = `
<div class="widget-header">
<h3>${this.title}</h3>
<div class="widget-actions">
<button class="refresh-btn">🔄</button>
<button class="settings-btn">⚙️</button>
</div>
</div>
<div class="score-display">
<div class="score-circle">
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="45" fill="none" stroke="#e0e0e0" stroke-width="8"/>
<circle cx="50" cy="50" r="45" fill="none" stroke="#4caf50"
stroke-width="8" stroke-dasharray="283"
stroke-dashoffset="${283 - (283 * this.currentScore) / 100}"
transform="rotate(-90 50 50)"/>
</svg>
<div class="score-text">
<span class="score-value">${this.currentScore}%</span>
<span class="score-trend ${this.trend}">${this.getTrendIcon()}</span>
</div>
</div>
<div class="score-details">
<div class="target">Target: ${this.targetScore}%</div>
<div class="frameworks">
${this.config.frameworks?.map((f) => `<span class="framework-tag">${f}</span>`).join('')}
</div>
</div>
</div>
`;
this.attachEventListeners(container);
return container;
}
update(data: { score: number; trend: 'up' | 'down' | 'stable' }): void {
this.currentScore = data.score;
this.trend = data.trend;
// Animate score change
this.animateScoreChange();
// Update trend indicator
this.updateTrendIndicator();
}
private getTrendIcon(): string {
switch (this.trend) {
case 'up':
return '📈';
case 'down':
return '📉';
case 'stable':
return '➡️';
}
}
private animateScoreChange(): void {
// Smooth animation implementation
const circle = this.container?.querySelector(
'circle[stroke="#4caf50"]'
) as SVGCircleElement;
if (circle) {
const newOffset = 283 - (283 * this.currentScore) / 100;
circle.style.transition = 'stroke-dashoffset 1s ease-in-out';
circle.style.strokeDashoffset = newOffset.toString();
}
}
}
class RequirementStatusWidget extends Widget {
id = 'requirement-status';
title = 'Requirements Status';
render(): HTMLElement {
const container = document.createElement('div');
container.className = 'requirement-status-widget';
container.innerHTML = `
<div class="widget-header">
<h3>${this.title}</h3>
<div class="filter-controls">
<select class="framework-filter">
<option value="all">All Frameworks</option>
${this.config.frameworks?.map((f) => `<option value="${f}">${f}</option>`).join('')}
</select>
</div>
</div>
<div class="status-grid">
<div class="status-card completed">
<div class="status-icon">✅</div>
<div class="status-count" data-status="completed">0</div>
<div class="status-label">Completed</div>
</div>
<div class="status-card in-progress">
<div class="status-icon">🔄</div>
<div class="status-count" data-status="in-progress">0</div>
<div class="status-label">In Progress</div>
</div>
<div class="status-card pending">
<div class="status-icon">⏳</div>
<div class="status-count" data-status="pending">0</div>
<div class="status-label">Pending</div>
</div>
<div class="status-card failed">
<div class="status-icon">❌</div>
<div class="status-count" data-status="failed">0</div>
<div class="status-label">Failed</div>
</div>
</div>
<div class="requirement-list">
<div class="list-header">
<span>Recent Updates</span>
<button class="view-all-btn">View All</button>
</div>
<div class="requirement-items"></div>
</div>
`;
return container;
}
update(data: RequirementStatusData): void {
// Update status counts
Object.entries(data.counts).forEach(([status, count]) => {
const element = this.container?.querySelector(
`[data-status="${status}"]`
);
if (element) {
element.textContent = count.toString();
}
});
// Update recent requirements list
this.updateRequirementsList(data.recent);
}
}
Real-Time Data Synchronization (Aspirational)
/* Aspirational - WebSocket not yet implemented
class RealTimeDashboardSync {
private dashboard: AdvancedComplianceDashboard;
private syncInterval: number = 30000; // 30 seconds
private wsReconnectAttempts = 0;
private maxReconnectAttempts = 5;
constructor(dashboard: AdvancedComplianceDashboard) {
this.dashboard = dashboard;
this.setupPeriodicSync();
this.setupWebSocketSync();
}
private setupPeriodicSync(): void {
setInterval(async () => {
try {
const data = await this.fetchLatestData();
this.dashboard.updateAllWidgets(data);
} catch (error) {
console.error('Periodic sync failed:', error);
}
}, this.syncInterval);
}
private setupWebSocketSync(): void {
const ws = new WebSocket('wss://api.supernal-coding.com/v1/dashboard/sync'); // Aspirational API
ws.onopen = () => {
console.log('Dashboard sync connected');
this.wsReconnectAttempts = 0;
// Subscribe to all relevant events
ws.send(
JSON.stringify({
type: 'subscribe',
events: [
'compliance.score_changed',
'requirement.status_changed',
'audit.finding_created',
'framework.updated',
],
})
);
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleRealTimeUpdate(data);
};
ws.onclose = () => {
console.log('Dashboard sync disconnected');
this.attemptReconnect();
};
ws.onerror = (error) => {
console.error('Dashboard sync error:', error);
};
}
private handleRealTimeUpdate(data: any): void {
switch (data.type) {
case 'compliance.score_changed':
this.dashboard.updateWidget('compliance-score', {
score: data.newScore,
trend: data.trend,
});
break;
case 'requirement.status_changed':
this.dashboard.updateWidget('requirement-status', {
requirementId: data.requirementId,
newStatus: data.newStatus,
timestamp: data.timestamp,
});
break;
case 'audit.finding_created':
this.dashboard.showNotification({
type: 'warning',
title: 'New Audit Finding',
message: `Finding created for ${data.framework}: ${data.description}`,
actions: [
{
label: 'View Details',
action: () => this.openAuditFinding(data.findingId),
},
],
});
break;
}
}
private attemptReconnect(): void {
if (this.wsReconnectAttempts < this.maxReconnectAttempts) {
const delay = Math.pow(2, this.wsReconnectAttempts) * 1000;
setTimeout(() => {
this.wsReconnectAttempts++;
this.setupWebSocketSync();
}, delay);
}
}
}
*/
Advanced Visualization Components
Compliance Trend Chart
class ComplianceTrendChart {
private canvas: HTMLCanvasElement;
private ctx: CanvasRenderingContext2D;
private data: TrendData[];
private config: ChartConfig;
constructor(container: HTMLElement, config: ChartConfig) {
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d')!;
this.config = config;
container.appendChild(this.canvas);
this.setupCanvas();
}
public updateData(data: TrendData[]): void {
this.data = data;
this.render();
}
private render(): void {
this.clearCanvas();
this.drawAxes();
this.drawTrendLines();
this.drawDataPoints();
this.drawLegend();
}
private drawTrendLines(): void {
this.config.frameworks.forEach((framework, index) => {
const color = this.getFrameworkColor(framework);
const frameworkData = this.data.filter((d) => d.framework === framework);
this.ctx.strokeStyle = color;
this.ctx.lineWidth = 2;
this.ctx.beginPath();
frameworkData.forEach((point, i) => {
const x = this.getXPosition(point.timestamp);
const y = this.getYPosition(point.score);
if (i === 0) {
this.ctx.moveTo(x, y);
} else {
this.ctx.lineTo(x, y);
}
});
this.ctx.stroke();
});
}
}
Interactive Requirement Matrix
class RequirementMatrix {
private container: HTMLElement;
private matrix: RequirementMatrixData;
private selectedCell: { framework: string; category: string } | null = null;
constructor(container: HTMLElement) {
this.container = container;
this.render();
}
public updateMatrix(matrix: RequirementMatrixData): void {
this.matrix = matrix;
this.render();
}
private render(): void {
const table = document.createElement('table');
table.className = 'requirement-matrix';
// Create header
const header = this.createHeader();
table.appendChild(header);
// Create rows for each framework
this.matrix.frameworks.forEach((framework) => {
const row = this.createFrameworkRow(framework);
table.appendChild(row);
});
this.container.innerHTML = '';
this.container.appendChild(table);
this.attachEventListeners();
}
private createFrameworkRow(framework: FrameworkData): HTMLTableRowElement {
const row = document.createElement('tr');
row.className = 'framework-row';
// Framework name cell
const nameCell = document.createElement('td');
nameCell.className = 'framework-name';
nameCell.textContent = framework.name;
row.appendChild(nameCell);
// Category cells
this.matrix.categories.forEach((category) => {
const cell = document.createElement('td');
cell.className = 'matrix-cell';
const requirements = framework.requirements.filter(
(r) => r.category === category
);
const completionRate = this.calculateCompletionRate(requirements);
cell.innerHTML = `
<div class="cell-content">
<div class="completion-rate" style="background-color: ${this.getCompletionColor(completionRate)}">
${completionRate}%
</div>
<div class="requirement-count">${requirements.length}</div>
</div>
`;
cell.dataset.framework = framework.name;
cell.dataset.category = category;
row.appendChild(cell);
});
return row;
}
private attachEventListeners(): void {
this.container.addEventListener('click', (event) => {
const cell = (event.target as Element).closest(
'.matrix-cell'
) as HTMLElement;
if (cell) {
const framework = cell.dataset.framework!;
const category = cell.dataset.category!;
this.selectCell(framework, category);
this.showCellDetails(framework, category);
}
});
}
private showCellDetails(framework: string, category: string): void {
const requirements = this.getRequirementsForCell(framework, category);
const modal = document.createElement('div');
modal.className = 'matrix-detail-modal';
modal.innerHTML = `
<div class="modal-content">
<div class="modal-header">
<h3>${framework} - ${category}</h3>
<button class="close-btn">×</button>
</div>
<div class="modal-body">
<div class="requirements-list">
${requirements
.map(
(req) => `
<div class="requirement-item ${req.status}">
<div class="req-id">${req.id}</div>
<div class="req-title">${req.title}</div>
<div class="req-status">${req.status}</div>
<div class="req-actions">
<button onclick="openRequirement('${req.id}')">View</button>
<button onclick="editRequirement('${req.id}')">Edit</button>
</div>
</div>
`
)
.join('')}
</div>
</div>
</div>
`;
document.body.appendChild(modal);
// Close modal functionality
modal.querySelector('.close-btn')?.addEventListener('click', () => {
modal.remove();
});
}
}
Performance Optimization
Lazy Loading and Virtualization
class VirtualizedDashboard {
private visibleWidgets: Set<string> = new Set();
private widgetPool: Map<string, Widget> = new Map();
private intersectionObserver: IntersectionObserver;
constructor() {
this.setupIntersectionObserver();
}
private setupIntersectionObserver(): void {
this.intersectionObserver = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
const widgetId = entry.target.getAttribute('data-widget-id')!;
if (entry.isIntersecting) {
this.loadWidget(widgetId);
} else {
this.unloadWidget(widgetId);
}
});
},
{
rootMargin: '100px',
threshold: 0.1,
}
);
}
private loadWidget(widgetId: string): void {
if (this.visibleWidgets.has(widgetId)) return;
const widget = this.widgetPool.get(widgetId);
if (widget) {
widget.mount();
widget.startDataSync();
this.visibleWidgets.add(widgetId);
}
}
private unloadWidget(widgetId: string): void {
if (!this.visibleWidgets.has(widgetId)) return;
const widget = this.widgetPool.get(widgetId);
if (widget) {
widget.stopDataSync();
widget.unmount();
this.visibleWidgets.delete(widgetId);
}
}
}
Caching and Data Management
class DashboardDataManager {
private cache: Map<string, CacheEntry> = new Map();
private cacheTimeout = 5 * 60 * 1000; // 5 minutes
private requestQueue: Map<string, Promise<any>> = new Map();
async getData(key: string, fetcher: () => Promise<any>): Promise<any> {
// Check cache first
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.data;
}
// Check if request is already in progress
if (this.requestQueue.has(key)) {
return this.requestQueue.get(key);
}
// Make new request
const promise = fetcher()
.then((data) => {
this.cache.set(key, {
data,
timestamp: Date.now(),
});
this.requestQueue.delete(key);
return data;
})
.catch((error) => {
this.requestQueue.delete(key);
throw error;
});
this.requestQueue.set(key, promise);
return promise;
}
invalidateCache(pattern?: string): void {
if (pattern) {
const regex = new RegExp(pattern);
for (const key of this.cache.keys()) {
if (regex.test(key)) {
this.cache.delete(key);
}
}
} else {
this.cache.clear();
}
}
}
Related Documentation
- WebSocket Integration - Real-time communication setup
- Dashboard Integration - Basic dashboard integration
- Integration Examples - Main integration examples
- API Reference - API documentation
Advanced dashboard integration enables sophisticated compliance monitoring with real-time updates, custom visualizations, and optimized performance for large-scale compliance management.