widgets: wrap each room + furniture widget in its own WidgetErrorBoundary

The umbrella boundary on RoomWidgetsView caught any widget crash but
unmounted every sibling along with the failing widget — a single bad
parser in ChatWidget would dark out the avatar info, chat input,
doorbell and all furniture overlays until the next remount.

Wraps each of the 13 direct children of RoomWidgetsView (AvatarInfo,
Chat, ChatInput, Doorbell, RoomTools, RoomFilterWords, RoomThumbnail,
FurniChooser, PetPackage, UserChooser, WordQuiz, FriendRequest, plus
the FurnitureWidgets umbrella) and each of the 20 sub-widgets inside
FurnitureWidgetsView in its own named WidgetErrorBoundary. A crash
now silently logs through NitroLogger with the widget name and
renders null for that one widget; every sibling keeps rendering.

The outer umbrella stays as defense-in-depth for the wrapper div and
the listener setup in RoomWidgetsView itself.

Closes the "Per-widget WidgetErrorBoundary wrapping" roadmap item;
updates CLAUDE.md and docs/ARCHITECTURE.md accordingly.
This commit is contained in:
simoleo89
2026-05-14 20:18:38 +02:00
parent 97c9717253
commit ab93113ce7
4 changed files with 43 additions and 51 deletions
+13 -13
View File
@@ -161,20 +161,20 @@ export const RoomWidgetsView: FC<{}> = props =>
return (
<WidgetErrorBoundary name="RoomWidgets">
<div className="absolute top-0 left-0 pointer-events-none size-full">
<FurnitureWidgetsView />
<WidgetErrorBoundary name="FurnitureWidgets"><FurnitureWidgetsView /></WidgetErrorBoundary>
</div>
<AvatarInfoWidgetView />
<ChatWidgetView />
<ChatInputView />
<DoorbellWidgetView />
<RoomToolsWidgetView />
<RoomFilterWordsWidgetView />
<RoomThumbnailWidgetView />
<FurniChooserWidgetView />
<PetPackageWidgetView />
<UserChooserWidgetView />
<WordQuizWidgetView />
<FriendRequestWidgetView />
<WidgetErrorBoundary name="AvatarInfoWidget"><AvatarInfoWidgetView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="ChatWidget"><ChatWidgetView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="ChatInput"><ChatInputView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="DoorbellWidget"><DoorbellWidgetView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="RoomToolsWidget"><RoomToolsWidgetView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="RoomFilterWordsWidget"><RoomFilterWordsWidgetView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="RoomThumbnailWidget"><RoomThumbnailWidgetView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurniChooserWidget"><FurniChooserWidgetView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="PetPackageWidget"><PetPackageWidgetView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="UserChooserWidget"><UserChooserWidgetView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="WordQuizWidget"><WordQuizWidgetView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FriendRequestWidget"><FriendRequestWidgetView /></WidgetErrorBoundary>
</WidgetErrorBoundary>
);
};
@@ -1,4 +1,5 @@
import { FC } from 'react';
import { WidgetErrorBoundary } from '../../../../common';
import { FurnitureBackgroundColorView } from './FurnitureBackgroundColorView';
import { FurnitureAreaHideView } from './FurnitureAreaHideView';
import { FurnitureBadgeDisplayView } from './FurnitureBadgeDisplayView';
@@ -24,26 +25,26 @@ export const FurnitureWidgetsView: FC<{}> = props =>
{
return (
<>
<FurnitureAreaHideView />
<FurnitureBackgroundColorView />
<FurnitureBadgeDisplayView />
<FurnitureCraftingView />
<FurnitureDimmerView />
<FurnitureExchangeCreditView />
<FurnitureExternalImageView />
<FurnitureFriendFurniView />
<FurnitureGiftOpeningView />
<FurnitureHighScoreView />
<FurnitureInternalLinkView />
<FurnitureMannequinView />
<FurniturePlaylistEditorWidgetView />
<FurnitureRoomLinkView />
<FurnitureSpamWallPostItView />
<FurnitureStackHeightView />
<FurnitureStickieView />
<FurnitureTrophyView />
<FurnitureContextMenuView />
<FurnitureYoutubeDisplayView />
<WidgetErrorBoundary name="FurnitureAreaHide"><FurnitureAreaHideView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureBackgroundColor"><FurnitureBackgroundColorView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureBadgeDisplay"><FurnitureBadgeDisplayView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureCrafting"><FurnitureCraftingView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureDimmer"><FurnitureDimmerView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureExchangeCredit"><FurnitureExchangeCreditView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureExternalImage"><FurnitureExternalImageView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureFriendFurni"><FurnitureFriendFurniView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureGiftOpening"><FurnitureGiftOpeningView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureHighScore"><FurnitureHighScoreView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureInternalLink"><FurnitureInternalLinkView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureMannequin"><FurnitureMannequinView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurniturePlaylistEditorWidget"><FurniturePlaylistEditorWidgetView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureRoomLink"><FurnitureRoomLinkView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureSpamWallPostIt"><FurnitureSpamWallPostItView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureStackHeight"><FurnitureStackHeightView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureStickie"><FurnitureStickieView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureTrophy"><FurnitureTrophyView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureContextMenu"><FurnitureContextMenuView /></WidgetErrorBoundary>
<WidgetErrorBoundary name="FurnitureYoutubeDisplay"><FurnitureYoutubeDisplayView /></WidgetErrorBoundary>
</>
);
};