mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-24 08:56:28 +00:00
wip encapsulate exception capture
This commit is contained in:
@@ -2,6 +2,7 @@ import { Button } from '@/primitives'
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useMediaDeviceSelect } from '@livekit/components-react'
|
import { useMediaDeviceSelect } from '@livekit/components-react'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const SoundTester = () => {
|
export const SoundTester = () => {
|
||||||
const { t } = useTranslation('settings')
|
const { t } = useTranslation('settings')
|
||||||
@@ -15,7 +16,10 @@ export const SoundTester = () => {
|
|||||||
try {
|
try {
|
||||||
await audioRef?.current?.setSinkId(deviceId)
|
await audioRef?.current?.setSinkId(deviceId)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error setting sinkId: ${error}`)
|
reportError(
|
||||||
|
'device_switch_failure',
|
||||||
|
new Error(`Error setting sinkId: ${error}`)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateActiveId(activeDeviceId)
|
updateActiveId(activeDeviceId)
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useLocation } from 'wouter'
|
import { useLocation } from 'wouter'
|
||||||
import { type PostHog } from 'posthog-js'
|
|
||||||
import { type ApiUser } from '@/features/auth/api/ApiUser'
|
import { type ApiUser } from '@/features/auth/api/ApiUser'
|
||||||
import { useUser } from '@/features/auth/api/useUser'
|
import { useUser } from '@/features/auth/api/useUser'
|
||||||
|
import { getPosthog } from '../utils'
|
||||||
let posthog: PostHog | null = null
|
|
||||||
|
|
||||||
const getPosthog = async () => {
|
|
||||||
if (!posthog) posthog = (await import('posthog-js')).default
|
|
||||||
return posthog
|
|
||||||
}
|
|
||||||
|
|
||||||
export const startAnalyticsSession = (data: ApiUser) => {
|
export const startAnalyticsSession = (data: ApiUser) => {
|
||||||
getPosthog().then((ph) => {
|
getPosthog().then((ph) => {
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { getPosthog } from './utils'
|
||||||
|
|
||||||
|
export type LogCode =
|
||||||
|
// media
|
||||||
|
| 'join_preview_failure'
|
||||||
|
| 'livekit_room_error'
|
||||||
|
| 'device_switch_failure'
|
||||||
|
| 'permission_poll_failure'
|
||||||
|
// non-media families
|
||||||
|
| 'participant_mute_api_failure'
|
||||||
|
| 'permissions_api_failure'
|
||||||
|
| 'effects_processor_failure'
|
||||||
|
| 'clipboard_failure'
|
||||||
|
| 'fullscreen_failure'
|
||||||
|
| 'publish_sources_failure'
|
||||||
|
| 'disconnect_failure'
|
||||||
|
| 'generic_failure'
|
||||||
|
|
||||||
|
export const reportError = (
|
||||||
|
logCode: LogCode,
|
||||||
|
error: unknown,
|
||||||
|
extraInfo: Record<string, unknown> = {}
|
||||||
|
): void => {
|
||||||
|
const e = error instanceof Error ? error : new Error(String(error))
|
||||||
|
void getPosthog()
|
||||||
|
.then((ph) => {
|
||||||
|
ph.captureException(e, {
|
||||||
|
log_code: logCode,
|
||||||
|
error_name: e.name,
|
||||||
|
error_message: e.message,
|
||||||
|
...extraInfo,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
if (import.meta.env.DEV) {
|
||||||
|
console.warn(`[${logCode}]`, e, extraInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import type { PostHog } from 'posthog-js'
|
||||||
|
|
||||||
|
let posthog: PostHog | null = null
|
||||||
|
|
||||||
|
export const getPosthog = async () => {
|
||||||
|
if (!posthog) posthog = (await import('posthog-js')).default
|
||||||
|
return posthog
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ import { css } from '@/styled-system/css'
|
|||||||
import { useConfig } from '@/api/useConfig'
|
import { useConfig } from '@/api/useConfig'
|
||||||
import { LoginButton } from '@/components/LoginButton'
|
import { LoginButton } from '@/components/LoginButton'
|
||||||
import { LoadingScreen } from '@/components/LoadingScreen'
|
import { LoadingScreen } from '@/components/LoadingScreen'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
const Columns = ({ children }: { children?: ReactNode }) => {
|
const Columns = ({ children }: { children?: ReactNode }) => {
|
||||||
return (
|
return (
|
||||||
@@ -160,7 +161,9 @@ const Home = () => {
|
|||||||
window.location.replace(data.external_home_url)
|
window.location.replace(data.external_home_url)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setRedirectFailed(true)
|
setRedirectFailed(true)
|
||||||
console.error('Site is not reachable:', error)
|
reportError('generic_failure', error, {
|
||||||
|
context: 'Site is not reachable:',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { NotificationDuration } from './NotificationDuration'
|
|||||||
import type { Participant } from 'livekit-client'
|
import type { Participant } from 'livekit-client'
|
||||||
import type { NotificationPayload } from './NotificationPayload'
|
import type { NotificationPayload } from './NotificationPayload'
|
||||||
import type { RecordingMode } from '@/features/recording'
|
import type { RecordingMode } from '@/features/recording'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const notifyAutoMutedOnJoin = () => {
|
export const notifyAutoMutedOnJoin = () => {
|
||||||
toastQueue.add(
|
toastQueue.add(
|
||||||
@@ -55,7 +56,9 @@ export const decodeNotificationDataReceived = (
|
|||||||
return parsed as NotificationPayload
|
return parsed as NotificationPayload
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Handle errors appropriately for your application
|
// Handle errors appropriately for your application
|
||||||
console.error('Failed to decode notification payload:', error)
|
reportError('generic_failure', error, {
|
||||||
|
context: 'Failed to decode notification payload:',
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { Participant } from 'livekit-client'
|
import type { Participant } from 'livekit-client'
|
||||||
import { useLowerHandParticipant } from './lowerHandParticipant'
|
import { useLowerHandParticipant } from './lowerHandParticipant'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const useLowerHandParticipants = () => {
|
export const useLowerHandParticipants = () => {
|
||||||
const { lowerHandParticipant } = useLowerHandParticipant()
|
const { lowerHandParticipant } = useLowerHandParticipant()
|
||||||
@@ -11,7 +12,9 @@ export const useLowerHandParticipants = () => {
|
|||||||
)
|
)
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('An error occurred while lowering hands :', error)
|
reportError('generic_failure', error, {
|
||||||
|
context: 'An error occurred while lowering hands :',
|
||||||
|
})
|
||||||
throw new Error('An error occurred while lowering hands.', {
|
throw new Error('An error occurred while lowering hands.', {
|
||||||
cause: error,
|
cause: error,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { fetchApi } from '@/api/fetchApi'
|
import { fetchApi } from '@/api/fetchApi'
|
||||||
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
|
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
|
||||||
import { AssignableParticipantRole } from '@/features/rooms/api/ApiRoom'
|
import { AssignableParticipantRole } from '@/features/rooms/api/ApiRoom'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const useParticipantRole = () => {
|
export const useParticipantRole = () => {
|
||||||
const data = useRoomData()
|
const data = useRoomData()
|
||||||
@@ -22,8 +23,11 @@ export const useParticipantRole = () => {
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
reportError(
|
||||||
`Failed to update participant's role ${identity}: ${error instanceof Error ? error.message : 'Unknown error'}`
|
'generic_failure',
|
||||||
|
new Error(
|
||||||
|
`Failed to update participant's role ${identity}: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
} from '../../participants/api/listWaitingParticipants'
|
} from '../../participants/api/listWaitingParticipants'
|
||||||
import { decodeNotificationDataReceived } from '@/features/notifications/utils'
|
import { decodeNotificationDataReceived } from '@/features/notifications/utils'
|
||||||
import { NotificationType } from '@/features/notifications/NotificationType'
|
import { NotificationType } from '@/features/notifications/NotificationType'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const POLL_INTERVAL_MS = 1000
|
export const POLL_INTERVAL_MS = 1000
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ export const useWaitingParticipants = () => {
|
|||||||
|
|
||||||
await refetchWaiting()
|
await refetchWaiting()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
reportError('generic_failure', e)
|
||||||
setListEnabled(true)
|
setListEnabled(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useCallback, useMemo } from 'react'
|
|||||||
import { flushSync } from 'react-dom'
|
import { flushSync } from 'react-dom'
|
||||||
import { documentPictureInPictureStore } from '@/stores/documentPictureInPicture'
|
import { documentPictureInPictureStore } from '@/stores/documentPictureInPicture'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const IS_PIP_SUPPORTED =
|
export const IS_PIP_SUPPORTED =
|
||||||
typeof globalThis !== 'undefined' && 'documentPictureInPicture' in globalThis
|
typeof globalThis !== 'undefined' && 'documentPictureInPicture' in globalThis
|
||||||
@@ -86,7 +87,9 @@ export const usePictureInPicture = () => {
|
|||||||
documentPictureInPictureStore.window = ref(pipWindow)
|
documentPictureInPictureStore.window = ref(pipWindow)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Avoid unhandled rejections if the user blocks or closes the request.
|
// Avoid unhandled rejections if the user blocks or closes the request.
|
||||||
console.error('Failed to open Picture-in-Picture window', error)
|
reportError('generic_failure', error, {
|
||||||
|
context: 'Failed to open Picture-in-Picture window',
|
||||||
|
})
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
|
|||||||
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
|
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
|
||||||
import { FeatureFlags } from '@/features/analytics/enums'
|
import { FeatureFlags } from '@/features/analytics/enums'
|
||||||
import { LimitDescription } from './LimitDescription'
|
import { LimitDescription } from './LimitDescription'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const ScreenRecordingSidePanel = () => {
|
export const ScreenRecordingSidePanel = () => {
|
||||||
const { data } = useConfig()
|
const { data } = useConfig()
|
||||||
@@ -106,7 +107,9 @@ export const ScreenRecordingSidePanel = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to handle recording:', error)
|
reportError('generic_failure', error, {
|
||||||
|
context: 'Failed to handle recording:',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
|
|||||||
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
|
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
|
||||||
import { LimitDescription } from './LimitDescription'
|
import { LimitDescription } from './LimitDescription'
|
||||||
import { openSettingsDialog } from '@/stores/settings'
|
import { openSettingsDialog } from '@/stores/settings'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const TranscriptSidePanel = () => {
|
export const TranscriptSidePanel = () => {
|
||||||
const { data } = useConfig()
|
const { data } = useConfig()
|
||||||
@@ -127,7 +128,9 @@ export const TranscriptSidePanel = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to handle transcript:', error)
|
reportError('generic_failure', error, {
|
||||||
|
context: 'Failed to handle transcript:',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useRoomInfo } from '@livekit/components-react'
|
import { useRoomInfo } from '@livekit/components-react'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const useRoomMetadata = () => {
|
export const useRoomMetadata = () => {
|
||||||
const { metadata } = useRoomInfo()
|
const { metadata } = useRoomInfo()
|
||||||
@@ -8,7 +9,9 @@ export const useRoomMetadata = () => {
|
|||||||
try {
|
try {
|
||||||
return JSON.parse(metadata)
|
return JSON.parse(metadata)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to parse room metadata:', error)
|
reportError('generic_failure', error, {
|
||||||
|
context: 'Failed to parse room metadata:',
|
||||||
|
})
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { fetchApi } from '@/api/fetchApi'
|
|||||||
import { useIsAdminOrOwner } from '../livekit/hooks/useIsAdminOrOwner'
|
import { useIsAdminOrOwner } from '../livekit/hooks/useIsAdminOrOwner'
|
||||||
|
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const useMuteParticipant = () => {
|
export const useMuteParticipant = () => {
|
||||||
const apiRoomData = useRoomData()
|
const apiRoomData = useRoomData()
|
||||||
@@ -31,7 +32,10 @@ export const useMuteParticipant = () => {
|
|||||||
|
|
||||||
// Guard against undefined token for non-admin users
|
// Guard against undefined token for non-admin users
|
||||||
if (!isAdminOrOwner && !apiRoomData.livekit.token) {
|
if (!isAdminOrOwner && !apiRoomData.livekit.token) {
|
||||||
console.error('Cannot mute participant: missing auth token')
|
reportError(
|
||||||
|
'participant_mute_api_failure',
|
||||||
|
new Error('Cannot mute participant: missing auth token')
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,8 +57,11 @@ export const useMuteParticipant = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
reportError(
|
||||||
`Failed to mute participant ${participant.identity}: ${error instanceof Error ? error.message : 'Unknown error'}`
|
'participant_mute_api_failure',
|
||||||
|
new Error(
|
||||||
|
`Failed to mute participant ${participant.identity}: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||||
|
)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -65,8 +72,11 @@ export const useMuteParticipant = () => {
|
|||||||
destinationIdentities: [participant.identity],
|
destinationIdentities: [participant.identity],
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(
|
reportError(
|
||||||
`Failed to notify muted participant ${participant.identity}: ${e}`
|
'participant_mute_api_failure',
|
||||||
|
new Error(
|
||||||
|
`Failed to notify muted participant ${participant.identity}: ${e}`
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { Participant } from 'livekit-client'
|
import type { Participant } from 'livekit-client'
|
||||||
import { useMuteParticipant } from './muteParticipant'
|
import { useMuteParticipant } from './muteParticipant'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const useMuteParticipants = () => {
|
export const useMuteParticipants = () => {
|
||||||
const { muteParticipant } = useMuteParticipant()
|
const { muteParticipant } = useMuteParticipant()
|
||||||
@@ -11,7 +12,9 @@ export const useMuteParticipants = () => {
|
|||||||
)
|
)
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('An error occurred while muting participants :', error)
|
reportError('participant_mute_api_failure', error, {
|
||||||
|
context: 'An error occurred while muting participants :',
|
||||||
|
})
|
||||||
throw new Error('An error occurred while muting participants.', {
|
throw new Error('An error occurred while muting participants.', {
|
||||||
cause: error,
|
cause: error,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { Participant, Track } from 'livekit-client'
|
import type { Participant, Track } from 'livekit-client'
|
||||||
import { fetchApi } from '@/api/fetchApi'
|
import { fetchApi } from '@/api/fetchApi'
|
||||||
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
|
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
type Source = Track.Source
|
type Source = Track.Source
|
||||||
|
|
||||||
export const useParticipantPermissions = () => {
|
export const useParticipantPermissions = () => {
|
||||||
@@ -32,8 +33,11 @@ export const useParticipantPermissions = () => {
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
reportError(
|
||||||
`Failed to update participant's permissions ${participant.identity}: ${error instanceof Error ? error.message : 'Unknown error'}`
|
'permissions_api_failure',
|
||||||
|
new Error(
|
||||||
|
`Failed to update participant's permissions ${participant.identity}: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { Participant, Track } from 'livekit-client'
|
import type { Participant, Track } from 'livekit-client'
|
||||||
import { useParticipantPermissions } from './updateParticipantPermissions'
|
import { useParticipantPermissions } from './updateParticipantPermissions'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
type Source = Track.Source
|
type Source = Track.Source
|
||||||
|
|
||||||
export const useUpdateParticipantsPermissions = () => {
|
export const useUpdateParticipantsPermissions = () => {
|
||||||
@@ -15,7 +16,9 @@ export const useUpdateParticipantsPermissions = () => {
|
|||||||
)
|
)
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('An error occurred while updating permissions :', error)
|
reportError('permissions_api_failure', error, {
|
||||||
|
context: 'An error occurred while updating permissions :',
|
||||||
|
})
|
||||||
throw new Error('An error occurred while updating permissions.', {
|
throw new Error('An error occurred while updating permissions.', {
|
||||||
cause: error,
|
cause: error,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import { css } from '@/styled-system/css'
|
|||||||
import { BackgroundProcessorFactory } from '../livekit/components/blur'
|
import { BackgroundProcessorFactory } from '../livekit/components/blur'
|
||||||
import { LocalUserChoices } from '@/stores/userChoices'
|
import { LocalUserChoices } from '@/stores/userChoices'
|
||||||
import { MediaDeviceErrorAlert } from './MediaDeviceErrorAlert'
|
import { MediaDeviceErrorAlert } from './MediaDeviceErrorAlert'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
import { usePostHog } from 'posthog-js/react'
|
import { usePostHog } from 'posthog-js/react'
|
||||||
import { useConfig } from '@/api/useConfig'
|
import { useConfig } from '@/api/useConfig'
|
||||||
import { isFireFox } from '@/utils/livekit'
|
import { isFireFox } from '@/utils/livekit'
|
||||||
@@ -37,7 +38,6 @@ import { notifyAutoMutedOnJoin } from '@/features/notifications/utils'
|
|||||||
import { useSnapshot } from 'valtio'
|
import { useSnapshot } from 'valtio'
|
||||||
import { userPreferencesStore } from '@/stores/userPreferences'
|
import { userPreferencesStore } from '@/stores/userPreferences'
|
||||||
import { userStore } from '@/stores/user'
|
import { userStore } from '@/stores/user'
|
||||||
import { asError } from '../utils/error'
|
|
||||||
|
|
||||||
export const Conference = ({
|
export const Conference = ({
|
||||||
roomId,
|
roomId,
|
||||||
@@ -236,7 +236,9 @@ export const Conference = ({
|
|||||||
backgroundColor: 'primaryDark.50 !important',
|
backgroundColor: 'primaryDark.50 !important',
|
||||||
})}
|
})}
|
||||||
onError={(e) => {
|
onError={(e) => {
|
||||||
posthog.captureException(asError(e))
|
reportError('livekit_room_error', e, {
|
||||||
|
failure: MediaDeviceFailure.getFailure(e) ?? 'not-a-device-error',
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
onConnected={async () => {
|
onConnected={async () => {
|
||||||
if (!apiConfig) return
|
if (!apiConfig) return
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import { useLoginHint } from '@/hooks/useLoginHint'
|
|||||||
import { openPermissionsDialog } from '@/stores/permissions'
|
import { openPermissionsDialog } from '@/stores/permissions'
|
||||||
import { useResolveInitiallyDefaultDeviceId } from '../livekit/hooks/useResolveInitiallyDefaultDeviceId'
|
import { useResolveInitiallyDefaultDeviceId } from '../livekit/hooks/useResolveInitiallyDefaultDeviceId'
|
||||||
import { isSafari } from '@/utils/livekit'
|
import { isSafari } from '@/utils/livekit'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type LocalUserChoices,
|
type LocalUserChoices,
|
||||||
@@ -54,7 +55,8 @@ import { useSnapshot } from 'valtio'
|
|||||||
import { useUser } from '@/features/auth/api/useUser'
|
import { useUser } from '@/features/auth/api/useUser'
|
||||||
import { useConfig } from '@/api/useConfig'
|
import { useConfig } from '@/api/useConfig'
|
||||||
|
|
||||||
const onError = (e: Error) => console.error('ERROR', e)
|
const onError = (e: Error) =>
|
||||||
|
reportError('join_preview_failure', e, { path: 'join_preview' })
|
||||||
|
|
||||||
const Effects = ({
|
const Effects = ({
|
||||||
videoTrack,
|
videoTrack,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { permissionsStore } from '@/stores/permissions'
|
import { permissionsStore } from '@/stores/permissions'
|
||||||
import { isSafari } from '@/utils/livekit'
|
import { isSafari } from '@/utils/livekit'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
const POLLING_TIME = 500
|
const POLLING_TIME = 500
|
||||||
|
|
||||||
@@ -88,7 +89,9 @@ export const useWatchPermissions = () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!isCancelled) {
|
if (!isCancelled) {
|
||||||
console.error('Error polling permissions:', error)
|
reportError('permission_poll_failure', error, {
|
||||||
|
context: 'Error polling permissions:',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, POLLING_TIME)
|
}, POLLING_TIME)
|
||||||
@@ -142,7 +145,9 @@ export const useWatchPermissions = () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!isCancelled) {
|
if (!isCancelled) {
|
||||||
console.error('Error checking permissions:', error)
|
reportError('permission_poll_failure', error, {
|
||||||
|
context: 'Error checking permissions:',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (!isCancelled) {
|
if (!isCancelled) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { usePermissionsManager } from '../hooks/usePermissionsManager'
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { closeSidePanel } from '@/stores/layout'
|
import { closeSidePanel } from '@/stores/layout'
|
||||||
import { useIsAdminOrOwner } from '../hooks/useIsAdminOrOwner'
|
import { useIsAdminOrOwner } from '../hooks/useIsAdminOrOwner'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const Admin = () => {
|
export const Admin = () => {
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'admin' })
|
const { t } = useTranslation('rooms', { keyPrefix: 'admin' })
|
||||||
@@ -205,7 +206,7 @@ export const Admin = () => {
|
|||||||
patchRoom({
|
patchRoom({
|
||||||
roomId,
|
roomId,
|
||||||
room: { access_level: value as ApiAccessLevel },
|
room: { access_level: value as ApiAccessLevel },
|
||||||
}).catch((e) => console.error(e))
|
}).catch((e) => reportError('generic_failure', e))
|
||||||
}
|
}
|
||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { RiCameraSwitchLine } from '@remixicon/react'
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import type { ButtonProps } from 'react-aria-components'
|
import type { ButtonProps } from 'react-aria-components'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
enum FacingMode {
|
enum FacingMode {
|
||||||
USER = 'user',
|
USER = 'user',
|
||||||
@@ -103,7 +104,11 @@ export const CameraSwitchButton = (props: Partial<ButtonProps>) => {
|
|||||||
setActiveMediaDevice(device.deviceId)
|
setActiveMediaDevice(device.deviceId)
|
||||||
setFacingMode(target)
|
setFacingMode(target)
|
||||||
} else {
|
} else {
|
||||||
console.error('Cannot get user device with facingMode ' + target)
|
reportError(
|
||||||
|
'device_switch_failure',
|
||||||
|
new Error('Cannot get user device with facingMode ' + target),
|
||||||
|
{ path: 'switch_device', kind: 'videoinput', facing_mode: target }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Button } from '@/primitives'
|
|||||||
import { RiPhoneFill } from '@remixicon/react'
|
import { RiPhoneFill } from '@remixicon/react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ConnectionState } from 'livekit-client'
|
import { ConnectionState } from 'livekit-client'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const LeaveButton = () => {
|
export const LeaveButton = () => {
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'controls' })
|
const { t } = useTranslation('rooms', { keyPrefix: 'controls' })
|
||||||
@@ -15,11 +16,11 @@ export const LeaveButton = () => {
|
|||||||
tooltip={t('leave')}
|
tooltip={t('leave')}
|
||||||
aria-label={t('leave')}
|
aria-label={t('leave')}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
room
|
room.disconnect(true).catch((e) =>
|
||||||
.disconnect(true)
|
reportError('disconnect_failure', e, {
|
||||||
.catch((e) =>
|
context: 'An error occurred while disconnecting:',
|
||||||
console.error('An error occurred while disconnecting:', e)
|
})
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
data-attr="controls-leave"
|
data-attr="controls-leave"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import { useConfig } from '@/api/useConfig.ts'
|
|||||||
import { proxy, useSnapshot } from 'valtio'
|
import { proxy, useSnapshot } from 'valtio'
|
||||||
import { Spinner } from '@/primitives/Spinner.tsx'
|
import { Spinner } from '@/primitives/Spinner.tsx'
|
||||||
import { userChoicesStore, saveProcessorConfig } from '@/stores/userChoices'
|
import { userChoicesStore, saveProcessorConfig } from '@/stores/userChoices'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
enum BlurRadius {
|
enum BlurRadius {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
@@ -238,7 +239,9 @@ export const EffectsConfiguration = ({
|
|||||||
|
|
||||||
updateEffectStatusMessage(config, wasSelectedBeforeToggle)
|
updateEffectStatusMessage(config, wasSelectedBeforeToggle)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error applying effect:', error)
|
reportError('effects_processor_failure', error, {
|
||||||
|
context: 'Error applying effect:',
|
||||||
|
})
|
||||||
} finally {
|
} finally {
|
||||||
// Without setTimeout the DOM is not refreshing when updating the options.
|
// Without setTimeout the DOM is not refreshing when updating the options.
|
||||||
setTimeout(() => setProcessorPending(false))
|
setTimeout(() => setProcessorPending(false))
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { RiGlassesLine, RiGoblet2Fill } from '@remixicon/react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FaceLandmarksProcessor } from '../blur/FaceLandmarksProcessor'
|
import { FaceLandmarksProcessor } from '../blur/FaceLandmarksProcessor'
|
||||||
import type { LocalVideoTrack } from 'livekit-client'
|
import type { LocalVideoTrack } from 'livekit-client'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export type FunnyEffectsProps = {
|
export type FunnyEffectsProps = {
|
||||||
videoTrack: LocalVideoTrack
|
videoTrack: LocalVideoTrack
|
||||||
@@ -55,7 +56,9 @@ export const FunnyEffects = ({
|
|||||||
await videoTrack.setProcessor(newProcessor)
|
await videoTrack.setProcessor(newProcessor)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('could not update processor', e)
|
reportError('effects_processor_failure', e, {
|
||||||
|
context: 'could not update processor',
|
||||||
|
})
|
||||||
} finally {
|
} finally {
|
||||||
onPending(false)
|
onPending(false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useEffect, useMemo, useState } from 'react'
|
|||||||
import { formatPinCode } from '@/features/rooms/utils/telephony'
|
import { formatPinCode } from '@/features/rooms/utils/telephony'
|
||||||
import type { ApiRoom } from '@/features/rooms/api/ApiRoom'
|
import type { ApiRoom } from '@/features/rooms/api/ApiRoom'
|
||||||
import { getRouteUrl } from '@/navigation/getRouteUrl'
|
import { getRouteUrl } from '@/navigation/getRouteUrl'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
const COPY_SUCCESS_TIMEOUT = 3000
|
const COPY_SUCCESS_TIMEOUT = 3000
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ export const useCopyRoomToClipboard = (room: ApiRoom | undefined) => {
|
|||||||
await navigator.clipboard.writeText(content)
|
await navigator.clipboard.writeText(content)
|
||||||
setIsCopied(true)
|
setIsCopied(true)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
reportError('clipboard_failure', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ export const useCopyRoomToClipboard = (room: ApiRoom | undefined) => {
|
|||||||
await navigator.clipboard.writeText(roomUrl)
|
await navigator.clipboard.writeText(roomUrl)
|
||||||
setIsRoomUrlCopied(true)
|
setIsRoomUrlCopied(true)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
reportError('clipboard_failure', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
import { useMemo, useState } from 'react'
|
import { useMemo, useState } from 'react'
|
||||||
import { type TrackReferenceOrPlaceholder } from '@livekit/components-core'
|
import { type TrackReferenceOrPlaceholder } from '@livekit/components-core'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export function useFullScreen({
|
export function useFullScreen({
|
||||||
trackRef,
|
trackRef,
|
||||||
@@ -56,7 +57,9 @@ export function useFullScreen({
|
|||||||
await docEl.msRequestFullscreen()
|
await docEl.msRequestFullscreen()
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error entering fullscreen:', error)
|
reportError('fullscreen_failure', error, {
|
||||||
|
context: 'Error entering fullscreen:',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +73,9 @@ export function useFullScreen({
|
|||||||
await document.msExitFullscreen()
|
await document.msExitFullscreen()
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error exiting fullscreen:', error)
|
reportError('fullscreen_failure', error, {
|
||||||
|
context: 'Error exiting fullscreen:',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { usePatchRoom } from '@/features/rooms/api/patchRoom'
|
import { usePatchRoom } from '@/features/rooms/api/patchRoom'
|
||||||
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
|
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const usePermissionsManager = () => {
|
export const usePermissionsManager = () => {
|
||||||
const { mutateAsync: patchRoom } = usePatchRoom()
|
const { mutateAsync: patchRoom } = usePatchRoom()
|
||||||
@@ -28,7 +29,9 @@ export const usePermissionsManager = () => {
|
|||||||
|
|
||||||
return { configuration: newConfiguration }
|
return { configuration: newConfiguration }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to update muting permission:', error)
|
reportError('permissions_api_failure', error, {
|
||||||
|
context: 'Failed to update muting permission:',
|
||||||
|
})
|
||||||
return { success: false, error }
|
return { success: false, error }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
NotificationType,
|
NotificationType,
|
||||||
useNotifyParticipants,
|
useNotifyParticipants,
|
||||||
} from '@/features/notifications'
|
} from '@/features/notifications'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export const updatePublishSources = (
|
export const updatePublishSources = (
|
||||||
currentSources: Source[],
|
currentSources: Source[],
|
||||||
@@ -108,7 +109,9 @@ export const usePublishSourcesManager = () => {
|
|||||||
|
|
||||||
return { configuration: newConfiguration }
|
return { configuration: newConfiguration }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to update ${sources}:`, error)
|
reportError('publish_sources_failure', error, {
|
||||||
|
context: `Failed to update ${sources}:`,
|
||||||
|
})
|
||||||
return { success: false, error }
|
return { success: false, error }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
import { isLocal } from '@/utils/livekit'
|
import { isLocal } from '@/utils/livekit'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { useRaiseHand } from '@/features/rooms/api/updateRaiseHand'
|
import { useRaiseHand } from '@/features/rooms/api/updateRaiseHand'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
type useRaisedHandProps = {
|
type useRaisedHandProps = {
|
||||||
participant: Participant
|
participant: Participant
|
||||||
@@ -79,8 +80,11 @@ export function useRaisedHand({ participant }: useRaisedHandProps) {
|
|||||||
try {
|
try {
|
||||||
await raiseHand(!isHandRaised)
|
await raiseHand(!isHandRaised)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(
|
reportError(
|
||||||
`Failed to toggle hand: ${e instanceof Error ? e.message : 'Unknown error'}`
|
'generic_failure',
|
||||||
|
new Error(
|
||||||
|
`Failed to toggle hand: ${e instanceof Error ? e.message : 'Unknown error'}`
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { SidePanel } from '../components/SidePanel'
|
|||||||
import { RecordingProvider } from '@/features/recording'
|
import { RecordingProvider } from '@/features/recording'
|
||||||
import { ScreenShareErrorModal } from '../components/ScreenShareErrorModal'
|
import { ScreenShareErrorModal } from '../components/ScreenShareErrorModal'
|
||||||
import { ConnectionObserver } from '../components/ConnectionObserver'
|
import { ConnectionObserver } from '../components/ConnectionObserver'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
import { MediaStateObserver } from '../components/MediaStateObserver'
|
import { MediaStateObserver } from '../components/MediaStateObserver'
|
||||||
import { RoomMetadataSynchronizer } from '../components/RoomMetadataSynchronizer'
|
import { RoomMetadataSynchronizer } from '../components/RoomMetadataSynchronizer'
|
||||||
import { useRoomPageTitle } from '../hooks/useRoomPageTitle'
|
import { useRoomPageTitle } from '../hooks/useRoomPageTitle'
|
||||||
@@ -91,7 +92,10 @@ export function VideoConference({ ...props }: VideoConferenceProps) {
|
|||||||
</RoomContentArea>
|
</RoomContentArea>
|
||||||
<ControlBar
|
<ControlBar
|
||||||
onDeviceError={(e) => {
|
onDeviceError={(e) => {
|
||||||
console.error(e)
|
reportError('device_switch_failure', e.error, {
|
||||||
|
at: 'ControlBar.onDeviceError',
|
||||||
|
source: e.source,
|
||||||
|
})
|
||||||
if (
|
if (
|
||||||
e.source == Track.Source.ScreenShare &&
|
e.source == Track.Source.ScreenShare &&
|
||||||
e.error.toString() ==
|
e.error.toString() ==
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
export const asError = (value: unknown): Error => {
|
|
||||||
if (value instanceof Error) return value
|
|
||||||
if (value instanceof Event) {
|
|
||||||
return new Error(
|
|
||||||
`Unhandled event "${value.type}" from ${value.target?.constructor.name ?? 'unknown'}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return new Error(String(value))
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ import { useUser } from '@/features/auth/api/useUser'
|
|||||||
import { Spinner } from '@/primitives/Spinner'
|
import { Spinner } from '@/primitives/Spinner'
|
||||||
import { CallbackIdHandler } from '../utils/CallbackIdHandler'
|
import { CallbackIdHandler } from '../utils/CallbackIdHandler'
|
||||||
import { PopupWindow } from '../utils/PopupWindow'
|
import { PopupWindow } from '../utils/PopupWindow'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
const callbackIdHandler = new CallbackIdHandler()
|
const callbackIdHandler = new CallbackIdHandler()
|
||||||
const popupWindow = new PopupWindow()
|
const popupWindow = new PopupWindow()
|
||||||
@@ -52,7 +53,9 @@ const CreatePopup = () => {
|
|||||||
popupWindow.close()
|
popupWindow.close()
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to create meeting room:', error)
|
reportError('generic_failure', error, {
|
||||||
|
context: 'Failed to create meeting room:',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isLoggedIn && callbackId) {
|
if (isLoggedIn && callbackId) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { usePatchRoom } from '@/features/rooms/api/patchRoom'
|
|||||||
import { ApiAccessLevel } from '@/features/rooms/api/ApiRoom'
|
import { ApiAccessLevel } from '@/features/rooms/api/ApiRoom'
|
||||||
import { updatePublishSources } from '@/features/rooms/livekit/hooks/usePublishSourcesManager'
|
import { updatePublishSources } from '@/features/rooms/livekit/hooks/usePublishSourcesManager'
|
||||||
import { isSubsetOf } from '@/features/rooms/utils/isSubsetOf'
|
import { isSubsetOf } from '@/features/rooms/utils/isSubsetOf'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
type Source = Track.Source
|
type Source = Track.Source
|
||||||
|
|
||||||
@@ -108,7 +109,7 @@ const SettingsPopup = () => {
|
|||||||
patchRoom({
|
patchRoom({
|
||||||
roomId: roomSlug,
|
roomId: roomSlug,
|
||||||
room: { configuration: newConfiguration },
|
room: { configuration: newConfiguration },
|
||||||
}).catch((e) => console.error(e))
|
}).catch((e) => reportError('generic_failure', e))
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateSource = (sources: Source[], enabled: boolean) => {
|
const updateSource = (sources: Source[], enabled: boolean) => {
|
||||||
@@ -329,7 +330,7 @@ const SettingsPopup = () => {
|
|||||||
patchRoom({
|
patchRoom({
|
||||||
roomId: roomSlug,
|
roomId: roomSlug,
|
||||||
room: { access_level: value as ApiAccessLevel },
|
room: { access_level: value as ApiAccessLevel },
|
||||||
}).catch((e) => console.error(e))
|
}).catch((e) => reportError('generic_failure', e))
|
||||||
}
|
}
|
||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { authUrl } from '@/features/auth/utils/authUrl'
|
import { authUrl } from '@/features/auth/utils/authUrl'
|
||||||
import { PopupMessageType, CallbackCreationRoomData } from './types'
|
import { PopupMessageType, CallbackCreationRoomData } from './types'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export class PopupWindow {
|
export class PopupWindow {
|
||||||
private sendMessageToManager(
|
private sendMessageToManager(
|
||||||
@@ -9,7 +10,7 @@ export class PopupWindow {
|
|||||||
callback?: () => void
|
callback?: () => void
|
||||||
) {
|
) {
|
||||||
if (!window.opener) {
|
if (!window.opener) {
|
||||||
console.error('No manager window found')
|
reportError('generic_failure', new Error('No manager window found'))
|
||||||
window.close()
|
window.close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { useRenameParticipant } from '@/features/rooms/api/renameParticipant'
|
|||||||
import { saveUsername } from '@/stores/user'
|
import { saveUsername } from '@/stores/user'
|
||||||
import { logout } from '@/features/auth/utils/logout'
|
import { logout } from '@/features/auth/utils/logout'
|
||||||
import { useConfig } from '@/api/useConfig'
|
import { useConfig } from '@/api/useConfig'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export type AccountTabProps = Pick<DialogProps, 'onOpenChange'> &
|
export type AccountTabProps = Pick<DialogProps, 'onOpenChange'> &
|
||||||
Pick<TabPanelProps, 'id'>
|
Pick<TabPanelProps, 'id'>
|
||||||
@@ -35,8 +36,11 @@ export const AccountTab = ({ id, onOpenChange }: AccountTabProps) => {
|
|||||||
saveUsername(name)
|
saveUsername(name)
|
||||||
onOpenChange?.(false) // only close on success
|
onOpenChange?.(false) // only close on success
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
reportError(
|
||||||
`Failed to rename participant: ${error instanceof Error ? error.message : 'Unknown error'}`
|
'generic_failure',
|
||||||
|
new Error(
|
||||||
|
`Failed to rename participant: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { type StyledVariantProps } from '@/styled-system/types'
|
|||||||
import { styled } from '@/styled-system/jsx'
|
import { styled } from '@/styled-system/jsx'
|
||||||
import { FieldErrors } from './FieldErrors'
|
import { FieldErrors } from './FieldErrors'
|
||||||
import { FieldDescription } from './FieldDescription'
|
import { FieldDescription } from './FieldDescription'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
// styled taken from example at https://react-spectrum.adobe.com/react-aria/Checkbox.html
|
// styled taken from example at https://react-spectrum.adobe.com/react-aria/Checkbox.html
|
||||||
const StyledCheckbox = styled(RACCheckbox, {
|
const StyledCheckbox = styled(RACCheckbox, {
|
||||||
@@ -112,8 +113,11 @@ export const Checkbox = ({
|
|||||||
const descriptionId = useId()
|
const descriptionId = useId()
|
||||||
|
|
||||||
if (isInvalid !== undefined) {
|
if (isInvalid !== undefined) {
|
||||||
console.error(
|
reportError(
|
||||||
'Checkbox: passing isInvalid is not supported, use the validate prop instead'
|
'generic_failure',
|
||||||
|
new Error(
|
||||||
|
'Checkbox: passing isInvalid is not supported, use the validate prop instead'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { proxy, subscribe } from 'valtio'
|
import { proxy, subscribe } from 'valtio'
|
||||||
import { STORAGE_KEYS } from '@/utils/storageKeys'
|
import { STORAGE_KEYS } from '@/utils/storageKeys'
|
||||||
import { deserializeToProxyMap } from '@/utils/valtio'
|
import { deserializeToProxyMap } from '@/utils/valtio'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
export type UiFont =
|
export type UiFont =
|
||||||
| 'default'
|
| 'default'
|
||||||
@@ -154,10 +155,9 @@ function getAccessibilityState(): AccessibilityState {
|
|||||||
|
|
||||||
return DEFAULT_STATE
|
return DEFAULT_STATE
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
console.error(
|
reportError('generic_failure', error, {
|
||||||
'[AccessibilityStore] Failed to parse stored settings:',
|
context: '[AccessibilityStore] Failed to parse stored settings:',
|
||||||
error
|
})
|
||||||
)
|
|
||||||
return DEFAULT_STATE
|
return DEFAULT_STATE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { proxyMap } from 'valtio/utils'
|
|||||||
import { deserializeToProxyMap, serializeProxyMap } from '@/utils/valtio'
|
import { deserializeToProxyMap, serializeProxyMap } from '@/utils/valtio'
|
||||||
import { STORAGE_KEYS } from '@/utils/storageKeys'
|
import { STORAGE_KEYS } from '@/utils/storageKeys'
|
||||||
import { NotificationType } from '@/features/notifications/NotificationType'
|
import { NotificationType } from '@/features/notifications/NotificationType'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
soundNotifications: Map<NotificationType, boolean>
|
soundNotifications: Map<NotificationType, boolean>
|
||||||
@@ -41,10 +42,9 @@ function getNotificationsState(): State {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
console.error(
|
reportError('generic_failure', error, {
|
||||||
'[NotificationsStore] Failed to parse stored settings:',
|
context: '[NotificationsStore] Failed to parse stored settings:',
|
||||||
error
|
})
|
||||||
)
|
|
||||||
return DEFAULT_STATE
|
return DEFAULT_STATE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { proxy, subscribe } from 'valtio'
|
import { proxy, subscribe } from 'valtio'
|
||||||
import { STORAGE_KEYS } from '@/utils/storageKeys'
|
import { STORAGE_KEYS } from '@/utils/storageKeys'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
username: string
|
username: string
|
||||||
@@ -18,10 +19,9 @@ function getUserState(): State {
|
|||||||
...parsed,
|
...parsed,
|
||||||
}
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
console.error(
|
reportError('generic_failure', error, {
|
||||||
'[UserPreferencesStore] Failed to parse stored settings:',
|
context: '[UserPreferencesStore] Failed to parse stored settings:',
|
||||||
error
|
})
|
||||||
)
|
|
||||||
return DEFAULT_STATE
|
return DEFAULT_STATE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { proxy, subscribe } from 'valtio'
|
import { proxy, subscribe } from 'valtio'
|
||||||
import { STORAGE_KEYS } from '@/utils/storageKeys'
|
import { STORAGE_KEYS } from '@/utils/storageKeys'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
is_idle_disconnect_modal_enabled: boolean
|
is_idle_disconnect_modal_enabled: boolean
|
||||||
@@ -21,10 +22,9 @@ function getUserPreferencesState(): State {
|
|||||||
...parsed,
|
...parsed,
|
||||||
}
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
console.error(
|
reportError('generic_failure', error, {
|
||||||
'[UserPreferencesStore] Failed to parse stored settings:',
|
context: '[UserPreferencesStore] Failed to parse stored settings:',
|
||||||
error
|
})
|
||||||
)
|
|
||||||
return DEFAULT_STATE
|
return DEFAULT_STATE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
import { reportError } from '@/features/analytics/telemetry'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls all functions in the order they were chained with the same arguments.
|
* Calls all functions in the order they were chained with the same arguments.
|
||||||
@@ -25,7 +26,7 @@ export function chain(...callbacks: any[]): (...args: any[]) => void {
|
|||||||
try {
|
try {
|
||||||
callback(...args)
|
callback(...args)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
reportError('generic_failure', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user