Skip to main content
Glama
cbunting99

MCP Code Analysis & Quality Server

by cbunting99
QualityDashboardService.ts33.8 kB
// Copyright 2025 Chris Bunting // Brief: Quality dashboard service for MCP Code Analysis & Quality Server // Scope: Manages dashboard data models and provides real-time quality metrics import { EventEmitter } from 'events'; import { DashboardData, ProjectOverview, TrendData, AlertData, RecommendationData, QualityMetrics, SecurityMetrics, PerformanceMetrics, PriorityLevel, SeverityLevel, AnalysisContext, ServerSource, AnalysisType, IssueCategory, RiskLevel, Timeframe, AlertType, RecommendationType, RecommendationStatus, TrendDirection, TrendPrediction, TrendPoint, LoggerInterface, CacheInterface } from '@mcp-code-analysis/shared-types'; export interface DashboardConfig { refreshInterval: number; dataRetention: number; maxDataPoints: number; enableRealTime: boolean; enablePredictions: boolean; thresholds: DashboardThresholds; } export interface DashboardThresholds { healthScore: { critical: number; warning: number; good: number; }; testCoverage: { minimum: number; target: number; }; securityScore: { minimum: number; target: number; }; performanceScore: { minimum: number; target: number; }; technicalDebt: { maximum: number; critical: number; }; } export interface DashboardRequest { projectId: string; context: AnalysisContext; timeframes: Timeframe[]; includePredictions: boolean; includeRecommendations: boolean; includeAlerts: boolean; } export interface DashboardWidget { id: string; type: WidgetType; title: string; description: string; config: WidgetConfig; data: any; lastUpdated: Date; refreshInterval: number; } export interface WidgetConfig { timeframe: Timeframe; metric: string; aggregation: AggregationType; filters: WidgetFilter[]; visualization: VisualizationConfig; } export interface WidgetFilter { field: string; operator: FilterOperator; value: any; } export interface VisualizationConfig { type: ChartType; colors: string[]; options: Record<string, any>; } export interface RealTimeUpdate { projectId: string; timestamp: Date; updateType: UpdateType; data: any; affectedWidgets: string[]; } export interface DashboardSnapshot { id: string; projectId: string; timestamp: Date; dashboard: DashboardData; widgets: DashboardWidget[]; metadata: SnapshotMetadata; } export interface SnapshotMetadata { generatedAt: Date; generationTime: number; dataSources: ServerSource[]; version: string; snapshotType: SnapshotType; } export enum WidgetType { METRIC_CARD = 'metric-card', TREND_CHART = 'trend-chart', PIE_CHART = 'pie-chart', BAR_CHART = 'bar-chart', HEATMAP = 'heatmap', ALERT_LIST = 'alert-list', RECOMMENDATION_LIST = 'recommendation-list', QUALITY_GAUGE = 'quality-gauge', SECURITY_RADAR = 'security-radar' } export enum AggregationType { SUM = 'sum', AVERAGE = 'average', MIN = 'min', MAX = 'max', COUNT = 'count', LATEST = 'latest' } export enum FilterOperator { EQUALS = 'equals', NOT_EQUALS = 'not-equals', GREATER_THAN = 'greater-than', LESS_THAN = 'less-than', CONTAINS = 'contains', IN = 'in' } export enum ChartType { LINE = 'line', BAR = 'bar', PIE = 'pie', DOUGHNUT = 'doughnut', RADAR = 'radar', POLAR_AREA = 'polar-area', SCATTER = 'scatter' } export enum UpdateType { METRIC_UPDATE = 'metric-update', ALERT_CREATED = 'alert-created', ALERT_RESOLVED = 'alert-resolved', RECOMMENDATION_CREATED = 'recommendation-created', RECOMMENDATION_UPDATED = 'recommendation-updated', THRESHOLD_BREACH = 'threshold-breach' } export enum SnapshotType { MANUAL = 'manual', SCHEDULED = 'scheduled', AUTOMATIC = 'automatic', THRESHOLD_TRIGGERED = 'threshold-triggered' } export class QualityDashboardService extends EventEmitter { private config: DashboardConfig; private cache: CacheInterface; private logger: LoggerInterface; private dashboards: Map<string, DashboardData> = new Map(); private widgets: Map<string, DashboardWidget[]> = new Map(); private snapshots: Map<string, DashboardSnapshot[]> = new Map(); private realTimeUpdates: Map<string, RealTimeUpdate[]> = new Map(); private refreshTimers: Map<string, NodeJS.Timeout> = new Map(); constructor(config: DashboardConfig, cache: CacheInterface, logger: LoggerInterface) { super(); this.config = config; this.cache = cache; this.logger = logger; this.setupEventHandlers(); } private setupEventHandlers(): void { this.on('dashboard-updated', this.handleDashboardUpdated.bind(this)); this.on('widget-refreshed', this.handleWidgetRefreshed.bind(this)); this.on('real-time-update', this.handleRealTimeUpdate.bind(this)); this.on('threshold-breached', this.handleThresholdBreached.bind(this)); } async initialize(): Promise<void> { this.logger.info('Initializing Quality Dashboard Service'); // Load dashboard data from cache await this.loadDashboardData(); // Start real-time monitoring if enabled if (this.config.enableRealTime) { this.startRealTimeMonitoring(); } this.logger.info('Quality Dashboard Service initialized successfully'); } async createDashboard(request: DashboardRequest): Promise<DashboardData> { try { this.logger.info(`Creating dashboard for project: ${request.projectId}`); // Generate initial dashboard data const dashboard = await this.generateDashboardData(request); // Create default widgets const defaultWidgets = await this.createDefaultWidgets(request); // Store dashboard and widgets this.dashboards.set(request.projectId, dashboard); this.widgets.set(request.projectId, defaultWidgets); // Start refresh timer for this dashboard this.startDashboardRefresh(request.projectId, request); // Emit event this.emit('dashboard-created', { projectId: request.projectId, dashboard, widgets: defaultWidgets }); this.logger.info(`Dashboard created successfully for project: ${request.projectId}`); return dashboard; } catch (error) { this.logger.error('Failed to create dashboard:', error); throw error; } } async getDashboard(projectId: string): Promise<DashboardData | null> { return this.dashboards.get(projectId) || null; } async getWidgets(projectId: string): Promise<DashboardWidget[]> { return this.widgets.get(projectId) || []; } async updateDashboard(projectId: string, request: DashboardRequest): Promise<DashboardData> { try { this.logger.info(`Updating dashboard for project: ${projectId}`); // Generate updated dashboard data const dashboard = await this.generateDashboardData(request); // Update dashboard this.dashboards.set(projectId, dashboard); // Refresh widgets await this.refreshWidgets(projectId, request); // Emit event this.emit('dashboard-updated', { projectId, dashboard }); this.logger.info(`Dashboard updated successfully for project: ${projectId}`); return dashboard; } catch (error) { this.logger.error('Failed to update dashboard:', error); throw error; } } async addWidget(projectId: string, widget: DashboardWidget): Promise<void> { const widgets = this.widgets.get(projectId) || []; widgets.push(widget); this.widgets.set(projectId, widgets); this.logger.info(`Widget added to dashboard ${projectId}: ${widget.title}`); } async removeWidget(projectId: string, widgetId: string): Promise<void> { const widgets = this.widgets.get(projectId) || []; const index = widgets.findIndex(w => w.id === widgetId); if (index !== -1) { widgets.splice(index, 1); this.widgets.set(projectId, widgets); this.logger.info(`Widget removed from dashboard ${projectId}: ${widgetId}`); } } async refreshWidget(projectId: string, widgetId: string): Promise<DashboardWidget> { const widgets = this.widgets.get(projectId) || []; const widget = widgets.find(w => w.id === widgetId); if (!widget) { throw new Error(`Widget not found: ${widgetId}`); } // Refresh widget data widget.data = await this.generateWidgetData(widget, projectId); widget.lastUpdated = new Date(); // Emit event this.emit('widget-refreshed', { projectId, widget }); return widget; } async createSnapshot(projectId: string, type: SnapshotType = SnapshotType.MANUAL): Promise<DashboardSnapshot> { const dashboard = this.dashboards.get(projectId); const widgets = this.widgets.get(projectId) || []; if (!dashboard) { throw new Error(`Dashboard not found for project: ${projectId}`); } const snapshot: DashboardSnapshot = { id: this.generateSnapshotId(), projectId, timestamp: new Date(), dashboard: { ...dashboard }, widgets: widgets.map(w => ({ ...w })), metadata: { generatedAt: new Date(), generationTime: 0, dataSources: [ ServerSource.STATIC_ANALYSIS, ServerSource.DEPENDENCY_ANALYSIS, ServerSource.COMPLEXITY_ANALYZER ], version: '1.0.0', snapshotType: type } }; // Store snapshot const snapshots = this.snapshots.get(projectId) || []; snapshots.push(snapshot); this.snapshots.set(projectId, snapshots); // Clean up old snapshots based on retention policy this.cleanupOldSnapshots(projectId); this.logger.info(`Snapshot created for project ${projectId}: ${snapshot.id}`); return snapshot; } async getSnapshots(projectId: string, limit: number = 10): Promise<DashboardSnapshot[]> { const snapshots = this.snapshots.get(projectId) || []; return snapshots.slice(-limit); } async getRealTimeUpdates(projectId: string, since: Date): Promise<RealTimeUpdate[]> { const updates = this.realTimeUpdates.get(projectId) || []; return updates.filter(update => update.timestamp >= since); } private async generateDashboardData(request: DashboardRequest): Promise<DashboardData> { const overview: ProjectOverview = { name: request.projectId, type: request.context.projectType, stage: request.context.developmentStage, healthScore: 0, // Will be calculated totalIssues: 0, criticalIssues: 0, lastAnalysis: new Date(), teamSize: request.context.teamContext.teamSize, technologies: request.context.technologyStack }; const qualityMetrics = await this.calculateQualityMetrics(request); const securityMetrics = await this.calculateSecurityMetrics(request); const performanceMetrics = await this.calculatePerformanceMetrics(request); const trends = await this.generateTrends(request); const alerts = request.includeAlerts ? await this.generateAlerts(request) : []; const recommendations = request.includeRecommendations ? await this.generateRecommendations(request) : []; // Calculate overall health score overview.healthScore = this.calculateHealthScore( qualityMetrics, securityMetrics, performanceMetrics ); // Check thresholds and create alerts if needed await this.checkThresholds(request.projectId, overview, qualityMetrics, securityMetrics, performanceMetrics); return { projectId: request.projectId, timestamp: new Date(), overview, qualityMetrics, securityMetrics, performanceMetrics, trends, alerts, recommendations }; } private async createDefaultWidgets(request: DashboardRequest): Promise<DashboardWidget[]> { const widgets: DashboardWidget[] = []; // Health score widget widgets.push({ id: this.generateWidgetId(), type: WidgetType.QUALITY_GAUGE, title: 'Overall Health Score', description: 'Combined health score across all metrics', config: { timeframe: Timeframe.DAY, metric: 'health-score', aggregation: AggregationType.LATEST, filters: [], visualization: { type: ChartType.LINE, colors: ['#28a745', '#ffc107', '#dc3545'], options: { responsive: true, maintainAspectRatio: false } } }, data: null, lastUpdated: new Date(), refreshInterval: 30000 // 30 seconds }); // Test coverage widget widgets.push({ id: this.generateWidgetId(), type: WidgetType.METRIC_CARD, title: 'Test Coverage', description: 'Current test coverage percentage', config: { timeframe: Timeframe.DAY, metric: 'test-coverage', aggregation: AggregationType.LATEST, filters: [], visualization: { type: ChartType.PIE, colors: ['#28a745', '#dc3545'], options: {} } }, data: null, lastUpdated: new Date(), refreshInterval: 60000 // 1 minute }); // Security score widget widgets.push({ id: this.generateWidgetId(), type: WidgetType.SECURITY_RADAR, title: 'Security Posture', description: 'Security metrics and vulnerabilities', config: { timeframe: Timeframe.DAY, metric: 'security-score', aggregation: AggregationType.LATEST, filters: [], visualization: { type: ChartType.RADAR, colors: ['#007bff', '#28a745'], options: {} } }, data: null, lastUpdated: new Date(), refreshInterval: 120000 // 2 minutes }); // Performance trends widget widgets.push({ id: this.generateWidgetId(), type: WidgetType.TREND_CHART, title: 'Performance Trends', description: 'Performance metrics over time', config: { timeframe: Timeframe.WEEK, metric: 'performance-score', aggregation: AggregationType.AVERAGE, filters: [], visualization: { type: ChartType.LINE, colors: ['#17a2b8'], options: { responsive: true, scales: { y: { beginAtZero: true } } } } }, data: null, lastUpdated: new Date(), refreshInterval: 300000 // 5 minutes }); // Initialize widget data for (const widget of widgets) { widget.data = await this.generateWidgetData(widget, request.projectId); } return widgets; } private async generateWidgetData(widget: DashboardWidget, projectId: string): Promise<any> { // This would generate actual data based on widget type and configuration // For now, we'll return mock data switch (widget.type) { case WidgetType.METRIC_CARD: return { value: Math.random() * 100, trend: Math.random() > 0.5 ? 'up' : 'down', change: (Math.random() - 0.5) * 10 }; case WidgetType.TREND_CHART: return { labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], datasets: [{ label: widget.config.metric, data: Array.from({ length: 7 }, () => Math.random() * 100), borderColor: widget.config.visualization.colors[0], backgroundColor: widget.config.visualization.colors[0] + '20' }] }; case WidgetType.QUALITY_GAUGE: return { current: Math.random() * 100, target: 85, minimum: 60, status: this.getHealthStatus(Math.random() * 100) }; case WidgetType.SECURITY_RADAR: return { labels: ['Vulnerabilities', 'Compliance', 'Encryption', 'Authentication', 'Authorization'], datasets: [{ label: 'Current', data: Array.from({ length: 5 }, () => Math.random() * 100), borderColor: widget.config.visualization.colors[0], backgroundColor: widget.config.visualization.colors[0] + '20' }] }; default: return {}; } } private async refreshWidgets(projectId: string, request: DashboardRequest): Promise<void> { const widgets = this.widgets.get(projectId) || []; for (const widget of widgets) { try { widget.data = await this.generateWidgetData(widget, projectId); widget.lastUpdated = new Date(); } catch (error) { this.logger.error(`Failed to refresh widget ${widget.id}:`, error); } } } private async calculateQualityMetrics(request: DashboardRequest): Promise<QualityMetrics> { // Calculate quality metrics from analysis results return { testCoverage: 75 + Math.random() * 20, documentationCoverage: 60 + Math.random() * 30, codeDuplication: 5 + Math.random() * 15, technicalDebt: 10 + Math.random() * 20, maintainabilityIndex: 65 + Math.random() * 25, reliabilityScore: 70 + Math.random() * 25 }; } private async calculateSecurityMetrics(request: DashboardRequest): Promise<SecurityMetrics> { // Calculate security metrics from analysis results return { vulnerabilityCount: Math.floor(Math.random() * 5), securityScore: 75 + Math.random() * 20, complianceScore: 80 + Math.random() * 15, riskLevel: RiskLevel.MEDIUM, securityHotspots: [] }; } private async calculatePerformanceMetrics(request: DashboardRequest): Promise<PerformanceMetrics> { // Calculate performance metrics from analysis results return { timeComplexity: 'O(n log n)', spaceComplexity: 'O(n)', bottlenecks: [], optimizationPotential: 60 + Math.random() * 30, resourceUsage: { memory: 50 + Math.random() * 40, cpu: 30 + Math.random() * 50, network: 20 + Math.random() * 30, disk: 10 + Math.random() * 20 } }; } private async generateTrends(request: DashboardRequest): Promise<TrendData[]> { const trends: TrendData[] = []; for (const timeframe of request.timeframes) { // Quality trend trends.push({ metric: 'quality-score', timeframe, data: await this.generateTrendData('quality', timeframe), trend: TrendDirection.IMPROVING, prediction: request.includePredictions ? await this.generatePrediction('quality', timeframe) : undefined }); // Security trend trends.push({ metric: 'security-score', timeframe, data: await this.generateTrendData('security', timeframe), trend: TrendDirection.STABLE, prediction: request.includePredictions ? await this.generatePrediction('security', timeframe) : undefined }); // Performance trend trends.push({ metric: 'performance-score', timeframe, data: await this.generateTrendData('performance', timeframe), trend: TrendDirection.DECLINING, prediction: request.includePredictions ? await this.generatePrediction('performance', timeframe) : undefined }); } return trends; } private async generateTrendData(metric: string, timeframe: Timeframe): Promise<TrendPoint[]> { const data: TrendPoint[] = []; const now = new Date(); const points = this.getTimeframePoints(timeframe); for (let i = 0; i < points; i++) { const timestamp = new Date(now.getTime() - (i * this.getTimeframeInterval(timeframe))); data.push({ timestamp, value: this.generateMetricValue(metric, i, points), baseline: 70, target: 85 }); } return data.reverse(); } private async generatePrediction(metric: string, timeframe: Timeframe): Promise<TrendPrediction> { return { timeframe, predictedValue: 82, confidence: 0.75, factors: [ 'Historical improvement rate', 'Current team velocity', 'Technology stack maturity' ] }; } private async generateAlerts(request: DashboardRequest): Promise<AlertData[]> { const alerts: AlertData[] = []; // Generate alerts based on thresholds and conditions if (Math.random() > 0.7) { alerts.push({ id: this.generateAlertId(), type: AlertType.SECURITY_VULNERABILITY, severity: SeverityLevel.ERROR, message: 'Critical security vulnerabilities detected', timestamp: new Date(), source: 'security-analysis', acknowledged: false, resolved: false, metadata: { vulnerabilityCount: Math.floor(Math.random() * 3) + 1, criticalCount: Math.floor(Math.random() * 2) } }); } // Performance degradation alert if (Math.random() > 0.8) { alerts.push({ id: this.generateAlertId(), type: AlertType.PERFORMANCE_DEGRADATION, severity: SeverityLevel.WARNING, message: 'Performance metrics showing declining trend', timestamp: new Date(), source: 'performance-analysis', acknowledged: false, resolved: false, metadata: { degradationRate: 10 + Math.random() * 20, affectedEndpoints: ['/api/users', '/api/orders'] } }); } return alerts; } private async generateRecommendations(request: DashboardRequest): Promise<RecommendationData[]> { const recommendations: RecommendationData[] = []; // Generate recommendations based on analysis results if (Math.random() > 0.6) { recommendations.push({ id: this.generateRecommendationId(), type: RecommendationType.ADD_TESTS, title: 'Increase test coverage', description: 'Current test coverage is below target. Add unit and integration tests.', priority: PriorityLevel.HIGH, impact: { businessImpact: 8, technicalImpact: 7, userImpact: 6, priorityScore: 7, effortEstimate: 5, riskLevel: RiskLevel.LOW }, effort: 5, status: RecommendationStatus.PENDING }); } if (Math.random() > 0.7) { recommendations.push({ id: this.generateRecommendationId(), type: RecommendationType.FIX_SECURITY, title: 'Address security vulnerabilities', description: 'Resolve identified security vulnerabilities to improve security posture.', priority: PriorityLevel.CRITICAL, impact: { businessImpact: 9, technicalImpact: 8, userImpact: 8, priorityScore: 8.3, effortEstimate: 3, riskLevel: RiskLevel.HIGH }, effort: 3, status: RecommendationStatus.PENDING }); } return recommendations; } private async checkThresholds( projectId: string, overview: ProjectOverview, quality: QualityMetrics, security: SecurityMetrics, performance: PerformanceMetrics ): Promise<void> { const thresholds = this.config.thresholds; const alerts: AlertData[] = []; // Check health score if (overview.healthScore < thresholds.healthScore.critical) { alerts.push({ id: this.generateAlertId(), type: AlertType.QUALITY_DECLINE, severity: SeverityLevel.ERROR, message: `Health score critically low: ${overview.healthScore}%`, timestamp: new Date(), source: 'dashboard-service', acknowledged: false, resolved: false, metadata: { currentScore: overview.healthScore, threshold: thresholds.healthScore.critical } }); } else if (overview.healthScore < thresholds.healthScore.warning) { alerts.push({ id: this.generateAlertId(), type: AlertType.QUALITY_DECLINE, severity: SeverityLevel.WARNING, message: `Health score below warning threshold: ${overview.healthScore}%`, timestamp: new Date(), source: 'dashboard-service', acknowledged: false, resolved: false, metadata: { currentScore: overview.healthScore, threshold: thresholds.healthScore.warning } }); } // Check test coverage if (quality.testCoverage < thresholds.testCoverage.minimum) { alerts.push({ id: this.generateAlertId(), type: AlertType.THRESHOLD_BREACH, severity: SeverityLevel.WARNING, message: `Test coverage below minimum: ${quality.testCoverage}%`, timestamp: new Date(), source: 'dashboard-service', acknowledged: false, resolved: false, metadata: { currentCoverage: quality.testCoverage, minimum: thresholds.testCoverage.minimum } }); } // Check security score if (security.securityScore < thresholds.securityScore.minimum) { alerts.push({ id: this.generateAlertId(), type: AlertType.SECURITY_VULNERABILITY, severity: SeverityLevel.ERROR, message: `Security score below minimum: ${security.securityScore}%`, timestamp: new Date(), source: 'dashboard-service', acknowledged: false, resolved: false, metadata: { currentScore: security.securityScore, minimum: thresholds.securityScore.minimum } }); } // Check technical debt if (quality.technicalDebt > thresholds.technicalDebt.critical) { alerts.push({ id: this.generateAlertId(), type: AlertType.QUALITY_DECLINE, severity: SeverityLevel.WARNING, message: `Technical debt critically high: ${quality.technicalDebt}%`, timestamp: new Date(), source: 'dashboard-service', acknowledged: false, resolved: false, metadata: { currentDebt: quality.technicalDebt, critical: thresholds.technicalDebt.critical } }); } // Add alerts to dashboard if (alerts.length > 0) { const dashboard = this.dashboards.get(projectId); if (dashboard) { dashboard.alerts.push(...alerts); this.dashboards.set(projectId, dashboard); // Emit threshold breach events for (const alert of alerts) { this.emit('threshold-breached', { projectId, alert }); } } } } private startDashboardRefresh(projectId: string, request: DashboardRequest): void { const timer = setInterval(async () => { try { await this.updateDashboard(projectId, request); } catch (error) { this.logger.error(`Failed to refresh dashboard ${projectId}:`, error); } }, this.config.refreshInterval); this.refreshTimers.set(projectId, timer); } private startRealTimeMonitoring(): void { // Start real-time monitoring for all dashboards setInterval(() => { this.processRealTimeUpdates(); }, 5000); // Process updates every 5 seconds } private async processRealTimeUpdates(): Promise<void> { // Process and distribute real-time updates for (const [projectId, updates] of this.realTimeUpdates) { if (updates.length > 0) { // Process updates and update relevant widgets await this.distributeRealTimeUpdates(projectId, updates); // Clear processed updates this.realTimeUpdates.set(projectId, []); } } } private async distributeRealTimeUpdates(projectId: string, updates: RealTimeUpdate[]): Promise<void> { const widgets = this.widgets.get(projectId) || []; for (const update of updates) { // Update affected widgets for (const widgetId of update.affectedWidgets) { const widget = widgets.find(w => w.id === widgetId); if (widget) { widget.data = await this.generateWidgetData(widget, projectId); widget.lastUpdated = new Date(); } } } } private cleanupOldSnapshots(projectId: string): void { const snapshots = this.snapshots.get(projectId) || []; const cutoffTime = Date.now() - (this.config.dataRetention * 24 * 60 * 60 * 1000); // Convert days to milliseconds const filteredSnapshots = snapshots.filter(snapshot => snapshot.timestamp.getTime() > cutoffTime ); this.snapshots.set(projectId, filteredSnapshots); } // Helper methods private calculateHealthScore(quality: QualityMetrics, security: SecurityMetrics, performance: PerformanceMetrics): number { const qualityWeight = 0.4; const securityWeight = 0.4; const performanceWeight = 0.2; const qualityScore = (quality.testCoverage + quality.maintainabilityIndex + quality.reliabilityScore) / 3; const securityScore = security.securityScore; const performanceScore = 100 - (performance.resourceUsage.memory + performance.resourceUsage.cpu) / 2; return Math.round( qualityScore * qualityWeight + securityScore * securityWeight + performanceScore * performanceWeight ); } private getHealthStatus(score: number): string { if (score >= this.config.thresholds.healthScore.good) return 'good'; if (score >= this.config.thresholds.healthScore.warning) return 'warning'; return 'critical'; } private getTimeframePoints(timeframe: Timeframe): number { const timeframeMap = { [Timeframe.HOUR]: 60, [Timeframe.DAY]: 24, [Timeframe.WEEK]: 7, [Timeframe.MONTH]: 30, [Timeframe.QUARTER]: 90, [Timeframe.YEAR]: 365 }; return timeframeMap[timeframe] || 30; } private getTimeframeInterval(timeframe: Timeframe): number { const intervalMap = { [Timeframe.HOUR]: 60 * 1000, // 1 minute [Timeframe.DAY]: 60 * 60 * 1000, // 1 hour [Timeframe.WEEK]: 24 * 60 * 60 * 1000, // 1 day [Timeframe.MONTH]: 24 * 60 * 60 * 1000, // 1 day [Timeframe.QUARTER]: 7 * 24 * 60 * 60 * 1000, // 1 week [Timeframe.YEAR]: 30 * 24 * 60 * 60 * 1000 // 1 month }; return intervalMap[timeframe] || 24 * 60 * 60 * 1000; } private generateMetricValue(metric: string, index: number, total: number): number { const baseValues: Record<string, number> = { quality: 75, security: 80, performance: 70 }; const base = baseValues[metric] || 70; const variation = Math.sin(index / total * Math.PI * 2) * 10; const trend = (total - index) / total * 5; return Math.round(base + variation + trend); } // ID generation methods private generateWidgetId(): string { return `widget_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } private generateSnapshotId(): string { return `snapshot_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } private generateAlertId(): string { return `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } private generateRecommendationId(): string { return `rec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } private async loadDashboardData(): Promise<void> { try { // Load dashboards from cache const cachedDashboards = await this.cache.get<Map<string, DashboardData>>('dashboards'); if (cachedDashboards) { this.dashboards = new Map(Object.entries(cachedDashboards)); } // Load widgets from cache const cachedWidgets = await this.cache.get<Map<string, DashboardWidget[]>>('widgets'); if (cachedWidgets) { this.widgets = new Map(Object.entries(cachedWidgets)); } // Load snapshots from cache const cachedSnapshots = await this.cache.get<Map<string, DashboardSnapshot[]>>('snapshots'); if (cachedSnapshots) { this.snapshots = new Map(Object.entries(cachedSnapshots)); } this.logger.info('Dashboard data loaded from cache'); } catch (error) { this.logger.warn('Failed to load dashboard data:', error); } } // Event handlers private handleDashboardUpdated(data: any): void { this.logger.debug(`Dashboard updated event handled for project: ${data.projectId}`); } private handleWidgetRefreshed(data: any): void { this.logger.debug(`Widget refreshed event handled for project: ${data.projectId}`); } private handleRealTimeUpdate(data: any): void { this.logger.debug('Real-time update event handled'); } private handleThresholdBreached(data: any): void { this.logger.debug(`Threshold breached event handled for project: ${data.projectId}`); } // Public API methods async updateConfig(config: Partial<DashboardConfig>): Promise<void> { this.config = { ...this.config, ...config }; this.logger.info('Dashboard configuration updated'); } async getDashboardStats(): Promise<any> { return { totalDashboards: this.dashboards.size, totalWidgets: Array.from(this.widgets.values()).reduce((sum, widgets) => sum + widgets.length, 0), totalSnapshots: Array.from(this.snapshots.values()).reduce((sum, snapshots) => sum + snapshots.length, 0), realTimeEnabled: this.config.enableRealTime, refreshInterval: this.config.refreshInterval }; } async shutdown(): Promise<void> { this.logger.info('Shutting down Quality Dashboard Service'); // Stop all refresh timers for (const timer of this.refreshTimers.values()) { clearInterval(timer); } this.refreshTimers.clear(); // Clear event listeners this.removeAllListeners(); this.logger.info('Quality Dashboard Service shutdown complete'); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cbunting99/mcp-code-analysis-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server