From 2dbd32a16b6e68963dcd908e9bd03a0f7fd42fed Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 23 Dec 2025 11:58:23 +0000 Subject: [PATCH] Refine v5 release: UI consistency and logging cleanup --- frontend-modern/src/api/ai.ts | 4 +-- frontend-modern/src/api/patrol.ts | 3 +- .../src/components/AI/GuestNotes.tsx | 15 +++++---- .../src/components/FirstRunSetup.tsx | 3 +- .../src/components/Settings/UnifiedAgents.tsx | 32 ++++++++++++------- .../SetupWizard/steps/CompleteStep.tsx | 5 +-- .../shared/AIImpactTimelinePanel.tsx | 3 +- .../src/components/shared/AIInsightsPanel.tsx | 3 +- .../src/components/shared/AIOverviewTable.tsx | 3 +- .../shared/AIRecentChangesPanel.tsx | 3 +- frontend-modern/src/pages/Alerts.tsx | 6 ++-- frontend-modern/src/stores/aiChat.ts | 5 +-- frontend-modern/src/stores/metricsViewMode.ts | 5 +-- 13 files changed, 54 insertions(+), 36 deletions(-) diff --git a/frontend-modern/src/api/ai.ts b/frontend-modern/src/api/ai.ts index f1f9a3936..aa4c0c113 100644 --- a/frontend-modern/src/api/ai.ts +++ b/frontend-modern/src/api/ai.ts @@ -272,7 +272,7 @@ export class AIAPI { try { for (; ;) { if (Date.now() - lastEventTime > STREAM_TIMEOUT_MS) { - console.warn('[AI] Alert investigation stream timeout'); + logger.warn('[AI] Alert investigation stream timeout'); break; } @@ -310,7 +310,7 @@ export class AIAPI { const data = JSON.parse(jsonStr); onEvent(data as AIStreamEvent); } catch (e) { - console.error('[AI] Failed to parse investigation event:', e); + logger.error('[AI] Failed to parse investigation event:', e); } } } diff --git a/frontend-modern/src/api/patrol.ts b/frontend-modern/src/api/patrol.ts index 454930762..ffed8ae28 100644 --- a/frontend-modern/src/api/patrol.ts +++ b/frontend-modern/src/api/patrol.ts @@ -4,6 +4,7 @@ */ import { apiFetchJSON } from '@/utils/apiClient'; +import { logger } from '@/utils/logger'; export type FindingSeverity = 'info' | 'watch' | 'warning' | 'critical'; export type FindingCategory = 'performance' | 'capacity' | 'reliability' | 'backup' | 'security' | 'general'; @@ -339,7 +340,7 @@ export function subscribeToPatrolStream( const data = JSON.parse(event.data) as PatrolStreamEvent; onEvent(data); } catch (e) { - console.error('Failed to parse patrol stream event:', e); + logger.error('Failed to parse patrol stream event:', e); } }; diff --git a/frontend-modern/src/components/AI/GuestNotes.tsx b/frontend-modern/src/components/AI/GuestNotes.tsx index fac1e8f6a..d9dc76295 100644 --- a/frontend-modern/src/components/AI/GuestNotes.tsx +++ b/frontend-modern/src/components/AI/GuestNotes.tsx @@ -1,6 +1,7 @@ import { Component, createSignal, createEffect, For, Show, createMemo } from 'solid-js'; import { notificationStore } from '@/stores/notifications'; import { apiFetch } from '@/utils/apiClient'; +import { logger } from '@/utils/logger'; interface Note { id: string; @@ -146,7 +147,7 @@ export const GuestNotes: Component = (props) => { } } } catch (error) { - console.error('Failed to load guest knowledge:', error); + logger.error('Failed to load guest knowledge:', error); } finally { setIsLoading(false); } @@ -169,7 +170,7 @@ export const GuestNotes: Component = (props) => { notificationStore.error('Failed to save guest URL'); } } catch (error) { - console.error('Failed to save guest URL:', error); + logger.error('Failed to save guest URL:', error); notificationStore.error('Failed to save guest URL'); } finally { setIsSavingUrl(false); @@ -207,7 +208,7 @@ export const GuestNotes: Component = (props) => { notificationStore.error('Failed to save note'); } } catch (error) { - console.error('Failed to save note:', error); + logger.error('Failed to save note:', error); notificationStore.error('Failed to save note'); } }; @@ -231,7 +232,7 @@ export const GuestNotes: Component = (props) => { notificationStore.error('Failed to delete note'); } } catch (error) { - console.error('Failed to delete note:', error); + logger.error('Failed to delete note:', error); notificationStore.error('Failed to delete note'); } }; @@ -256,7 +257,7 @@ export const GuestNotes: Component = (props) => { notificationStore.error('Failed to export notes'); } } catch (error) { - console.error('Failed to export notes:', error); + logger.error('Failed to export notes:', error); notificationStore.error('Failed to export notes'); } }; @@ -296,7 +297,7 @@ export const GuestNotes: Component = (props) => { notificationStore.error('Import failed: ' + errorText); } } catch (error) { - console.error('Failed to import notes:', error); + logger.error('Failed to import notes:', error); notificationStore.error('Failed to parse import file'); } finally { setIsImporting(false); @@ -328,7 +329,7 @@ export const GuestNotes: Component = (props) => { notificationStore.error('Failed to clear notes'); } } catch (error) { - console.error('Failed to clear notes:', error); + logger.error('Failed to clear notes:', error); notificationStore.error('Failed to clear notes'); } }; diff --git a/frontend-modern/src/components/FirstRunSetup.tsx b/frontend-modern/src/components/FirstRunSetup.tsx index 29e36b58e..e237677ef 100644 --- a/frontend-modern/src/components/FirstRunSetup.tsx +++ b/frontend-modern/src/components/FirstRunSetup.tsx @@ -1,5 +1,6 @@ import { Component, createSignal, Show, onMount } from 'solid-js'; import { showSuccess, showError } from '@/utils/toast'; +import { logger } from '@/utils/logger'; import { copyToClipboard } from '@/utils/clipboard'; import { clearAuth as clearApiClientAuth, setApiToken as setApiClientToken } from '@/utils/apiClient'; import { getPulseBaseUrl } from '@/utils/url'; @@ -83,7 +84,7 @@ export const FirstRunSetup: Component<{ force?: boolean; showLegacyBanner?: bool } } } catch (error) { - console.error('Failed to fetch bootstrap token path:', error); + logger.error('Failed to fetch bootstrap token path:', error); } }); diff --git a/frontend-modern/src/components/Settings/UnifiedAgents.tsx b/frontend-modern/src/components/Settings/UnifiedAgents.tsx index 2fc78f61d..68d68b5ac 100644 --- a/frontend-modern/src/components/Settings/UnifiedAgents.tsx +++ b/frontend-modern/src/components/Settings/UnifiedAgents.tsx @@ -736,10 +736,7 @@ export const UnifiedAgents: Component = () => {

Run this command on any host to remove the Pulse agent:

-
- - {getUninstallCommand()} - +
+
+                                    {getUninstallCommand()}
+                                
@@ -782,10 +786,7 @@ export const UnifiedAgents: Component = () => {

Run this command on each legacy host to upgrade:

-
- - {getUpgradeCommand('')} - +
+
+                                        {getUpgradeCommand('')}
+                                    
diff --git a/frontend-modern/src/components/SetupWizard/steps/CompleteStep.tsx b/frontend-modern/src/components/SetupWizard/steps/CompleteStep.tsx index c4b65f73e..6e1db54f6 100644 --- a/frontend-modern/src/components/SetupWizard/steps/CompleteStep.tsx +++ b/frontend-modern/src/components/SetupWizard/steps/CompleteStep.tsx @@ -1,6 +1,7 @@ import { Component, createSignal, createEffect, onCleanup, Show, For } from 'solid-js'; // Note: For is still used for connectedAgents list import { copyToClipboard } from '@/utils/clipboard'; +import { logger } from '@/utils/logger'; import { getPulseBaseUrl } from '@/utils/url'; import { SecurityAPI } from '@/api/security'; import { ProxmoxIcon } from '@/components/icons/ProxmoxIcon'; @@ -108,7 +109,7 @@ export const CompleteStep: Component = (props) => { previousCount = totalAgents; } } catch (error) { - console.error('Failed to check for agents:', error); + logger.error('Failed to check for agents:', error); } }; @@ -138,7 +139,7 @@ export const CompleteStep: Component = (props) => { setCurrentInstallToken(result.token); } } catch (error) { - console.error('Failed to generate new token:', error); + logger.error('Failed to generate new token:', error); } finally { setGeneratingToken(false); } diff --git a/frontend-modern/src/components/shared/AIImpactTimelinePanel.tsx b/frontend-modern/src/components/shared/AIImpactTimelinePanel.tsx index 34a9493aa..86613158f 100644 --- a/frontend-modern/src/components/shared/AIImpactTimelinePanel.tsx +++ b/frontend-modern/src/components/shared/AIImpactTimelinePanel.tsx @@ -1,5 +1,6 @@ import { Component, createEffect, createSignal, For, Show } from 'solid-js'; import { AIAPI } from '@/api/ai'; +import { logger } from '@/utils/logger'; import type { RemediationRecord, RemediationStats } from '@/types/aiIntelligence'; const DEFAULT_UPGRADE_URL = 'https://pulserelay.pro'; @@ -24,7 +25,7 @@ export const AIImpactTimelinePanel: Component<{ hours?: number; showWhenEmpty?: setStats(response.stats || null); setRemediations(response.remediations || []); } catch (e) { - console.error('Failed to load AI impact timeline:', e); + logger.error('Failed to load AI impact timeline:', e); setError('Failed to load AI impact timeline.'); } finally { setLoading(false); diff --git a/frontend-modern/src/components/shared/AIInsightsPanel.tsx b/frontend-modern/src/components/shared/AIInsightsPanel.tsx index 5f85db44e..9f416f9cf 100644 --- a/frontend-modern/src/components/shared/AIInsightsPanel.tsx +++ b/frontend-modern/src/components/shared/AIInsightsPanel.tsx @@ -1,5 +1,6 @@ import { Component, createSignal, createEffect, Show, For } from 'solid-js'; import { AIAPI } from '@/api/ai'; +import { logger } from '@/utils/logger'; import type { FailurePrediction, ResourceCorrelation } from '@/types/aiIntelligence'; /** @@ -40,7 +41,7 @@ export const AIInsightsPanel: Component<{ resourceId?: string; showWhenEmpty?: b setCorrelations(corrResp.correlations || []); } } catch (e) { - console.error('Failed to load AI insights:', e); + logger.error('Failed to load AI insights:', e); setError('Failed to load AI insights.'); } finally { setLoading(false); diff --git a/frontend-modern/src/components/shared/AIOverviewTable.tsx b/frontend-modern/src/components/shared/AIOverviewTable.tsx index cb8cab5e2..2984e94de 100644 --- a/frontend-modern/src/components/shared/AIOverviewTable.tsx +++ b/frontend-modern/src/components/shared/AIOverviewTable.tsx @@ -1,5 +1,6 @@ import { Component, createEffect, createSignal, For, Show } from 'solid-js'; import { AIAPI } from '@/api/ai'; +import { logger } from '@/utils/logger'; import type { FailurePrediction, InfrastructureChange, RemediationRecord, RemediationStats, AnomalyReport } from '@/types/aiIntelligence'; const DEFAULT_UPGRADE_URL = 'https://pulserelay.pro'; @@ -110,7 +111,7 @@ export const AIOverviewTable: Component<{ showWhenEmpty?: boolean }> = (props) = predResp.upgrade_url || corrResp.upgrade_url || remResp.upgrade_url || changesResp.upgrade_url || DEFAULT_UPGRADE_URL ); } catch (e) { - console.error('Failed to load AI overview data:', e); + logger.error('Failed to load AI overview data:', e); setError('Failed to load AI overview data.'); } finally { setLoading(false); diff --git a/frontend-modern/src/components/shared/AIRecentChangesPanel.tsx b/frontend-modern/src/components/shared/AIRecentChangesPanel.tsx index 84214d0ef..3c971041a 100644 --- a/frontend-modern/src/components/shared/AIRecentChangesPanel.tsx +++ b/frontend-modern/src/components/shared/AIRecentChangesPanel.tsx @@ -1,5 +1,6 @@ import { Component, createEffect, createSignal, For, Show } from 'solid-js'; import { AIAPI } from '@/api/ai'; +import { logger } from '@/utils/logger'; import type { InfrastructureChange } from '@/types/aiIntelligence'; const DEFAULT_UPGRADE_URL = 'https://pulserelay.pro'; @@ -30,7 +31,7 @@ export const AIRecentChangesPanel: Component<{ hours?: number; showWhenEmpty?: b setChanges(response.changes || []); } } catch (e) { - console.error('Failed to load AI change history:', e); + logger.error('Failed to load AI change history:', e); setError('Failed to load recent changes.'); } finally { setLoading(false); diff --git a/frontend-modern/src/pages/Alerts.tsx b/frontend-modern/src/pages/Alerts.tsx index 3a379fd64..df9506cdf 100644 --- a/frontend-modern/src/pages/Alerts.tsx +++ b/frontend-modern/src/pages/Alerts.tsx @@ -2357,7 +2357,7 @@ function OverviewTab(props: { }, () => { // Error - just log it - console.error('Patrol stream error'); + logger.error('Patrol stream error'); } ); } else if ((!isExpanded || !isRunning) && liveStreamUnsubscribe) { @@ -2444,7 +2444,7 @@ function OverviewTab(props: { const response = await AIAPI.getRemediations({ findingId, limit: 3 }); setRemediationsByFinding((prev) => ({ ...prev, [findingId]: response.remediations || [] })); } catch (err) { - console.error('Failed to load remediation history', err); + logger.error('Failed to load remediation history', err); } finally { setRemediationLoadingByFinding((prev) => ({ ...prev, [findingId]: false })); } @@ -2467,7 +2467,7 @@ function OverviewTab(props: { setForcePatrolLoading(false); }, 2000); } catch (e) { - console.error('Force patrol error:', e); + logger.error('Force patrol error:', e); showError('Failed to start patrol: ' + (e instanceof Error ? e.message : 'Unknown error')); setForcePatrolLoading(false); } diff --git a/frontend-modern/src/stores/aiChat.ts b/frontend-modern/src/stores/aiChat.ts index 739c7eb58..02c5c9d3d 100644 --- a/frontend-modern/src/stores/aiChat.ts +++ b/frontend-modern/src/stores/aiChat.ts @@ -1,4 +1,5 @@ import { createSignal } from 'solid-js'; +import { logger } from '@/utils/logger'; interface AIChatContext { targetType?: string; @@ -49,7 +50,7 @@ const loadMessagesFromStorage = (): Message[] => { timestamp: new Date(m.timestamp) })); } catch (e) { - console.error('Failed to load chat history:', e); + logger.error('Failed to load chat history:', e); return []; } }; @@ -106,7 +107,7 @@ export const aiChatStore = { try { localStorage.setItem(HISTORY_STORAGE_KEY, JSON.stringify(msgs)); } catch (e) { - console.error('Failed to save chat history:', e); + logger.error('Failed to save chat history:', e); } }, diff --git a/frontend-modern/src/stores/metricsViewMode.ts b/frontend-modern/src/stores/metricsViewMode.ts index a3979c573..6a5b62661 100644 --- a/frontend-modern/src/stores/metricsViewMode.ts +++ b/frontend-modern/src/stores/metricsViewMode.ts @@ -7,6 +7,7 @@ */ import { createSignal } from 'solid-js'; +import { logger } from '@/utils/logger'; import { STORAGE_KEYS } from '@/utils/localStorage'; import { seedFromBackend, resetSeedingState } from './metricsHistory'; import type { TimeRange } from '@/api/charts'; @@ -87,7 +88,7 @@ export function setMetricsViewModePreference(mode: MetricsViewMode): void { localStorage.setItem(STORAGE_KEYS.METRICS_VIEW_MODE, mode); } catch (err) { // Ignore localStorage errors - console.warn('Failed to save metrics view mode preference', err); + logger.warn('Failed to save metrics view mode preference', err); } } @@ -112,7 +113,7 @@ export function setMetricsTimeRangePreference(range: TimeRange): void { localStorage.setItem(STORAGE_KEYS.METRICS_TIME_RANGE, range); } catch (err) { // Ignore localStorage errors - console.warn('Failed to save metrics time range preference', err); + logger.warn('Failed to save metrics time range preference', err); } }