From 7f759e6fd26615e1635ce83ba6672f4d2ed3eb53 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Sat, 24 Jan 2026 22:55:55 +0000 Subject: [PATCH] chore: remove unused frontend code Remove unused utility files: - utils/textWidth.ts - not imported anywhere - utils/extractErrorMessage.ts - not imported anywhere Remove unused exports: - utils/canvasRenderQueue.ts: getRenderQueueStats() - hooks/useBreakpoint.ts: getVisibilityClass(), getPriorityMinWidth() - api/ai.ts: getForecast(), getForecastOverview(), related types - api/patrol.ts: categoryLabels, autonomyLevelLabels (kept used exports) --- frontend-modern/src/api/ai.ts | 116 ---------------- frontend-modern/src/api/patrol.ts | 124 +++++++----------- frontend-modern/src/hooks/useBreakpoint.ts | 18 --- .../src/utils/canvasRenderQueue.ts | 16 --- .../src/utils/extractErrorMessage.ts | 41 ------ frontend-modern/src/utils/textWidth.ts | 12 -- 6 files changed, 46 insertions(+), 281 deletions(-) delete mode 100644 frontend-modern/src/utils/extractErrorMessage.ts delete mode 100644 frontend-modern/src/utils/textWidth.ts diff --git a/frontend-modern/src/api/ai.ts b/frontend-modern/src/api/ai.ts index b8ce816ba..74d1be3c4 100644 --- a/frontend-modern/src/api/ai.ts +++ b/frontend-modern/src/api/ai.ts @@ -16,59 +16,6 @@ import type { LearningStatusResponse, } from '@/types/aiIntelligence'; -const toNumber = (value: unknown, fallback = 0) => { - if (typeof value === 'number' && !Number.isNaN(value)) return value; - if (typeof value === 'string') { - const num = Number(value); - if (!Number.isNaN(num)) return num; - } - return fallback; -}; - -const normalizeForecastResponse = (data: any): ForecastResponse => { - const raw = data?.forecast ?? data; - if (!raw) { - throw new Error('No forecast data available'); - } - - const trendDirection = typeof raw.trend === 'string' ? raw.trend : raw.trend?.direction; - const trend = - trendDirection === 'increasing' || trendDirection === 'decreasing' || trendDirection === 'stable' - ? trendDirection - : 'stable'; - - const currentValue = toNumber(raw.current_value ?? raw.currentValue, 0); - const predictedValue = toNumber(raw.predicted_value ?? raw.predictedValue, currentValue); - const startTime = Date.now(); - const endTime = raw.predicted_at ? new Date(raw.predicted_at).getTime() : startTime; - const points = 12; - const stepMs = points > 1 ? (endTime - startTime) / (points - 1) : 0; - const confidence = Math.min(Math.max(toNumber(raw.confidence, 0), 0), 1); - const baseSpread = Math.max(Math.abs(predictedValue - currentValue) * (1 - confidence + 0.15), Math.abs(currentValue) * 0.05); - - const predictions: ForecastPrediction[] = []; - for (let i = 0; i < points; i += 1) { - const ratio = points > 1 ? i / (points - 1) : 1; - const value = currentValue + (predictedValue - currentValue) * ratio; - const spread = baseSpread * (0.6 + ratio * 0.8); - predictions.push({ - timestamp: new Date(startTime + stepMs * i).toISOString(), - value, - lower_bound: Math.max(0, value - spread), - upper_bound: value + spread, - }); - } - - return { - resource_id: raw.resource_id ?? raw.resourceId ?? '', - metric: raw.metric ?? '', - predictions, - confidence, - trend, - message: raw.description ?? raw.message, - }; -}; - export class AIAPI { private static baseUrl = '/api'; @@ -541,33 +488,6 @@ export class AIAPI { }; } - // ============================================ - // Phase 7: Event-Driven Intelligence API - // ============================================ - - // Get forecast for a metric - static async getForecast(options: { resourceId: string; metric: string; horizonHours?: number }): Promise { - const params = new URLSearchParams(); - params.set('resource_id', options.resourceId); - params.set('metric', options.metric); - if (options.horizonHours) params.set('horizon_hours', String(options.horizonHours)); - const data = await apiFetchJSON(`${this.baseUrl}/ai/forecast?${params.toString()}`); - return normalizeForecastResponse(data); - } - - // Get forecast overview for all resources sorted by urgency - static async getForecastOverview(params: { - metric: string; - horizonHours?: number; - threshold?: number; - }): Promise { - const urlParams = new URLSearchParams(); - urlParams.set('metric', params.metric); - if (params.horizonHours) urlParams.set('horizon_hours', String(params.horizonHours)); - if (params.threshold) urlParams.set('threshold', String(params.threshold)); - return apiFetchJSON(`${this.baseUrl}/ai/forecasts/overview?${urlParams.toString()}`) as Promise; - } - // Remediation plans static async getRemediationPlans(): Promise { const data = await apiFetchJSON(`${this.baseUrl}/ai/remediation/plans`) as { plans?: RemediationPlan[]; executions?: unknown[] }; @@ -658,42 +578,6 @@ export interface UnifiedFindingsResponse { active_count?: number; } -export interface ForecastResponse { - resource_id: string; - metric: string; - predictions: ForecastPrediction[]; - confidence: number; - trend: 'increasing' | 'decreasing' | 'stable'; - message?: string; -} - -export interface ForecastPrediction { - timestamp: string; - value: number; - lower_bound: number; - upper_bound: number; -} - -export interface ForecastOverviewItem { - resource_id: string; - resource_name: string; - resource_type: 'node' | 'vm' | 'lxc'; - metric: string; - current_value: number; - predicted_value: number; - time_to_threshold: number | null; // seconds, null if won't breach - confidence: number; - trend: 'increasing' | 'decreasing' | 'stable' | 'volatile'; -} - -export interface ForecastOverviewResponse { - forecasts: ForecastOverviewItem[]; - metric: string; - threshold: number; - horizon_hours: number; - error?: string; -} - export interface RemediationPlansResponse { plans: RemediationPlan[]; } diff --git a/frontend-modern/src/api/patrol.ts b/frontend-modern/src/api/patrol.ts index 7c71a91a3..2d04f0d81 100644 --- a/frontend-modern/src/api/patrol.ts +++ b/frontend-modern/src/api/patrol.ts @@ -166,66 +166,6 @@ export async function dismissFinding( }); } -/** - * Approve and execute a proposed fix - * @param approvalId The approval ID from the investigation - */ -export async function approveFix(approvalId: string): Promise<{ success: boolean; message: string; output?: string }> { - return apiFetchJSON(`/api/ai/approvals/${approvalId}/approve`, { - method: 'POST', - }); -} - -/** - * Deny/skip a proposed fix - * @param approvalId The approval ID from the investigation - */ -export async function denyFix(approvalId: string): Promise<{ success: boolean; message: string }> { - return apiFetchJSON(`/api/ai/approvals/${approvalId}/deny`, { - method: 'POST', - }); -} - -/** - * Severity color mapping for UI - */ -export const severityColors: Record = { - critical: { bg: 'rgba(220, 38, 38, 0.15)', text: '#ef4444', border: 'rgba(220, 38, 38, 0.3)' }, - warning: { bg: 'rgba(234, 179, 8, 0.15)', text: '#eab308', border: 'rgba(234, 179, 8, 0.3)' }, - watch: { bg: 'rgba(59, 130, 246, 0.15)', text: '#3b82f6', border: 'rgba(59, 130, 246, 0.3)' }, - info: { bg: 'rgba(107, 114, 128, 0.15)', text: '#9ca3af', border: 'rgba(107, 114, 128, 0.3)' }, -}; - -/** - * Category labels for UI - */ -export const categoryLabels: Record = { - performance: 'Performance', - capacity: 'Capacity', - reliability: 'Reliability', - backup: 'Backup', - security: 'Security', - general: 'General', -}; - -/** - * Format a timestamp for display - */ -export function formatTimestamp(ts: string): string { - const date = new Date(ts); - const now = new Date(); - const diffMs = now.getTime() - date.getTime(); - const diffMins = Math.floor(diffMs / 60000); - const diffHours = Math.floor(diffMs / 3600000); - const diffDays = Math.floor(diffMs / 86400000); - - if (diffMins < 1) return 'just now'; - if (diffMins < 60) return `${diffMins}m ago`; - if (diffHours < 24) return `${diffHours}h ago`; - if (diffDays < 7) return `${diffDays}d ago`; - return date.toLocaleDateString(); -} - // ============================================================================= // Patrol Autonomy APIs // ============================================================================= @@ -270,6 +210,52 @@ export async function reinvestigateFinding(findingId: string): Promise<{ success }); } +/** + * Approve and execute a proposed fix + */ +export async function approveFix(approvalId: string): Promise<{ success: boolean; message: string; output?: string }> { + return apiFetchJSON(`/api/ai/approvals/${approvalId}/approve`, { + method: 'POST', + }); +} + +/** + * Deny/skip a proposed fix + */ +export async function denyFix(approvalId: string): Promise<{ success: boolean; message: string }> { + return apiFetchJSON(`/api/ai/approvals/${approvalId}/deny`, { + method: 'POST', + }); +} + +/** + * Severity color mapping for UI + */ +export const severityColors: Record = { + critical: { bg: 'rgba(220, 38, 38, 0.15)', text: '#ef4444', border: 'rgba(220, 38, 38, 0.3)' }, + warning: { bg: 'rgba(234, 179, 8, 0.15)', text: '#eab308', border: 'rgba(234, 179, 8, 0.3)' }, + watch: { bg: 'rgba(59, 130, 246, 0.15)', text: '#3b82f6', border: 'rgba(59, 130, 246, 0.3)' }, + info: { bg: 'rgba(107, 114, 128, 0.15)', text: '#9ca3af', border: 'rgba(107, 114, 128, 0.3)' }, +}; + +/** + * Format a timestamp for display + */ +export function formatTimestamp(ts: string): string { + const date = new Date(ts); + const now = new Date(); + const diffMs = now.getTime() - date.getTime(); + const diffMins = Math.floor(diffMs / 60000); + const diffHours = Math.floor(diffMs / 3600000); + const diffDays = Math.floor(diffMs / 86400000); + + if (diffMins < 1) return 'just now'; + if (diffMins < 60) return `${diffMins}m ago`; + if (diffHours < 24) return `${diffHours}h ago`; + if (diffDays < 7) return `${diffDays}d ago`; + return date.toLocaleDateString(); +} + /** * Investigation status labels for UI */ @@ -292,21 +278,3 @@ export const investigationOutcomeLabels: Record = needs_attention: 'Needs Attention', cannot_fix: 'Cannot Auto-Fix', }; - -/** - * Autonomy level labels for UI - */ -export const autonomyLevelLabels: Record = { - monitor: { - label: 'Monitor Only', - description: 'Detect issues and create findings. No automatic investigation.', - }, - approval: { - label: 'Investigate with Approval', - description: 'Automatically investigate findings. Queue fixes for your approval.', - }, - full: { - label: 'Full Autonomy', - description: 'Automatically investigate and apply non-critical fixes. Critical fixes still require approval.', - }, -}; diff --git a/frontend-modern/src/hooks/useBreakpoint.ts b/frontend-modern/src/hooks/useBreakpoint.ts index 93b92734a..6a6543a5d 100644 --- a/frontend-modern/src/hooks/useBreakpoint.ts +++ b/frontend-modern/src/hooks/useBreakpoint.ts @@ -141,21 +141,3 @@ export function useBreakpoint(): UseBreakpointReturn { }; } -/** - * Get the Tailwind CSS class for hiding an element below a given breakpoint - */ -export function getVisibilityClass(priority: ColumnPriority, display: 'flex' | 'block' | 'table-cell' | 'grid' | 'inline' = 'flex'): string { - const bp = PRIORITY_BREAKPOINTS[priority]; - if (bp === 'xs') { - // Always visible, no hiding class needed - return display; - } - return `hidden ${bp}:${display}`; -} - -/** - * Get the minimum width for a priority level - */ -export function getPriorityMinWidth(priority: ColumnPriority): number { - return BREAKPOINTS[PRIORITY_BREAKPOINTS[priority]]; -} diff --git a/frontend-modern/src/utils/canvasRenderQueue.ts b/frontend-modern/src/utils/canvasRenderQueue.ts index 3a4af70c8..9d1019205 100644 --- a/frontend-modern/src/utils/canvasRenderQueue.ts +++ b/frontend-modern/src/utils/canvasRenderQueue.ts @@ -51,19 +51,3 @@ export function scheduleSparkline(draw: () => void): () => void { }; } -/** - * Get render queue stats for debugging - */ -export function getRenderQueueStats() { - return { - pendingCount: pending.size, - rafScheduled: rafId !== null, - }; -} - -if (import.meta.env.DEV) { - // Expose for debugging in dev mode - (window as any).__canvasRenderQueue = { - getStats: getRenderQueueStats, - }; -} diff --git a/frontend-modern/src/utils/extractErrorMessage.ts b/frontend-modern/src/utils/extractErrorMessage.ts deleted file mode 100644 index 4d704c5e4..000000000 --- a/frontend-modern/src/utils/extractErrorMessage.ts +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Extract a user-friendly error message from an API response. - * Handles various response formats including JSON with error/message fields. - * - * @param response - The Response object from fetch - * @param defaultMessage - Default message if extraction fails - * @returns The extracted error message - */ -export async function extractErrorMessage( - response: Response, - defaultMessage?: string -): Promise { - const fallback = defaultMessage || `Failed with status ${response.status}`; - - try { - const text = await response.text(); - if (!text?.trim()) { - return fallback; - } - - // Try to parse as JSON first - try { - const parsed = JSON.parse(text); - // Check for common error field names - if (typeof parsed?.error === 'string' && parsed.error.trim()) { - return parsed.error.trim(); - } - if (typeof parsed?.message === 'string' && parsed.message.trim()) { - return parsed.message.trim(); - } - } catch { - // Not JSON, fall through to use raw text - } - - // Use raw text if it's non-empty - return text.trim(); - } catch { - // Body read failed - return fallback; - } -} diff --git a/frontend-modern/src/utils/textWidth.ts b/frontend-modern/src/utils/textWidth.ts deleted file mode 100644 index 4b1c4ee6f..000000000 --- a/frontend-modern/src/utils/textWidth.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Estimate text width based on character count. - * Uses an approximation for 10px font size (~5.5-6px per character). - * - * @param text - The text to estimate width for - * @param charWidth - Average character width (default: 5.5) - * @param padding - Additional padding to add (default: 8) - * @returns Estimated width in pixels - */ -export function estimateTextWidth(text: string, charWidth = 5.5, padding = 8): number { - return text.length * charWidth + padding; -}