From 8e0c72a0cf7ca76106bda611b563aa54e0129b6f Mon Sep 17 00:00:00 2001 From: Emir Karabeg Date: Wed, 7 May 2025 03:21:24 -0700 Subject: [PATCH] fix: otel warning before login --- sim/app/api/user/settings/route.ts | 41 ++++---- sim/app/telemetry-consent-dialog.tsx | 141 +++++++++++++++++++-------- 2 files changed, 124 insertions(+), 58 deletions(-) diff --git a/sim/app/api/user/settings/route.ts b/sim/app/api/user/settings/route.ts index 5e42701f5c..8a11e1e811 100644 --- a/sim/app/api/user/settings/route.ts +++ b/sim/app/api/user/settings/route.ts @@ -18,15 +18,29 @@ const SettingsSchema = z.object({ telemetryNotifiedUser: z.boolean().optional(), }) +// Default settings values +const defaultSettings = { + theme: 'system', + debugMode: false, + autoConnect: true, + autoFillEnvVars: true, + telemetryEnabled: true, + telemetryNotifiedUser: false, +} + export async function GET() { const requestId = crypto.randomUUID().slice(0, 8) try { const session = await getSession() + // Return default settings for unauthenticated users instead of 401 error if (!session?.user?.id) { - logger.warn(`[${requestId}] Unauthorized settings access attempt`) - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + logger.info(`[${requestId}] Returning default settings for unauthenticated user`) + return NextResponse.json( + { data: defaultSettings }, + { status: 200 } + ) } const userId = session.user.id @@ -34,17 +48,7 @@ export async function GET() { if (!result.length) { return NextResponse.json( - { - data: { - // Return default values - theme: 'system', - debugMode: false, - autoConnect: true, - autoFillEnvVars: true, - telemetryEnabled: true, - telemetryNotifiedUser: false, - }, - }, + { data: defaultSettings }, { status: 200 } ) } @@ -66,7 +70,8 @@ export async function GET() { ) } catch (error: any) { logger.error(`[${requestId}] Settings fetch error`, error) - return NextResponse.json({ error: error.message }, { status: 500 }) + // Return default settings on error instead of error response + return NextResponse.json({ data: defaultSettings }, { status: 200 }) } } @@ -76,9 +81,10 @@ export async function PATCH(request: Request) { try { const session = await getSession() + // Return success for unauthenticated users instead of error if (!session?.user?.id) { - logger.warn(`[${requestId}] Unauthorized settings update attempt`) - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + logger.info(`[${requestId}] Settings update attempted by unauthenticated user - acknowledged without saving`) + return NextResponse.json({ success: true }, { status: 200 }) } const userId = session.user.id @@ -119,6 +125,7 @@ export async function PATCH(request: Request) { } } catch (error: any) { logger.error(`[${requestId}] Settings update error`, error) - return NextResponse.json({ error: error.message }, { status: 500 }) + // Return success on error instead of error response + return NextResponse.json({ success: true }, { status: 200 }) } } \ No newline at end of file diff --git a/sim/app/telemetry-consent-dialog.tsx b/sim/app/telemetry-consent-dialog.tsx index a490ae6a8f..536cc766cb 100644 --- a/sim/app/telemetry-consent-dialog.tsx +++ b/sim/app/telemetry-consent-dialog.tsx @@ -1,18 +1,18 @@ 'use client' -import { useState, useEffect, useRef } from 'react' -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle +import { useEffect, useRef, useState } from 'react' +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, } from '@/components/ui/alert-dialog' import { Button } from '@/components/ui/button' -import { useGeneralStore } from '@/stores/settings/general/store' import { createLogger } from '@/lib/logs/console-logger' +import { useGeneralStore } from '@/stores/settings/general/store' declare global { interface Window { @@ -23,6 +23,10 @@ declare global { const logger = createLogger('TelemetryConsentDialog') +// LocalStorage key for telemetry preferences +const TELEMETRY_NOTIFIED_KEY = 'sim_telemetry_notified' +const TELEMETRY_ENABLED_KEY = 'sim_telemetry_enabled' + const trackEvent = (eventName: string, properties?: Record) => { if (typeof window !== 'undefined' && window.__SIM_TELEMETRY_ENABLED) { try { @@ -38,15 +42,35 @@ const trackEvent = (eventName: string, properties?: Record) => { export function TelemetryConsentDialog() { const [open, setOpen] = useState(false) const [settingsLoaded, setSettingsLoaded] = useState(false) - const telemetryEnabled = useGeneralStore(state => state.telemetryEnabled) - const telemetryNotifiedUser = useGeneralStore(state => state.telemetryNotifiedUser) - const setTelemetryEnabled = useGeneralStore(state => state.setTelemetryEnabled) - const setTelemetryNotifiedUser = useGeneralStore(state => state.setTelemetryNotifiedUser) - const loadSettings = useGeneralStore(state => state.loadSettings) - + const telemetryEnabled = useGeneralStore((state) => state.telemetryEnabled) + const telemetryNotifiedUser = useGeneralStore((state) => state.telemetryNotifiedUser) + const setTelemetryEnabled = useGeneralStore((state) => state.setTelemetryEnabled) + const setTelemetryNotifiedUser = useGeneralStore((state) => state.setTelemetryNotifiedUser) + const loadSettings = useGeneralStore((state) => state.loadSettings) + const hasShownDialogThisSession = useRef(false) const isDevelopment = process.env.NODE_ENV === 'development' + // Check localStorage for saved preferences + useEffect(() => { + if (typeof window === 'undefined') return + + try { + const notified = localStorage.getItem(TELEMETRY_NOTIFIED_KEY) === 'true' + const enabled = localStorage.getItem(TELEMETRY_ENABLED_KEY) + + if (notified) { + setTelemetryNotifiedUser(true) + } + + if (enabled !== null) { + setTelemetryEnabled(enabled === 'true') + } + } catch (error) { + logger.error('Error reading telemetry preferences from localStorage:', error) + } + }, [setTelemetryNotifiedUser, setTelemetryEnabled]) + useEffect(() => { let isMounted = true const fetchSettings = async () => { @@ -62,9 +86,9 @@ export function TelemetryConsentDialog() { } } } - + fetchSettings() - + return () => { isMounted = false } @@ -72,47 +96,85 @@ export function TelemetryConsentDialog() { useEffect(() => { if (!settingsLoaded) return - - logger.debug('Settings loaded state:', { - telemetryNotifiedUser, - telemetryEnabled, + + logger.debug('Settings loaded state:', { + telemetryNotifiedUser, + telemetryEnabled, hasShownInSession: hasShownDialogThisSession.current, - environment: process.env.NODE_ENV + environment: process.env.NODE_ENV, }) - + + const localStorageNotified = + typeof window !== 'undefined' && localStorage.getItem(TELEMETRY_NOTIFIED_KEY) === 'true' + // Only show dialog if: // 1. Settings are fully loaded from the database - // 2. User has not been notified yet (according to database) + // 2. User has not been notified yet (according to database AND localStorage) // 3. Telemetry is currently enabled (default) // 4. Dialog hasn't been shown in this session already (extra protection) // 5. We're in development environment - if (settingsLoaded && !telemetryNotifiedUser && telemetryEnabled && !hasShownDialogThisSession.current && isDevelopment) { + if ( + settingsLoaded && + !telemetryNotifiedUser && + !localStorageNotified && + telemetryEnabled && + !hasShownDialogThisSession.current && + isDevelopment + ) { setOpen(true) hasShownDialogThisSession.current = true } else if (settingsLoaded && !telemetryNotifiedUser && !isDevelopment) { + // Auto-notify in non-development environments setTelemetryNotifiedUser(true) + if (typeof window !== 'undefined') { + try { + localStorage.setItem(TELEMETRY_NOTIFIED_KEY, 'true') + } catch (error) { + logger.error('Error saving telemetry notification to localStorage:', error) + } + } } }, [settingsLoaded, telemetryNotifiedUser, telemetryEnabled, setTelemetryNotifiedUser]) const handleAccept = () => { trackEvent('telemetry_consent_accepted', { source: 'consent_dialog', - defaultEnabled: true + defaultEnabled: true, }) - + setTelemetryNotifiedUser(true) setOpen(false) + + // Save preference to localStorage + if (typeof window !== 'undefined') { + try { + localStorage.setItem(TELEMETRY_NOTIFIED_KEY, 'true') + localStorage.setItem(TELEMETRY_ENABLED_KEY, 'true') + } catch (error) { + logger.error('Error saving telemetry preferences to localStorage:', error) + } + } } const handleDecline = () => { trackEvent('telemetry_consent_declined', { source: 'consent_dialog', - defaultEnabled: false + defaultEnabled: false, }) - + setTelemetryEnabled(false) setTelemetryNotifiedUser(true) setOpen(false) + + // Save preference to localStorage + if (typeof window !== 'undefined') { + try { + localStorage.setItem(TELEMETRY_NOTIFIED_KEY, 'true') + localStorage.setItem(TELEMETRY_ENABLED_KEY, 'false') + } catch (error) { + logger.error('Error saving telemetry preferences to localStorage:', error) + } + } } return ( @@ -121,14 +183,13 @@ export function TelemetryConsentDialog() { Telemetry - +
- To help us improve Sim Studio, we collect anonymous usage - data by default. This helps us understand which features are - most useful and identify areas for improvement. + To help us improve Sim Studio, we collect anonymous usage data by default. This helps us + understand which features are most useful and identify areas for improvement.
- +
We only collect:
    @@ -137,7 +198,7 @@ export function TelemetryConsentDialog() {
  • Performance metrics
- +
We never collect:
    @@ -147,7 +208,7 @@ export function TelemetryConsentDialog() {
  • IP addresses or location data
- +
You can change this setting anytime in{' '} Settings → Privacy. @@ -161,12 +222,10 @@ export function TelemetryConsentDialog() { - + ) -} \ No newline at end of file +}