Room list: add custom section creation (#33155)
* feat: add creation section dialog * feat: add in skip list a method to change filters * feat: add helper to creation section * feat: add custom sections data to Settings * feat: add custom section to room list store v3 * feat: update header and room list item vms * feat: add toast to room list vm * feat: add new translation * chore: move util functions of room list specs * test: add custom section playwright tests * chore: call loadCustomSections in RoomListStoreV3 ctor
This commit is contained in:
@@ -201,7 +201,7 @@ export class RoomListHeaderViewModel
|
||||
};
|
||||
|
||||
public createSection = (): void => {
|
||||
// To be implemented when custom section creation is added in vms
|
||||
RoomListStoreV3.instance.createSection();
|
||||
};
|
||||
}
|
||||
/**
|
||||
@@ -275,6 +275,10 @@ function computeHeaderSpaceState(
|
||||
);
|
||||
const canAccessSpaceSettings = Boolean(activeSpace && shouldShowSpaceSettings(activeSpace));
|
||||
|
||||
const isSectionFeatureEnabled = SettingsStore.getValue("feature_room_list_sections");
|
||||
const useComposeIcon = !isSectionFeatureEnabled;
|
||||
const canCreateSection = isSectionFeatureEnabled;
|
||||
|
||||
return {
|
||||
title,
|
||||
canCreateRoom,
|
||||
@@ -283,8 +287,7 @@ function computeHeaderSpaceState(
|
||||
displaySpaceMenu,
|
||||
canInviteInSpace,
|
||||
canAccessSpaceSettings,
|
||||
// To be implemented when custom section creation is added in vms
|
||||
canCreateSection: false,
|
||||
useComposeIcon: true,
|
||||
canCreateSection,
|
||||
useComposeIcon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import { Action } from "../../dispatcher/actions";
|
||||
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";
|
||||
|
||||
interface RoomItemProps {
|
||||
room: Room;
|
||||
@@ -276,6 +277,8 @@ export class RoomListItemViewModel
|
||||
const callType =
|
||||
call?.callType === CallType.Voice ? "voice" : call?.callType === CallType.Video ? "video" : undefined;
|
||||
|
||||
const canMoveToSection = SettingsStore.getValue("feature_room_list_sections");
|
||||
|
||||
return {
|
||||
id: room.roomId,
|
||||
room,
|
||||
@@ -303,8 +306,7 @@ export class RoomListItemViewModel
|
||||
canMarkAsRead,
|
||||
canMarkAsUnread,
|
||||
roomNotifState,
|
||||
// To be implemented when custom section creation is added in vms
|
||||
canMoveToSection: false,
|
||||
canMoveToSection,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -385,6 +387,6 @@ export class RoomListItemViewModel
|
||||
};
|
||||
|
||||
public onCreateSection = (): void => {
|
||||
// To be implemented when custom section creation is added in vms
|
||||
RoomListStoreV3.instance.createSection();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -91,6 +91,11 @@ export class RoomListViewModel
|
||||
// Don't clear section vm because we want to keep the expand/collapse state even during space changes.
|
||||
private readonly roomSectionHeaderViewModels = new Map<string, RoomListSectionHeaderViewModel>();
|
||||
|
||||
/**
|
||||
* Reference to the currently displayed toast, used to automatically close the toast after a timeout.
|
||||
*/
|
||||
private toastRef?: number;
|
||||
|
||||
public constructor(props: RoomListViewModelProps) {
|
||||
const activeSpace = SpaceStore.instance.activeSpaceRoom;
|
||||
|
||||
@@ -144,6 +149,13 @@ export class RoomListViewModel
|
||||
this.onListsLoaded,
|
||||
);
|
||||
|
||||
// Subscribe to section creation
|
||||
this.disposables.trackListener(
|
||||
RoomListStoreV3.instance,
|
||||
RoomListStoreV3Event.SectionCreated as any,
|
||||
this.onSectionCreated,
|
||||
);
|
||||
|
||||
// Subscribe to active room changes to update selected room
|
||||
const dispatcherRef = dispatcher.register(this.onDispatch);
|
||||
this.disposables.track(() => {
|
||||
@@ -264,7 +276,8 @@ export class RoomListViewModel
|
||||
public getSectionHeaderViewModel(tag: string): RoomListSectionHeaderViewModel {
|
||||
if (this.roomSectionHeaderViewModels.has(tag)) return this.roomSectionHeaderViewModels.get(tag)!;
|
||||
|
||||
const title = TAG_TO_TITLE_MAP[tag] || tag;
|
||||
const customSections = SettingsStore.getValue("RoomList.CustomSectionData");
|
||||
const title = TAG_TO_TITLE_MAP[tag] || customSections[tag]?.name || tag;
|
||||
const viewModel = new RoomListSectionHeaderViewModel({
|
||||
tag,
|
||||
title,
|
||||
@@ -573,7 +586,19 @@ export class RoomListViewModel
|
||||
}
|
||||
};
|
||||
|
||||
public onSectionCreated = (): void => {
|
||||
clearTimeout(this.toastRef);
|
||||
this.snapshot.merge({
|
||||
toast: "section_created",
|
||||
});
|
||||
// Automatically close the toast after 15 seconds
|
||||
this.toastRef = setTimeout(() => {
|
||||
this.closeToast();
|
||||
}, 15 * 1000);
|
||||
};
|
||||
|
||||
public closeToast: () => void = () => {
|
||||
clearTimeout(this.toastRef);
|
||||
this.snapshot.merge({
|
||||
toast: undefined,
|
||||
});
|
||||
@@ -590,9 +615,11 @@ function computeSections(
|
||||
roomsResult: RoomsResult,
|
||||
isSectionExpanded: (tag: string) => boolean,
|
||||
): { sections: Section[]; isFlatList: boolean } {
|
||||
const customSections = SettingsStore.getValue("RoomList.CustomSectionData");
|
||||
|
||||
const sections = roomsResult.sections
|
||||
// Only include sections that have rooms
|
||||
.filter((section) => section.rooms.length > 0)
|
||||
// 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])
|
||||
// Remove roomIds for sections that are currently collapsed according to their section header view model
|
||||
.map((section) => ({
|
||||
...section,
|
||||
|
||||
Reference in New Issue
Block a user