Compare commits

..

1 Commits

Author SHA1 Message Date
lebaudantoine 1d3281da7f 🔥(frontend) drop unused vendored ConnectionObserver
The vendored ConnectionObserver collected connection data that never
turned out to be useful for debugging.

Remove it to reduce dead code, and re-add a targeted observer later
if a concrete debugging need shows up.
2026-08-13 10:26:55 +02:00
7 changed files with 14 additions and 89 deletions
-4
View File
@@ -11,16 +11,12 @@ and this project adheres to
### Changed
- 🔥(frontend) drop unused vendored ConnectionObserver
- 🐛(frontend) vendor formatChatMessageLinks and trim surrounding newlines
### Fixed
- 📈(frontend) downgrade unreachable external home URL from error to event
- 🐛(frontend) handle 401 responses when syncing user preferences
- 🐛(frontend) harden speaker test against missing sinks and play errors
- 🐛(frontend) implement hysteresis band for the control bar layout
- 🐛(frontend) fix toolbar ResizeObserver loop and alignment drift
- 🐛(analytics) filter benign ResizeObserver loop error in Sentry/PostHog
## [1.26.0] - 2026-08-12
@@ -1,24 +0,0 @@
import type { CaptureResult } from 'posthog-js'
const IGNORED_EXCEPTION_PATTERNS = [
/ResizeObserver loop (completed with undelivered notifications|limit exceeded)/,
]
const shouldIgnoreException = (value: unknown): boolean =>
typeof value === 'string' &&
IGNORED_EXCEPTION_PATTERNS.some((pattern) => pattern.test(value))
export const filterExceptions = (
event: CaptureResult | null
): CaptureResult | null => {
if (event?.event !== '$exception') return event
const exceptionList = event.properties?.['$exception_list']
const values: unknown[] = Array.isArray(exceptionList)
? exceptionList.map((exception) => exception?.value)
: []
values.push(event.properties?.['$exception_message'])
return values.some(shouldIgnoreException) ? null : event
}
@@ -2,7 +2,6 @@ import { useEffect } from 'react'
import { type ApiUser } from '@/features/auth/api/ApiUser'
import { useUser } from '@/features/auth/api/useUser'
import { getPosthog } from '../utils'
import { filterExceptions } from '../exceptionFilters'
export const startAnalyticsSession = (data: ApiUser) => {
getPosthog().then((ph) => {
@@ -48,7 +47,6 @@ export const useAnalytics = ({
capture_unhandled_rejections: true,
capture_console_errors: true,
},
before_send: filterExceptions,
})
})
}, [id, host, flags_api_host, isDisabled])
@@ -1,6 +1,6 @@
import { ChatRow } from '@/stores/chat'
import React, { useMemo } from 'react'
import { formatChatMessageLinks } from '../utils'
import { formatChatMessageLinks } from '@livekit/components-react'
import { css } from '@/styled-system/css'
import { Text } from '@/primitives'
-32
View File
@@ -1,32 +0,0 @@
import { tokenize, createDefaultGrammar } from '@livekit/components-core'
import { ReactNode } from 'react'
const defaultGrammar = Object.freeze(createDefaultGrammar())
export function formatChatMessageLinks(message: string): ReactNode {
const trimmedMessage = message.replace(/^[\r\n]+|[\r\n]+$/g, '')
return tokenize(trimmedMessage, defaultGrammar).map((tok, i) => {
if (typeof tok === `string`) {
return tok
} else {
const content = tok.content.toString()
const href =
tok.type === `url`
? /^http(s?):\/\//.test(content)
? content
: `https://${content}`
: `mailto:${content}`
return (
<a
className="lk-chat-link"
key={i}
href={href}
target="_blank"
rel="noreferrer"
>
{content}
</a>
)
}
})
}
@@ -26,8 +26,8 @@ const StyledContainer = styled('div', {
backgroundColor: 'primaryDark.100',
maxWidth: '100%',
opacity: 0,
translate: '0 3.25rem',
transition: 'opacity, translate',
transform: 'translateY(3.25rem)',
transition: 'opacity, transform',
transitionDuration: '0.5s',
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
pointerEvents: 'none',
@@ -36,7 +36,7 @@ const StyledContainer = styled('div', {
isVisible: {
true: {
opacity: 1,
translate: '0 0',
transform: 'translateY(0)',
pointerEvents: 'auto',
},
},
@@ -84,7 +84,7 @@ export const ReactionButtonsContainer = ({
shouldBeCenteredWithToggleButton,
setShouldBeCenteredWithToggleButton,
] = useState(false)
const [offsetX, setOffsetX] = useState(0)
const [rightOffset, setRightOffset] = useState(0)
const updateArrows = useCallback(() => {
const el = scrollRef.current
@@ -115,7 +115,7 @@ export const ReactionButtonsContainer = ({
useLayoutEffect(() => {
if (!shouldBeCenteredWithToggleButton || isMobile) {
setOffsetX(0)
setRightOffset(0)
return
}
@@ -133,7 +133,7 @@ export const ReactionButtonsContainer = ({
const containerCenterX = containerRect.left + containerRect.width / 2
const shift = toggleCenterX - containerCenterX
if (Math.abs(shift) < 0.5) return
setOffsetX((prev) => prev + shift)
setRightOffset((prev) => prev - shift * 2)
}
const schedule = () => {
@@ -182,7 +182,7 @@ export const ReactionButtonsContainer = ({
isVisible={isVisible}
style={
shouldBeCenteredWithToggleButton && !isMobile && adjustedCentering
? { transform: `translateX(${offsetX}px)` }
? { marginRight: `${rightOffset}px` }
: { margin: '0 15px' }
}
>
@@ -12,8 +12,7 @@ import type { ToggleButtonProps } from '@/primitives/ToggleButton'
import { RiArrowDownSLine, RiArrowUpSLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
const CONTROL_BAR_BREAKPOINT_WIDE = 1100
const CONTROL_BAR_BREAKPOINT_NARROW = 1050
const CONTROL_BAR_BREAKPOINT = 1100
const NavigationControls = ({
onPress,
@@ -66,9 +65,10 @@ export const LateralMenu = () => {
</DialogTrigger>
)
}
interface BreakpointObserverProps {
containerRef: RefObject<HTMLDivElement>
onWideChange: (isWide: boolean | null) => void
onWideChange: (isWide: boolean) => void
}
const BreakpointObserver = ({
@@ -76,20 +76,7 @@ const BreakpointObserver = ({
onWideChange,
}: BreakpointObserverProps) => {
const { width } = useSize(containerRef)
const [isWide, setIsWide] = useState<boolean | null>(null)
useEffect(() => {
if (!width) {
return
}
if (width > CONTROL_BAR_BREAKPOINT_WIDE) {
setIsWide(true)
} else if (width <= CONTROL_BAR_BREAKPOINT_NARROW) {
setIsWide(false)
} else {
setIsWide((prev) => (prev === null ? false : prev))
}
}, [width])
const isWide = width > CONTROL_BAR_BREAKPOINT
useEffect(() => {
onWideChange(isWide)
@@ -103,7 +90,7 @@ export const MoreOptions = ({
}: {
parentElement: RefObject<HTMLDivElement>
}) => {
const [isWide, setIsWide] = useState<boolean | null>(null)
const [isWide, setIsWide] = useState(false)
return (
<nav
@@ -120,7 +107,7 @@ export const MoreOptions = ({
containerRef={parentElement}
onWideChange={setIsWide}
/>
{isWide !== null && (isWide ? <NavigationControls /> : <LateralMenu />)}
{isWide ? <NavigationControls /> : <LateralMenu />}
</nav>
)
}