New Room List: Create new labs flag (#29239)

* Create new labs flag

* Render empty room list view

* Reload on flag change

* Rename RoomList.tsx to LegacyRoomList.tsx

and rename NewRoomListView.tsx to RoomListView.tsx

* Update labs.md
This commit is contained in:
R Midhun Suresh
2025-02-12 17:44:18 +05:30
committed by GitHub
parent 902146a829
commit 03a5ee1c5b
8 changed files with 104 additions and 53 deletions

View File

@@ -112,3 +112,7 @@ Unreliable in encrypted rooms.
## Knock rooms (`feature_ask_to_join`) [In Development] ## Knock rooms (`feature_ask_to_join`) [In Development]
Enables knock feature for rooms. This allows users to ask to join a room. Enables knock feature for rooms. This allows users to ask to join a room.
## New room list (`feature_new_room_list`) [In Development]
Enable the new room list that is currently in development.

View File

@@ -12,7 +12,7 @@ import classNames from "classnames";
import dis from "../../dispatcher/dispatcher"; import dis from "../../dispatcher/dispatcher";
import { _t } from "../../languageHandler"; import { _t } from "../../languageHandler";
import RoomList from "../views/rooms/RoomList"; import LegacyRoomList from "../views/rooms/LegacyRoomList";
import LegacyCallHandler, { LegacyCallHandlerEvent } from "../../LegacyCallHandler"; import LegacyCallHandler, { LegacyCallHandlerEvent } from "../../LegacyCallHandler";
import { HEADER_HEIGHT } from "../views/rooms/RoomSublist"; import { HEADER_HEIGHT } from "../views/rooms/RoomSublist";
import { Action } from "../../dispatcher/actions"; import { Action } from "../../dispatcher/actions";
@@ -36,6 +36,8 @@ import AccessibleButton, { type ButtonEvent } from "../views/elements/Accessible
import PosthogTrackers from "../../PosthogTrackers"; import PosthogTrackers from "../../PosthogTrackers";
import type PageType from "../../PageTypes"; import type PageType from "../../PageTypes";
import { Landmark, LandmarkNavigation } from "../../accessibility/LandmarkNavigation"; import { Landmark, LandmarkNavigation } from "../../accessibility/LandmarkNavigation";
import SettingsStore from "../../settings/SettingsStore";
import { RoomListView } from "../views/rooms/RoomListView";
interface IProps { interface IProps {
isMinimized: boolean; isMinimized: boolean;
@@ -56,7 +58,7 @@ interface IState {
export default class LeftPanel extends React.Component<IProps, IState> { export default class LeftPanel extends React.Component<IProps, IState> {
private listContainerRef = createRef<HTMLDivElement>(); private listContainerRef = createRef<HTMLDivElement>();
private roomListRef = createRef<RoomList>(); private roomListRef = createRef<LegacyRoomList>();
private focusedElement: Element | null = null; private focusedElement: Element | null = null;
private isDoingStickyHeaders = false; private isDoingStickyHeaders = false;
@@ -377,8 +379,25 @@ export default class LeftPanel extends React.Component<IProps, IState> {
} }
public render(): React.ReactNode { public render(): React.ReactNode {
const containerClasses = classNames({
mx_LeftPanel: true,
mx_LeftPanel_minimized: this.props.isMinimized,
});
const roomListClasses = classNames("mx_LeftPanel_actualRoomListContainer", "mx_AutoHideScrollbar");
const useNewRoomList = SettingsStore.getValue("feature_new_room_list");
if (useNewRoomList) {
return (
<div className={containerClasses}>
<div className="mx_LeftPanel_roomListContainer">
<RoomListView />
</div>
</div>
);
}
const roomList = ( const roomList = (
<RoomList <LegacyRoomList
onKeyDown={this.onKeyDown} onKeyDown={this.onKeyDown}
resizeNotifier={this.props.resizeNotifier} resizeNotifier={this.props.resizeNotifier}
onFocus={this.onFocus} onFocus={this.onFocus}
@@ -391,13 +410,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
/> />
); );
const containerClasses = classNames({
mx_LeftPanel: true,
mx_LeftPanel_minimized: this.props.isMinimized,
});
const roomListClasses = classNames("mx_LeftPanel_actualRoomListContainer", "mx_AutoHideScrollbar");
return ( return (
<div className={containerClasses}> <div className={containerClasses}>
<div className="mx_LeftPanel_roomListContainer"> <div className="mx_LeftPanel_roomListContainer">

View File

@@ -9,26 +9,26 @@ Please see LICENSE files in the repository root for full details.
import { EventType, type Room, RoomType } from "matrix-js-sdk/src/matrix"; import { EventType, type Room, RoomType } from "matrix-js-sdk/src/matrix";
import React, { type ComponentType, createRef, type ReactComponentElement, type SyntheticEvent } from "react"; import React, { type ComponentType, createRef, type ReactComponentElement, type SyntheticEvent } from "react";
import { type IState as IRovingTabIndexState, RovingTabIndexProvider } from "../../../accessibility/RovingTabIndex"; import { type IState as IRovingTabIndexState, RovingTabIndexProvider } from "../../../accessibility/RovingTabIndex.tsx";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext.tsx";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents"; import { shouldShowComponent } from "../../../customisations/helpers/UIComponents.ts";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions.ts";
import defaultDispatcher from "../../../dispatcher/dispatcher"; import defaultDispatcher from "../../../dispatcher/dispatcher.ts";
import { type ActionPayload } from "../../../dispatcher/payloads"; import { type ActionPayload } from "../../../dispatcher/payloads.ts";
import { type ViewRoomDeltaPayload } from "../../../dispatcher/payloads/ViewRoomDeltaPayload"; import { type ViewRoomDeltaPayload } from "../../../dispatcher/payloads/ViewRoomDeltaPayload.ts";
import { type ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { type ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload.ts";
import { useEventEmitterState } from "../../../hooks/useEventEmitter"; import { useEventEmitterState } from "../../../hooks/useEventEmitter.ts";
import { _t, _td, type TranslationKey } from "../../../languageHandler"; import { _t, _td, type TranslationKey } from "../../../languageHandler.tsx";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg.ts";
import PosthogTrackers from "../../../PosthogTrackers"; import PosthogTrackers from "../../../PosthogTrackers.ts";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore.ts";
import { useFeatureEnabled } from "../../../hooks/useSettings"; import { useFeatureEnabled } from "../../../hooks/useSettings.ts";
import { UIComponent } from "../../../settings/UIFeature"; import { UIComponent } from "../../../settings/UIFeature.ts";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore"; import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore.ts";
import { type ITagMap } from "../../../stores/room-list/algorithms/models"; import { type ITagMap } from "../../../stores/room-list/algorithms/models.ts";
import { DefaultTagID, type TagID } from "../../../stores/room-list/models"; import { DefaultTagID, type TagID } from "../../../stores/room-list/models.ts";
import { UPDATE_EVENT } from "../../../stores/AsyncStore"; import { UPDATE_EVENT } from "../../../stores/AsyncStore.ts";
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore"; import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore.ts";
import { import {
isMetaSpace, isMetaSpace,
type ISuggestedRoom, type ISuggestedRoom,
@@ -36,26 +36,36 @@ import {
type SpaceKey, type SpaceKey,
UPDATE_SELECTED_SPACE, UPDATE_SELECTED_SPACE,
UPDATE_SUGGESTED_ROOMS, UPDATE_SUGGESTED_ROOMS,
} from "../../../stores/spaces"; } from "../../../stores/spaces/index.ts";
import SpaceStore from "../../../stores/spaces/SpaceStore"; import SpaceStore from "../../../stores/spaces/SpaceStore.ts";
import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays"; import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays.ts";
import { objectShallowClone, objectWithOnly } from "../../../utils/objects"; import { objectShallowClone, objectWithOnly } from "../../../utils/objects.ts";
import type ResizeNotifier from "../../../utils/ResizeNotifier"; import type ResizeNotifier from "../../../utils/ResizeNotifier.ts";
import { shouldShowSpaceInvite, showAddExistingRooms, showCreateNewRoom, showSpaceInvite } from "../../../utils/space"; import {
import { ChevronFace, ContextMenuTooltipButton, type MenuProps, useContextMenu } from "../../structures/ContextMenu"; shouldShowSpaceInvite,
import RoomAvatar from "../avatars/RoomAvatar"; showAddExistingRooms,
import { BetaPill } from "../beta/BetaCard"; showCreateNewRoom,
showSpaceInvite,
} from "../../../utils/space.tsx";
import {
ChevronFace,
ContextMenuTooltipButton,
type MenuProps,
useContextMenu,
} from "../../structures/ContextMenu.tsx";
import RoomAvatar from "../avatars/RoomAvatar.tsx";
import { BetaPill } from "../beta/BetaCard.tsx";
import IconizedContextMenu, { import IconizedContextMenu, {
IconizedContextMenuOption, IconizedContextMenuOption,
IconizedContextMenuOptionList, IconizedContextMenuOptionList,
} from "../context_menus/IconizedContextMenu"; } from "../context_menus/IconizedContextMenu.tsx";
import ExtraTile from "./ExtraTile"; import ExtraTile from "./ExtraTile.tsx";
import RoomSublist, { type IAuxButtonProps } from "./RoomSublist"; import RoomSublist, { type IAuxButtonProps } from "./RoomSublist.tsx";
import { SdkContextClass } from "../../../contexts/SDKContext"; import { SdkContextClass } from "../../../contexts/SDKContext.ts";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts.ts";
import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import { getKeyBindingsManager } from "../../../KeyBindingsManager.ts";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton.tsx";
import { Landmark, LandmarkNavigation } from "../../../accessibility/LandmarkNavigation"; import { Landmark, LandmarkNavigation } from "../../../accessibility/LandmarkNavigation.ts";
import LegacyCallHandler, { LegacyCallHandlerEvent } from "../../../LegacyCallHandler.tsx"; import LegacyCallHandler, { LegacyCallHandlerEvent } from "../../../LegacyCallHandler.tsx";
interface IProps { interface IProps {
@@ -420,7 +430,7 @@ const TAG_AESTHETICS: TagAestheticsMap = {
}, },
}; };
export default class RoomList extends React.PureComponent<IProps, IState> { export default class LegacyRoomList extends React.PureComponent<IProps, IState> {
private dispatcherRef?: string; private dispatcherRef?: string;
private treeRef = createRef<HTMLDivElement>(); private treeRef = createRef<HTMLDivElement>();

View File

@@ -0,0 +1,14 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import React from "react";
type IProps = unknown;
export const RoomListView: React.FC<IProps> = (props: IProps) => {
return <div>New Room List</div>;
};

View File

@@ -1496,6 +1496,7 @@
"location_share_live_description": "Temporary implementation. Locations persist in room history.", "location_share_live_description": "Temporary implementation. Locations persist in room history.",
"mjolnir": "New ways to ignore people", "mjolnir": "New ways to ignore people",
"msc3531_hide_messages_pending_moderation": "Let moderators hide messages pending moderation.", "msc3531_hide_messages_pending_moderation": "Let moderators hide messages pending moderation.",
"new_room_list": "Enable new room list",
"notification_settings": "New Notification Settings", "notification_settings": "New Notification Settings",
"notification_settings_beta_caption": "Introducing a simpler way to change your notification settings. Customize your %(brand)s, just the way you like.", "notification_settings_beta_caption": "Introducing a simpler way to change your notification settings. Customize your %(brand)s, just the way you like.",
"notification_settings_beta_title": "Notification Settings", "notification_settings_beta_title": "Notification Settings",

View File

@@ -205,6 +205,7 @@ export interface Settings {
"feature_location_share_live": IFeature; "feature_location_share_live": IFeature;
"feature_dynamic_room_predecessors": IFeature; "feature_dynamic_room_predecessors": IFeature;
"feature_render_reaction_images": IFeature; "feature_render_reaction_images": IFeature;
"feature_new_room_list": IFeature;
"feature_ask_to_join": IFeature; "feature_ask_to_join": IFeature;
"feature_notifications": IFeature; "feature_notifications": IFeature;
// These are in the feature namespace but aren't actually features // These are in the feature namespace but aren't actually features
@@ -623,6 +624,15 @@ export const SETTINGS: Settings = {
supportedLevelsAreOrdered: true, supportedLevelsAreOrdered: true,
default: false, default: false,
}, },
"feature_new_room_list": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG_PRIORITISED,
labsGroup: LabGroup.Ui,
displayName: _td("labs|new_room_list"),
description: _td("labs|under_active_development"),
isFeature: true,
default: false,
controller: new ReloadOnChangeController(),
},
/** /**
* With the transition to Compound we are moving to a base font size * With the transition to Compound we are moving to a base font size
* of 16px. We're taking the opportunity to move away from the `baseFontSize` * of 16px. We're taking the opportunity to move away from the `baseFontSize`

View File

@@ -36,7 +36,7 @@ import { setDiff, setHasDiff } from "../../utils/sets";
import { Action } from "../../dispatcher/actions"; import { Action } from "../../dispatcher/actions";
import { arrayHasDiff, arrayHasOrderChange, filterBoolean } from "../../utils/arrays"; import { arrayHasDiff, arrayHasOrderChange, filterBoolean } from "../../utils/arrays";
import { reorderLexicographically } from "../../utils/stringOrderField"; import { reorderLexicographically } from "../../utils/stringOrderField";
import { TAG_ORDER } from "../../components/views/rooms/RoomList"; import { TAG_ORDER } from "../../components/views/rooms/LegacyRoomList";
import { type SettingUpdatedPayload } from "../../dispatcher/payloads/SettingUpdatedPayload"; import { type SettingUpdatedPayload } from "../../dispatcher/payloads/SettingUpdatedPayload";
import { import {
isMetaSpace, isMetaSpace,

View File

@@ -13,7 +13,7 @@ import userEvent from "@testing-library/user-event";
import { mocked } from "jest-mock"; import { mocked } from "jest-mock";
import { type Room } from "matrix-js-sdk/src/matrix"; import { type Room } from "matrix-js-sdk/src/matrix";
import RoomList from "../../../../../src/components/views/rooms/RoomList"; import LegacyRoomList from "../../../../../src/components/views/rooms/LegacyRoomList";
import ResizeNotifier from "../../../../../src/utils/ResizeNotifier"; import ResizeNotifier from "../../../../../src/utils/ResizeNotifier";
import { MetaSpace } from "../../../../../src/stores/spaces"; import { MetaSpace } from "../../../../../src/stores/spaces";
import { shouldShowComponent } from "../../../../../src/customisations/helpers/UIComponents"; import { shouldShowComponent } from "../../../../../src/customisations/helpers/UIComponents";
@@ -40,14 +40,14 @@ const getDMRoomsForUserId = jest.fn();
// @ts-ignore // @ts-ignore
DMRoomMap.sharedInstance = { getUserIdForRoomId, getDMRoomsForUserId }; DMRoomMap.sharedInstance = { getUserIdForRoomId, getDMRoomsForUserId };
describe("RoomList", () => { describe("LegacyRoomList", () => {
stubClient(); stubClient();
const client = MatrixClientPeg.safeGet(); const client = MatrixClientPeg.safeGet();
const store = SpaceStore.instance; const store = SpaceStore.instance;
function getComponent(props: Partial<RoomList["props"]> = {}): JSX.Element { function getComponent(props: Partial<LegacyRoomList["props"]> = {}): JSX.Element {
return ( return (
<RoomList <LegacyRoomList
onKeyDown={jest.fn()} onKeyDown={jest.fn()}
onFocus={jest.fn()} onFocus={jest.fn()}
onBlur={jest.fn()} onBlur={jest.fn()}