Room list: scroll to newly creation section (#33210)

* feat(rls): emit tag when section is created

* feat(vm): scroll to newly section tag

* feat(view): scroll to new section
This commit is contained in:
Florian Duros
2026-04-22 12:21:41 +00:00
committed by GitHub
parent 29411f0ded
commit 9df9fb9428
9 changed files with 101 additions and 27 deletions
@@ -485,13 +485,12 @@ export class RoomListStoreV3Class extends AsyncStoreWithClient<EmptyObject> {
/**
* Create a new section.
* Emits {@link SECTION_CREATED_EVENT} and {@link LISTS_UPDATE_EVENT} if the section was successfully created.
* Emits {@link SECTION_CREATED_EVENT} if the section was successfully created.
*/
public async createSection(): Promise<void> {
const sectionIsCreated = await createSection();
if (!sectionIsCreated) return;
this.emit(SECTION_CREATED_EVENT);
this.scheduleEmit();
const tag = await createSection();
if (!tag) return;
this.emit(SECTION_CREATED_EVENT, tag);
}
/**
+4 -4
View File
@@ -33,13 +33,13 @@ export type OrderedCustomSections = Tag[];
* Creates a new custom section by showing a dialog to the user to enter the section name.
* If the user confirms, it generates a unique tag for the section, saves the section data in the settings, and updates the ordered list of sections.
*
* @return A promise that resolves to true if the section was created, or false if the user cancelled the creation or if there was an error.
* @return A promise that resolves to the new section tag if created, or undefined if cancelled.
*/
export async function createSection(): Promise<boolean> {
export async function createSection(): Promise<string | undefined> {
const modal = Modal.createDialog(CreateSectionDialog);
const [shouldCreateSection, sectionName] = await modal.finished;
if (!shouldCreateSection || !sectionName) return false;
if (!shouldCreateSection || !sectionName) return undefined;
const tag = `element.io.section.${window.crypto.randomUUID()}`;
const newSection: CustomSection = { tag, name: sectionName };
@@ -53,5 +53,5 @@ export async function createSection(): Promise<boolean> {
const orderedSections = SettingsStore.getValue("RoomList.OrderedCustomSections") || [];
orderedSections.push(tag);
await SettingsStore.setValue("RoomList.OrderedCustomSections", null, SettingLevel.ACCOUNT, orderedSections);
return true;
return tag;
}
@@ -153,7 +153,7 @@ export class RoomListViewModel
this.disposables.trackListener(
RoomListStoreV3.instance,
RoomListStoreV3Event.SectionCreated as any,
this.onSectionCreated,
this.onSectionCreated as (...args: unknown[]) => void,
);
// Subscribe to active room changes to update selected room
@@ -500,6 +500,7 @@ export class RoomListViewModel
private async updateRoomListData(
isRoomChange: boolean = false,
roomIdOverride: string | null = null,
scrollToSectionTag: string | undefined = undefined,
): Promise<void> {
// Determine the room ID to use for calculations
// Use override if provided (e.g., during space changes), otherwise fall back to RoomViewStore
@@ -544,17 +545,23 @@ export class RoomListViewModel
// Update filter keys - only update if they have actually changed to prevent unnecessary re-renders of the room list
const previousFilterKeys = this.snapshot.current.roomListState.filterKeys;
const newFilterKeys = this.roomsResult.filterKeys?.map((k) => String(k));
const viewSections = toRoomListSection(this.sections);
const resolvedScrollToSectionTag =
scrollToSectionTag && viewSections.some((s) => s.id === scrollToSectionTag)
? scrollToSectionTag
: undefined;
const roomListState: RoomListViewState = {
activeRoomIndex,
spaceId: this.roomsResult.spaceId,
filterKeys: keepIfSame(previousFilterKeys, newFilterKeys),
scrollToSectionTag: resolvedScrollToSectionTag,
};
const activeFilterId = this.activeFilter !== undefined ? filterKeyToIdMap.get(this.activeFilter) : undefined;
const isRoomListEmpty = this.roomsResult.sections.every((section) => section.rooms.length === 0);
const isLoadingRooms = RoomListStoreV3.instance.isLoadingRooms;
const viewSections = toRoomListSection(this.sections);
const previousSections = this.snapshot.current.sections;
// Single atomic snapshot update
@@ -586,7 +593,9 @@ export class RoomListViewModel
}
};
public onSectionCreated = (): void => {
public onSectionCreated = (tag: string): void => {
this.updateRoomListData(false, null, tag);
clearTimeout(this.toastRef);
this.snapshot.merge({
toast: "section_created",