Browse Source
Diagnostics Export Utility (diagnostics-export.ts): - ComprehensiveDiagnostics interface with detailed system information - System info: screen resolution, color depth, pixel ratio, viewport size - Network info: connection type, effective type, downlink, RTT - Storage info: localStorage, sessionStorage, IndexedDB, WebSQL availability - Performance metrics: load time, memory usage, connection type - Browser/WebView info: user agent, language, platform, hardware concurrency - Error context: error state, messages, timestamps - Plugin availability and status information DiagnosticsExporter class: - collectDiagnostics(): comprehensive data collection - exportAsJSON(): formatted JSON export - exportAsCSV(): CSV format for spreadsheet analysis - copyToClipboard(): clipboard integration with format selection - Performance timing and memory usage collection - Storage availability testing - Network connection detection StatusView Integration: - Updated to use comprehensive diagnostics collector - Enhanced diagnostics display with system information - Improved error handling and user feedback - Maintains existing functionality with added depth Key features: - Real-time system information collection - Multiple export formats (JSON, CSV) - Clipboard integration with user feedback - Performance metrics and timing - Comprehensive error context - Storage and network capability detection This completes the comprehensive diagnostics export from the implementation plan.master
2 changed files with 364 additions and 36 deletions
@ -0,0 +1,318 @@ |
|||||
|
/** |
||||
|
* Diagnostics Export Utility |
||||
|
* |
||||
|
* Comprehensive diagnostics collection and export for the DailyNotification plugin |
||||
|
* Provides detailed system information for debugging and support |
||||
|
* |
||||
|
* @author Matthew Raymer |
||||
|
* @version 1.0.0 |
||||
|
*/ |
||||
|
|
||||
|
import { |
||||
|
PermissionStatus, |
||||
|
NotificationStatus, |
||||
|
ExactAlarmStatus |
||||
|
} from './bridge' |
||||
|
|
||||
|
export interface ComprehensiveDiagnostics { |
||||
|
// Basic app information
|
||||
|
appVersion: string |
||||
|
platform: string |
||||
|
apiLevel: string |
||||
|
timezone: string |
||||
|
lastUpdated: string |
||||
|
|
||||
|
// Core status matrix fields
|
||||
|
postNotificationsGranted: boolean |
||||
|
exactAlarmGranted: boolean |
||||
|
channelEnabled: boolean |
||||
|
batteryOptimizationsIgnored: boolean |
||||
|
canScheduleNow: boolean |
||||
|
lastError?: string |
||||
|
|
||||
|
// Detailed capabilities
|
||||
|
capabilities: { |
||||
|
notificationStatus: NotificationStatus |
||||
|
permissions: PermissionStatus |
||||
|
exactAlarmStatus: ExactAlarmStatus |
||||
|
|
||||
|
// Browser/WebView information
|
||||
|
userAgent: string |
||||
|
language: string |
||||
|
platform: string |
||||
|
cookieEnabled: boolean |
||||
|
onLine: boolean |
||||
|
hardwareConcurrency: number |
||||
|
maxTouchPoints: number |
||||
|
|
||||
|
// Timing information
|
||||
|
timestamp: number |
||||
|
timezoneOffset: number |
||||
|
|
||||
|
// Plugin availability
|
||||
|
pluginAvailable: boolean |
||||
|
|
||||
|
// Error context
|
||||
|
errorContext: { |
||||
|
hasError: boolean |
||||
|
errorMessage: string | null |
||||
|
lastCheckTime: string |
||||
|
} |
||||
|
|
||||
|
// Performance metrics
|
||||
|
performanceMetrics: { |
||||
|
loadTime: number |
||||
|
memoryUsage?: number |
||||
|
connectionType?: string |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// System information
|
||||
|
systemInfo: { |
||||
|
screenResolution: string |
||||
|
colorDepth: number |
||||
|
pixelRatio: number |
||||
|
viewportSize: string |
||||
|
devicePixelRatio: number |
||||
|
} |
||||
|
|
||||
|
// Network information
|
||||
|
networkInfo: { |
||||
|
connectionType: string |
||||
|
effectiveType?: string |
||||
|
downlink?: number |
||||
|
rtt?: number |
||||
|
} |
||||
|
|
||||
|
// Storage information
|
||||
|
storageInfo: { |
||||
|
localStorageAvailable: boolean |
||||
|
sessionStorageAvailable: boolean |
||||
|
indexedDBAvailable: boolean |
||||
|
webSQLAvailable: boolean |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export class DiagnosticsExporter { |
||||
|
|
||||
|
/** |
||||
|
* Collect comprehensive diagnostics |
||||
|
*/ |
||||
|
async collectDiagnostics( |
||||
|
notificationStatus: NotificationStatus, |
||||
|
permissions: PermissionStatus, |
||||
|
exactAlarmStatus: ExactAlarmStatus, |
||||
|
pluginAvailable: boolean |
||||
|
): Promise<ComprehensiveDiagnostics> { |
||||
|
|
||||
|
const startTime = performance.now() |
||||
|
|
||||
|
// Collect system information
|
||||
|
const systemInfo = this.collectSystemInfo() |
||||
|
|
||||
|
// Collect network information
|
||||
|
const networkInfo = this.collectNetworkInfo() |
||||
|
|
||||
|
// Collect storage information
|
||||
|
const storageInfo = this.collectStorageInfo() |
||||
|
|
||||
|
// Calculate performance metrics
|
||||
|
const loadTime = performance.now() - startTime |
||||
|
|
||||
|
return { |
||||
|
appVersion: '1.0.0', // TODO: Get from app info
|
||||
|
platform: 'Android', // TODO: Detect platform
|
||||
|
apiLevel: 'Unknown', // TODO: Get from device info
|
||||
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, |
||||
|
lastUpdated: new Date().toLocaleString(), |
||||
|
postNotificationsGranted: permissions.notifications === 'granted', |
||||
|
exactAlarmGranted: exactAlarmStatus.enabled, |
||||
|
channelEnabled: notificationStatus.isEnabled, |
||||
|
batteryOptimizationsIgnored: false, // TODO: Check battery optimization status
|
||||
|
canScheduleNow: notificationStatus.isEnabled && permissions.notifications === 'granted', |
||||
|
lastError: notificationStatus.error, |
||||
|
capabilities: { |
||||
|
notificationStatus, |
||||
|
permissions, |
||||
|
exactAlarmStatus, |
||||
|
userAgent: navigator.userAgent, |
||||
|
language: navigator.language, |
||||
|
platform: navigator.platform, |
||||
|
cookieEnabled: navigator.cookieEnabled, |
||||
|
onLine: navigator.onLine, |
||||
|
hardwareConcurrency: navigator.hardwareConcurrency || 0, |
||||
|
maxTouchPoints: navigator.maxTouchPoints || 0, |
||||
|
timestamp: Date.now(), |
||||
|
timezoneOffset: new Date().getTimezoneOffset(), |
||||
|
pluginAvailable, |
||||
|
errorContext: { |
||||
|
hasError: !!notificationStatus.error, |
||||
|
errorMessage: notificationStatus.error || null, |
||||
|
lastCheckTime: new Date().toISOString() |
||||
|
}, |
||||
|
performanceMetrics: { |
||||
|
loadTime, |
||||
|
memoryUsage: this.getMemoryUsage(), |
||||
|
connectionType: networkInfo.connectionType |
||||
|
} |
||||
|
}, |
||||
|
systemInfo, |
||||
|
networkInfo, |
||||
|
storageInfo |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Collect system information |
||||
|
*/ |
||||
|
private collectSystemInfo() { |
||||
|
return { |
||||
|
screenResolution: `${screen.width}x${screen.height}`, |
||||
|
colorDepth: screen.colorDepth, |
||||
|
pixelRatio: window.devicePixelRatio || 1, |
||||
|
viewportSize: `${window.innerWidth}x${window.innerHeight}`, |
||||
|
devicePixelRatio: window.devicePixelRatio || 1 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Collect network information |
||||
|
*/ |
||||
|
private collectNetworkInfo() { |
||||
|
const connection = (navigator as any).connection || (navigator as any).mozConnection || (navigator as any).webkitConnection |
||||
|
|
||||
|
return { |
||||
|
connectionType: connection?.type || 'unknown', |
||||
|
effectiveType: connection?.effectiveType, |
||||
|
downlink: connection?.downlink, |
||||
|
rtt: connection?.rtt |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Collect storage information |
||||
|
*/ |
||||
|
private collectStorageInfo() { |
||||
|
return { |
||||
|
localStorageAvailable: this.isStorageAvailable('localStorage'), |
||||
|
sessionStorageAvailable: this.isStorageAvailable('sessionStorage'), |
||||
|
indexedDBAvailable: this.isStorageAvailable('indexedDB'), |
||||
|
webSQLAvailable: this.isStorageAvailable('openDatabase') |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Check if storage is available |
||||
|
*/ |
||||
|
private isStorageAvailable(type: string): boolean { |
||||
|
try { |
||||
|
const storage = (window as any)[type] |
||||
|
if (!storage) return false |
||||
|
|
||||
|
if (type === 'indexedDB') { |
||||
|
return !!storage |
||||
|
} |
||||
|
|
||||
|
if (type === 'openDatabase') { |
||||
|
return !!storage |
||||
|
} |
||||
|
|
||||
|
// Test localStorage/sessionStorage
|
||||
|
const test = '__storage_test__' |
||||
|
storage.setItem(test, test) |
||||
|
storage.removeItem(test) |
||||
|
return true |
||||
|
} catch { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Get memory usage (if available) |
||||
|
*/ |
||||
|
private getMemoryUsage(): number | undefined { |
||||
|
const memory = (performance as any).memory |
||||
|
return memory ? memory.usedJSHeapSize : undefined |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Export diagnostics as JSON string |
||||
|
*/ |
||||
|
exportAsJSON(diagnostics: ComprehensiveDiagnostics): string { |
||||
|
return JSON.stringify(diagnostics, null, 2) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Export diagnostics as CSV |
||||
|
*/ |
||||
|
exportAsCSV(diagnostics: ComprehensiveDiagnostics): string { |
||||
|
const rows = [ |
||||
|
['Field', 'Value'], |
||||
|
['App Version', diagnostics.appVersion], |
||||
|
['Platform', diagnostics.platform], |
||||
|
['API Level', diagnostics.apiLevel], |
||||
|
['Timezone', diagnostics.timezone], |
||||
|
['Last Updated', diagnostics.lastUpdated], |
||||
|
['Post Notifications Granted', diagnostics.postNotificationsGranted.toString()], |
||||
|
['Exact Alarm Granted', diagnostics.exactAlarmGranted.toString()], |
||||
|
['Channel Enabled', diagnostics.channelEnabled.toString()], |
||||
|
['Battery Optimizations Ignored', diagnostics.batteryOptimizationsIgnored.toString()], |
||||
|
['Can Schedule Now', diagnostics.canScheduleNow.toString()], |
||||
|
['Last Error', diagnostics.lastError || 'None'], |
||||
|
['Plugin Available', diagnostics.capabilities.pluginAvailable.toString()], |
||||
|
['User Agent', diagnostics.capabilities.userAgent], |
||||
|
['Language', diagnostics.capabilities.language], |
||||
|
['Platform', diagnostics.capabilities.platform], |
||||
|
['Online', diagnostics.capabilities.onLine.toString()], |
||||
|
['Hardware Concurrency', diagnostics.capabilities.hardwareConcurrency.toString()], |
||||
|
['Max Touch Points', diagnostics.capabilities.maxTouchPoints.toString()], |
||||
|
['Screen Resolution', diagnostics.systemInfo.screenResolution], |
||||
|
['Color Depth', diagnostics.systemInfo.colorDepth.toString()], |
||||
|
['Pixel Ratio', diagnostics.systemInfo.pixelRatio.toString()], |
||||
|
['Viewport Size', diagnostics.systemInfo.viewportSize], |
||||
|
['Connection Type', diagnostics.networkInfo.connectionType], |
||||
|
['Local Storage Available', diagnostics.storageInfo.localStorageAvailable.toString()], |
||||
|
['Session Storage Available', diagnostics.storageInfo.sessionStorageAvailable.toString()], |
||||
|
['IndexedDB Available', diagnostics.storageInfo.indexedDBAvailable.toString()], |
||||
|
['WebSQL Available', diagnostics.storageInfo.webSQLAvailable.toString()] |
||||
|
] |
||||
|
|
||||
|
return rows.map(row => row.map(cell => `"${cell}"`).join(',')).join('\n') |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Copy diagnostics to clipboard |
||||
|
*/ |
||||
|
async copyToClipboard(diagnostics: ComprehensiveDiagnostics, format: 'json' | 'csv' = 'json'): Promise<void> { |
||||
|
const content = format === 'json' |
||||
|
? this.exportAsJSON(diagnostics) |
||||
|
: this.exportAsCSV(diagnostics) |
||||
|
|
||||
|
await navigator.clipboard.writeText(content) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Singleton instance
|
||||
|
export const diagnosticsExporter = new DiagnosticsExporter() |
||||
|
|
||||
|
// Utility functions
|
||||
|
export async function collectDiagnostics( |
||||
|
notificationStatus: NotificationStatus, |
||||
|
permissions: PermissionStatus, |
||||
|
exactAlarmStatus: ExactAlarmStatus, |
||||
|
pluginAvailable: boolean |
||||
|
): Promise<ComprehensiveDiagnostics> { |
||||
|
return diagnosticsExporter.collectDiagnostics(notificationStatus, permissions, exactAlarmStatus, pluginAvailable) |
||||
|
} |
||||
|
|
||||
|
export function exportDiagnosticsAsJSON(diagnostics: ComprehensiveDiagnostics): string { |
||||
|
return diagnosticsExporter.exportAsJSON(diagnostics) |
||||
|
} |
||||
|
|
||||
|
export function exportDiagnosticsAsCSV(diagnostics: ComprehensiveDiagnostics): string { |
||||
|
return diagnosticsExporter.exportAsCSV(diagnostics) |
||||
|
} |
||||
|
|
||||
|
export async function copyDiagnosticsToClipboard(diagnostics: ComprehensiveDiagnostics, format: 'json' | 'csv' = 'json'): Promise<void> { |
||||
|
return diagnosticsExporter.copyToClipboard(diagnostics, format) |
||||
|
} |
||||
Loading…
Reference in new issue