Room list: add robustness to custom section loading (#33475)

* refactor: move all access to custom sections settings into `section.ts`

* fix: add robustness when getting the order list of custom sections

* fix: add robustness when getting the custom section data

* fix: ignore malformed section but don't erase them

* fix: remove useless await operator

* test: add more tests
This commit is contained in:
Florian Duros
2026-05-13 15:50:33 +00:00
committed by GitHub
parent c4c32b8334
commit 47f8012691
9 changed files with 178 additions and 34 deletions
@@ -39,8 +39,8 @@ import type { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload"
import PosthogTrackers from "../../PosthogTrackers";
import { type Call, CallEvent } from "../../models/Call";
import RoomListStoreV3 from "../../stores/room-list-v3/RoomListStoreV3";
import { getCustomSectionData, isDefaultSectionTag } from "../../stores/room-list-v3/section";
import { _t } from "../../languageHandler";
import { isDefaultSectionTag } from "../../stores/room-list-v3/section";
interface RoomItemProps {
room: Room;
@@ -424,7 +424,7 @@ export class RoomListItemViewModel
* Order follows the canonical section order from RoomListStoreV3.
*/
private static buildSections(roomTags: Room["tags"]): Section[] {
const customSectionData = SettingsStore.getValue("RoomList.CustomSectionData") || {};
const customSectionData = getCustomSectionData();
return (
RoomListStoreV3.instance.orderedSectionTags
@@ -17,7 +17,7 @@ import { NotificationStateEvents } from "../../stores/notifications/Notification
import { type RoomNotificationState } from "../../stores/notifications/RoomNotificationState";
import SettingsStore from "../../settings/SettingsStore";
import RoomListStoreV3 from "../../stores/room-list-v3/RoomListStoreV3";
import { isDefaultSectionTag } from "../../stores/room-list-v3/section";
import { getCustomSectionData, isCustomSectionTag, isDefaultSectionTag } from "../../stores/room-list-v3/section";
interface RoomListSectionHeaderViewModelProps {
tag: string;
@@ -139,8 +139,7 @@ export class RoomListSectionHeaderViewModel
* Handle changes to custom section data.
*/
private onCustomSectionDataChange(): void {
const customSectionData = SettingsStore.getValue("RoomList.CustomSectionData") || {};
const sectionData = customSectionData[this.props.tag];
const sectionData = isCustomSectionTag(this.props.tag) ? getCustomSectionData()[this.props.tag] : undefined;
if (sectionData) {
this.snapshot.merge({ title: sectionData.name });
}
@@ -36,10 +36,10 @@ import { hasCreateRoomRights } from "./utils";
import { keepIfSame } from "../../utils/keepIfSame";
import { DefaultTagID } from "../../stores/room-list-v3/skip-list/tag";
import { RoomListSectionHeaderViewModel } from "./RoomListSectionHeaderViewModel";
import { getCustomSectionData, isCustomSectionTag, CHATS_TAG } from "../../stores/room-list-v3/section";
import SettingsStore from "../../settings/SettingsStore";
import { tagRoom } from "../../utils/room/tagRoom";
import { getSectionTagForRoom } from "../../utils/room/getSectionTagForRoom";
import { CHATS_TAG } from "../../stores/room-list-v3/section";
/**
* Tracks the position of the active room within a specific section.
@@ -287,8 +287,7 @@ export class RoomListViewModel
public getSectionHeaderViewModel(tag: string): RoomListSectionHeaderViewModel {
if (this.roomSectionHeaderViewModels.has(tag)) return this.roomSectionHeaderViewModels.get(tag)!;
const customSections = SettingsStore.getValue("RoomList.CustomSectionData");
const title = TAG_TO_TITLE_MAP[tag] || customSections[tag]?.name || tag;
const title = TAG_TO_TITLE_MAP[tag] || (isCustomSectionTag(tag) && getCustomSectionData()[tag]?.name) || tag;
const viewModel = new RoomListSectionHeaderViewModel({
tag,
title,
@@ -692,11 +691,13 @@ function computeSections(
roomsResult: RoomsResult,
isSectionExpanded: (tag: string) => boolean,
): { sections: Section[]; isFlatList: boolean } {
const customSections = SettingsStore.getValue("RoomList.CustomSectionData");
const customSections = getCustomSectionData();
const sections = roomsResult.sections
// Only include sections that have rooms or are custom sections (which may be empty but should still be shown)
.filter((section) => section.rooms.length > 0 || customSections[section.tag])
.filter(
(section) => section.rooms.length > 0 || (isCustomSectionTag(section.tag) && customSections[section.tag]),
)
// Remove roomIds for sections that are currently collapsed according to their section header view model
.map((section) => ({
...section,