fix(composer): recover silently from a composer render error; capture details
CI / Build & Quality Checks (push) Successful in 1m49s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 9s
CI / Trigger Desktop Build (push) Successful in 9s
CI / Playwright smoke (e2e) (push) Canceled after 3m3s
CI / Build & Quality Checks (push) Successful in 1m49s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 9s
CI / Trigger Desktop Build (push) Successful in 9s
CI / Playwright smoke (e2e) (push) Canceled after 3m3s
Reported on chat.lotusguild.org: picking a name from the @-mention list
showed "The message composer hit a snag." — clicking OK continued with the
draft intact. The composer's known failure mode is a transient render error
right after an autocomplete insert (slate-react's DOM selection sync racing
the model; 477df4ae fixed one such path). It did not reproduce locally in 60
attempts (click / Enter / Tab, fast and slow, display names with spaces and
emoji, Chromium and WebKit), so this makes it harmless and diagnosable:
- ComposerErrorBoundary: the first failure clears the selection and remounts
the composer immediately, with no notice (the draft is intact). A second
failure within 5 s shows the notice, now saying the draft is safe, with
"Reload composer" and "Copy details" (time, error, stack, component stack,
browser). Every failure is logged to the console as "[composer] render
error".
- Used for the room composer and, newly, the thread panel composer (which had
no boundary, so the same error took the whole panel down).
Verified with a temporary injected crash (not committed): one crash recovers
with the draft kept and no notice; two within 5 s show the notice, Copy
details copies the report, Reload composer restores the full draft.
Chromium e2e 19 passed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
afd14719ef
commit
4c9af57a97
@@ -1,9 +1,8 @@
|
||||
import React, { useCallback, useMemo, useRef } from 'react';
|
||||
import { ErrorBoundary } from 'react-error-boundary';
|
||||
import { Box, Button, Text, config } from 'folds';
|
||||
import { Box, Text, config } from 'folds';
|
||||
import { EventType } from 'matrix-js-sdk';
|
||||
import { ReactEditor } from 'slate-react';
|
||||
import { Transforms } from 'slate';
|
||||
import { isKeyHotkey } from 'is-hotkey';
|
||||
import { useStateEvent } from '../../hooks/useStateEvent';
|
||||
import { StateEvent } from '../../../types/matrix/room';
|
||||
@@ -15,6 +14,7 @@ import { RoomTimeline } from './RoomTimeline';
|
||||
import { RoomViewTyping } from './RoomViewTyping';
|
||||
import { RoomTombstone } from './RoomTombstone';
|
||||
import { RoomInput } from './RoomInput';
|
||||
import { ComposerErrorBoundary } from './ComposerErrorBoundary';
|
||||
import { RoomViewFollowing, RoomViewFollowingPlaceholder } from './RoomViewFollowing';
|
||||
import { Page } from '../../components/page';
|
||||
import { useSetting } from '../../state/hooks/settings';
|
||||
@@ -162,40 +162,7 @@ export function RoomView({ eventId }: { eventId?: string }) {
|
||||
) : (
|
||||
<>
|
||||
{canMessage && (
|
||||
<ErrorBoundary
|
||||
onReset={() => {
|
||||
// The composer crash is a transient bad-selection render
|
||||
// (e.g. after an autocomplete insert); the draft content is
|
||||
// intact. Clear the selection so the remounted composer can
|
||||
// render — the user clicks in to continue, no page refresh.
|
||||
try {
|
||||
Transforms.deselect(editor);
|
||||
} catch {
|
||||
/* editor already in a safe state */
|
||||
}
|
||||
}}
|
||||
fallbackRender={({ resetErrorBoundary }) => (
|
||||
<RoomInputPlaceholder
|
||||
role="alert"
|
||||
style={{ padding: config.space.S200 }}
|
||||
direction="Column"
|
||||
alignItems="Center"
|
||||
justifyContent="Center"
|
||||
gap="200"
|
||||
>
|
||||
<Text align="Center">The message composer hit a snag.</Text>
|
||||
<Button
|
||||
size="300"
|
||||
variant="Secondary"
|
||||
fill="Soft"
|
||||
radii="300"
|
||||
onClick={resetErrorBoundary}
|
||||
>
|
||||
<Text size="B300">Reload composer</Text>
|
||||
</Button>
|
||||
</RoomInputPlaceholder>
|
||||
)}
|
||||
>
|
||||
<ComposerErrorBoundary editor={editor}>
|
||||
<RoomInput
|
||||
room={room}
|
||||
editor={editor}
|
||||
@@ -203,7 +170,7 @@ export function RoomView({ eventId }: { eventId?: string }) {
|
||||
fileDropContainerRef={roomViewRef}
|
||||
ref={roomInputRef}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</ComposerErrorBoundary>
|
||||
)}
|
||||
{!canMessage && (
|
||||
<RoomInputPlaceholder
|
||||
|
||||
Reference in New Issue
Block a user