Remove unused code left over from the old search (#8947)

This commit is contained in:
Janne Mareike Koschinski 2022-06-30 17:14:49 +02:00 committed by GitHub
parent 424d33d4b0
commit 328d7ea5eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 102 additions and 466 deletions

View file

@ -217,14 +217,6 @@ $roomListCollapsedWidth: 68px;
}
}
.mx_LeftPanel_roomListFilterCount {
font-size: $font-13px;
font-weight: $font-semi-bold;
margin-left: 12px;
margin-top: 14px;
margin-bottom: -4px; // to counteract the normal roomListWrapper margin-top
}
.mx_LeftPanel_roomListWrapper {
// Make the y-scrollbar more responsive
padding-right: 2px;

View file

@ -14,35 +14,30 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { ComponentType, createRef, ReactComponentElement, RefObject } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomType, EventType } from "matrix-js-sdk/src/@types/event";
import * as fbEmitter from "fbemitter";
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
import { Room } from "matrix-js-sdk/src/models/room";
import React, { ComponentType, createRef, ReactComponentElement, RefObject } from "react";
import { _t, _td } from "../../../languageHandler";
import { IState as IRovingTabIndexState, RovingTabIndexProvider } from "../../../accessibility/RovingTabIndex";
import ResizeNotifier from "../../../utils/ResizeNotifier";
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore";
import { RoomViewStore } from "../../../stores/RoomViewStore";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { Action } from "../../../dispatcher/actions";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import { ActionPayload } from "../../../dispatcher/payloads";
import { ViewRoomDeltaPayload } from "../../../dispatcher/payloads/ViewRoomDeltaPayload";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
import { _t, _td } from "../../../languageHandler";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import PosthogTrackers from "../../../PosthogTrackers";
import SettingsStore from "../../../settings/SettingsStore";
import { UIComponent } from "../../../settings/UIFeature";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import { ITagMap } from "../../../stores/room-list/algorithms/models";
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import RoomSublist, { IAuxButtonProps } from "./RoomSublist";
import { ActionPayload } from "../../../dispatcher/payloads";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import ExtraTile from "./ExtraTile";
import { Action } from "../../../dispatcher/actions";
import { ViewRoomDeltaPayload } from "../../../dispatcher/payloads/ViewRoomDeltaPayload";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays";
import { objectShallowClone, objectWithOnly } from "../../../utils/objects";
import IconizedContextMenu, {
IconizedContextMenuOption,
IconizedContextMenuOptionList,
} from "../context_menus/IconizedContextMenu";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import { BetaPill } from "../beta/BetaCard";
import SpaceStore from "../../../stores/spaces/SpaceStore";
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore";
import { RoomViewStore } from "../../../stores/RoomViewStore";
import {
isMetaSpace,
ISuggestedRoom,
@ -51,17 +46,21 @@ import {
UPDATE_SELECTED_SPACE,
UPDATE_SUGGESTED_ROOMS,
} from "../../../stores/spaces";
import SpaceStore from "../../../stores/spaces/SpaceStore";
import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays";
import { objectShallowClone, objectWithOnly } from "../../../utils/objects";
import ResizeNotifier from "../../../utils/ResizeNotifier";
import { shouldShowSpaceInvite, showAddExistingRooms, showCreateNewRoom, showSpaceInvite } from "../../../utils/space";
import RoomAvatar from "../avatars/RoomAvatar";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { UIComponent } from "../../../settings/UIFeature";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import SettingsStore from "../../../settings/SettingsStore";
import PosthogTrackers from "../../../PosthogTrackers";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import RoomAvatar from "../avatars/RoomAvatar";
import { BetaPill } from "../beta/BetaCard";
import IconizedContextMenu, {
IconizedContextMenuOption,
IconizedContextMenuOptionList,
} from "../context_menus/IconizedContextMenu";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import ExtraTile from "./ExtraTile";
import RoomSublist, { IAuxButtonProps } from "./RoomSublist";
interface IProps {
onKeyDown: (ev: React.KeyboardEvent, state: IRovingTabIndexState) => void;
@ -76,7 +75,6 @@ interface IProps {
interface IState {
sublists: ITagMap;
isNameFiltering: boolean;
currentRoomId?: string;
suggestedRooms: ISuggestedRoom[];
}
@ -403,7 +401,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
this.state = {
sublists: {},
isNameFiltering: !!RoomListStore.instance.getFirstNameFilterCondition(),
suggestedRooms: SpaceStore.instance.suggestedRooms,
};
}
@ -480,8 +477,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
const previousListIds = Object.keys(this.state.sublists);
const newListIds = Object.keys(newLists);
const isNameFiltering = !!RoomListStore.instance.getFirstNameFilterCondition();
let doUpdate = this.state.isNameFiltering !== isNameFiltering || arrayHasDiff(previousListIds, newListIds);
let doUpdate = arrayHasDiff(previousListIds, newListIds);
if (!doUpdate) {
// so we didn't have the visible sublists change, but did the contents of those
// sublists change significantly enough to break the sticky headers? Probably, so
@ -503,33 +499,12 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
const newSublists = objectWithOnly(newLists, newListIds);
const sublists = objectShallowClone(newSublists, (k, v) => arrayFastClone(v));
this.setState({ sublists, isNameFiltering }, () => {
this.setState({ sublists }, () => {
this.props.onResize();
});
}
};
private onStartChat = (ev: ButtonEvent) => {
const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search;
defaultDispatcher.dispatch({ action: "view_create_chat", initialText });
PosthogTrackers.trackInteraction("WebRoomListRoomsSublistPlusMenuCreateChatItem", ev);
};
private onExplore = (ev: ButtonEvent) => {
if (!isMetaSpace(this.props.activeSpace)) {
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: this.props.activeSpace,
metricsTrigger: undefined, // other
});
PosthogTrackers.trackInteraction("WebRoomListRoomsSublistPlusMenuExploreRoomsItem", ev);
} else {
const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search;
defaultDispatcher.dispatch({ action: Action.ViewRoomDirectory, initialText });
PosthogTrackers.trackInteraction("WebRoomListRoomsSublistPlusMenuExploreRoomsItem", ev);
}
};
private renderSuggestedRooms(): ReactComponentElement<typeof ExtraTile>[] {
return this.state.suggestedRooms.map(room => {
const name = room.name || room.canonical_alias || room.aliases?.[0] || _t("Empty room");
@ -573,8 +548,8 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
private renderSublists(): React.ReactElement[] {
// show a skeleton UI if the user is in no rooms and they are not filtering and have no suggested rooms
const showSkeleton = !this.state.isNameFiltering && !this.state.suggestedRooms?.length &&
Object.values(RoomListStore.instance.unfilteredLists).every(list => !list?.length);
const showSkeleton = !this.state.suggestedRooms?.length &&
Object.values(RoomListStore.instance.orderedLists).every(list => !list?.length);
return TAG_ORDER
.map(orderedTagId => {
@ -636,29 +611,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
}
public render() {
let explorePrompt: JSX.Element;
if (!this.props.isMinimized) {
if (this.state.isNameFiltering) {
explorePrompt = <div className="mx_RoomList_explorePrompt">
<div>{ _t("Can't see what you're looking for?") }</div>
<AccessibleButton
className="mx_RoomList_explorePrompt_startChat"
kind="link"
onClick={this.onStartChat}
>
{ _t("Start a new chat") }
</AccessibleButton>
<AccessibleButton
className="mx_RoomList_explorePrompt_explore"
kind="link"
onClick={this.onExplore}
>
{ !isMetaSpace(this.props.activeSpace) ? _t("Explore rooms") : _t("Explore all public rooms") }
</AccessibleButton>
</div>;
}
}
const sublists = this.renderSublists();
return (
<RovingTabIndexProvider handleHomeEnd handleUpDown onKeyDown={this.props.onKeyDown}>
@ -673,7 +625,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
ref={this.treeRef}
>
{ sublists }
{ explorePrompt }
</div>
) }
</RovingTabIndexProvider>

View file

@ -14,35 +14,22 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { useContext, useEffect, useState } from "react";
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
import { ClientEvent } from "matrix-js-sdk/src/client";
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import React, { useContext, useEffect, useState } from "react";
import { _t } from "../../../languageHandler";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { Action } from "../../../dispatcher/actions";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { useDispatcher } from "../../../hooks/useDispatcher";
import { useEventEmitterState, useTypedEventEmitter, useTypedEventEmitterState } from "../../../hooks/useEventEmitter";
import { useFeatureEnabled } from "../../../hooks/useSettings";
import SpaceStore from "../../../stores/spaces/SpaceStore";
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
import SpaceContextMenu from "../context_menus/SpaceContextMenu";
import { HomeButtonContextMenu } from "../spaces/SpacePanel";
import IconizedContextMenu, {
IconizedContextMenuOption,
IconizedContextMenuOptionList,
} from "../context_menus/IconizedContextMenu";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import {
shouldShowSpaceInvite,
showAddExistingRooms,
showCreateNewRoom,
showCreateNewSubspace,
showSpaceInvite,
} from "../../../utils/space";
import { Action } from "../../../dispatcher/actions";
import { useDispatcher } from "../../../hooks/useDispatcher";
import InlineSpinner from "../elements/InlineSpinner";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore";
import { _t } from "../../../languageHandler";
import PosthogTrackers from "../../../PosthogTrackers";
import { UIComponent } from "../../../settings/UIFeature";
import {
getMetaSpaceName,
MetaSpace,
@ -50,13 +37,24 @@ import {
UPDATE_HOME_BEHAVIOUR,
UPDATE_SELECTED_SPACE,
} from "../../../stores/spaces";
import TooltipTarget from "../elements/TooltipTarget";
import SpaceStore from "../../../stores/spaces/SpaceStore";
import {
shouldShowSpaceInvite,
showAddExistingRooms,
showCreateNewRoom,
showCreateNewSubspace,
showSpaceInvite,
} from "../../../utils/space";
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
import { BetaPill } from "../beta/BetaCard";
import PosthogTrackers from "../../../PosthogTrackers";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { useWebSearchMetrics } from "../dialogs/spotlight/SpotlightDialog";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { UIComponent } from "../../../settings/UIFeature";
import IconizedContextMenu, {
IconizedContextMenuOption,
IconizedContextMenuOptionList,
} from "../context_menus/IconizedContextMenu";
import SpaceContextMenu from "../context_menus/SpaceContextMenu";
import InlineSpinner from "../elements/InlineSpinner";
import TooltipTarget from "../elements/TooltipTarget";
import { HomeButtonContextMenu } from "../spaces/SpacePanel";
const contextMenuBelow = (elementRect: DOMRect) => {
// align the context menu's icons with the icon which opened the context menu
@ -131,15 +129,6 @@ const RoomListHeader = ({ onVisibilityChange }: IProps) => {
const videoRoomsEnabled = useFeatureEnabled("feature_video_rooms");
const pendingActions = usePendingActions();
const filterCondition = RoomListStore.instance.getFirstNameFilterCondition();
const count = useEventEmitterState(RoomListStore.instance, LISTS_UPDATE_EVENT, () => {
if (filterCondition) {
return Object.values(RoomListStore.instance.orderedLists).flat(1).length;
} else {
return null;
}
});
const canShowMainMenu = activeSpace || spaceKey === MetaSpace.Home;
useEffect(() => {
@ -149,22 +138,13 @@ const RoomListHeader = ({ onVisibilityChange }: IProps) => {
}
}, [closeMainMenu, canShowMainMenu, mainMenuDisplayed]);
// we pass null for the queryLength to inhibit the metrics hook for when there is no filterCondition
useWebSearchMetrics(count, filterCondition ? filterCondition.search.length : null, false);
const spaceName = useTypedEventEmitterState(activeSpace, RoomEvent.Name, () => activeSpace?.name);
useEffect(() => {
if (onVisibilityChange) {
onVisibilityChange();
}
}, [count, onVisibilityChange]);
if (typeof count === "number") {
return <div className="mx_LeftPanel_roomListFilterCount">
{ _t("%(count)s results", { count }) }
</div>;
}
}, [onVisibilityChange]);
const canAddRooms = activeSpace?.currentState?.maySendStateEvent(EventType.SpaceChild, cli.getUserId());

View file

@ -16,45 +16,44 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import * as React from "react";
import { ComponentType, createRef, ReactComponentElement } from "react";
import { normalize } from "matrix-js-sdk/src/utils";
import { Room } from "matrix-js-sdk/src/models/room";
import classNames from 'classnames';
import { Dispatcher } from "flux";
import { Room } from "matrix-js-sdk/src/models/room";
import { Enable, Resizable } from "re-resizable";
import { Direction } from "re-resizable/lib/resizer";
import { Dispatcher } from "flux";
import * as React from "react";
import { ComponentType, createRef, ReactComponentElement } from "react";
import { polyfillTouchEvent } from "../../../@types/polyfill";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { RovingAccessibleButton, RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex";
import { Action } from "../../../dispatcher/actions";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import { ActionPayload } from "../../../dispatcher/payloads";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { _t } from "../../../languageHandler";
import AccessibleButton from "../../views/elements/AccessibleButton";
import RoomTile from "./RoomTile";
import { ListNotificationState } from "../../../stores/notifications/ListNotificationState";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import { ListAlgorithm, SortAlgorithm } from "../../../stores/room-list/algorithms/models";
import { ListLayout } from "../../../stores/room-list/ListLayout";
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
import RoomListLayoutStore from "../../../stores/room-list/RoomListLayoutStore";
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore";
import { arrayFastClone, arrayHasOrderChange } from "../../../utils/arrays";
import { objectExcluding, objectHasDiff } from "../../../utils/objects";
import ResizeNotifier from "../../../utils/ResizeNotifier";
import ContextMenu, {
ChevronFace,
ContextMenuTooltipButton,
StyledMenuItemCheckbox,
StyledMenuItemRadio,
} from "../../structures/ContextMenu";
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore";
import { ListAlgorithm, SortAlgorithm } from "../../../stores/room-list/algorithms/models";
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import { Action } from "../../../dispatcher/actions";
import NotificationBadge from "./NotificationBadge";
import AccessibleButton from "../../views/elements/AccessibleButton";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { ActionPayload } from "../../../dispatcher/payloads";
import { polyfillTouchEvent } from "../../../@types/polyfill";
import ResizeNotifier from "../../../utils/ResizeNotifier";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import RoomListLayoutStore from "../../../stores/room-list/RoomListLayoutStore";
import { arrayFastClone, arrayHasOrderChange } from "../../../utils/arrays";
import { objectExcluding, objectHasDiff } from "../../../utils/objects";
import ExtraTile from "./ExtraTile";
import { ListNotificationState } from "../../../stores/notifications/ListNotificationState";
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import NotificationBadge from "./NotificationBadge";
import RoomTile from "./RoomTile";
const SHOW_N_BUTTON_HEIGHT = 28; // As defined by CSS
const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS
@ -99,7 +98,6 @@ interface IState {
isExpanded: boolean; // used for the for expand of the sublist when the room list is being filtered
height: number;
rooms: Room[];
filteredExtraTiles?: ReactComponentElement<typeof ExtraTile>[];
}
export default class RoomSublist extends React.Component<IProps, IState> {
@ -109,7 +107,6 @@ export default class RoomSublist extends React.Component<IProps, IState> {
private dispatcherRef: string;
private layout: ListLayout;
private heightAtStart: number;
private isBeingFiltered: boolean;
private notificationState: ListNotificationState;
constructor(props: IProps) {
@ -117,12 +114,11 @@ export default class RoomSublist extends React.Component<IProps, IState> {
this.layout = RoomListLayoutStore.instance.getLayoutFor(this.props.tagId);
this.heightAtStart = 0;
this.isBeingFiltered = !!RoomListStore.instance.getFirstNameFilterCondition();
this.notificationState = RoomNotificationStateStore.instance.getListState(this.props.tagId);
this.state = {
contextMenuPosition: null,
isResizing: false,
isExpanded: this.isBeingFiltered ? this.isBeingFiltered : !this.layout.isCollapsed,
isExpanded: !this.layout.isCollapsed,
height: 0, // to be fixed in a moment, we need `rooms` to calculate this.
rooms: arrayFastClone(RoomListStore.instance.orderedLists[this.props.tagId] || []),
};
@ -156,9 +152,6 @@ export default class RoomSublist extends React.Component<IProps, IState> {
}
private get extraTiles(): ReactComponentElement<typeof ExtraTile>[] | null {
if (this.state.filteredExtraTiles) {
return this.state.filteredExtraTiles;
}
if (this.props.extraTiles) {
return this.props.extraTiles;
}
@ -179,7 +172,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
}
public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>) {
const prevExtraTiles = prevState.filteredExtraTiles || prevProps.extraTiles;
const prevExtraTiles = prevProps.extraTiles;
// as the rooms can come in one by one we need to reevaluate
// the amount of available rooms to cap the amount of requested visible rooms by the layout
if (RoomSublist.calcNumTiles(prevState.rooms, prevExtraTiles) !== this.numTiles) {
@ -203,7 +196,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
// If we're supposed to handle extra tiles, take the performance hit and re-render all the
// time so we don't have to consider them as part of the visible room optimization.
const prevExtraTiles = this.props.extraTiles || [];
const nextExtraTiles = (nextState.filteredExtraTiles || nextProps.extraTiles) || [];
const nextExtraTiles = nextProps.extraTiles || [];
if (prevExtraTiles.length > 0 || nextExtraTiles.length > 0) {
return true;
}
@ -260,32 +253,12 @@ export default class RoomSublist extends React.Component<IProps, IState> {
private onListsUpdated = () => {
const stateUpdates: IState & any = {}; // &any is to avoid a cast on the initializer
if (this.props.extraTiles) {
const nameCondition = RoomListStore.instance.getFirstNameFilterCondition();
if (nameCondition) {
stateUpdates.filteredExtraTiles = this.props.extraTiles
.filter(t => nameCondition.matches(normalize(t.props.displayName || "")));
} else if (this.state.filteredExtraTiles) {
stateUpdates.filteredExtraTiles = null;
}
}
const currentRooms = this.state.rooms;
const newRooms = arrayFastClone(RoomListStore.instance.orderedLists[this.props.tagId] || []);
if (arrayHasOrderChange(currentRooms, newRooms)) {
stateUpdates.rooms = newRooms;
}
const isStillBeingFiltered = !!RoomListStore.instance.getFirstNameFilterCondition();
if (isStillBeingFiltered !== this.isBeingFiltered) {
this.isBeingFiltered = isStillBeingFiltered;
if (isStillBeingFiltered) {
stateUpdates.isExpanded = true;
} else {
stateUpdates.isExpanded = !this.layout.isCollapsed;
}
}
if (Object.keys(stateUpdates).length > 0) {
this.setState(stateUpdates);
}
@ -418,7 +391,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
room = this.state.rooms && this.state.rooms[0];
} else {
// find the first room with a count of the same colour as the badge count
room = RoomListStore.instance.unfilteredLists[this.props.tagId].find((r: Room) => {
room = RoomListStore.instance.orderedLists[this.props.tagId].find((r: Room) => {
const notifState = this.notificationState.getForRoom(r);
return notifState.count > 0 && notifState.color === this.notificationState.color;
});

View file

@ -1791,11 +1791,6 @@
"Historical": "Historical",
"Suggested Rooms": "Suggested Rooms",
"Empty room": "Empty room",
"Can't see what you're looking for?": "Can't see what you're looking for?",
"Start a new chat": "Start a new chat",
"Explore all public rooms": "Explore all public rooms",
"%(count)s results|other": "%(count)s results",
"%(count)s results|one": "%(count)s result",
"Add space": "Add space",
"You do not have permissions to add spaces to this space": "You do not have permissions to add spaces to this space",
"Join public room": "Join public room",

View file

@ -26,14 +26,13 @@ import { IListOrderingMap, ITagMap, ITagSortingMap, ListAlgorithm, SortAlgorithm
import { ActionPayload } from "../../dispatcher/payloads";
import defaultDispatcher from "../../dispatcher/dispatcher";
import { readReceiptChangeIsFor } from "../../utils/read-receipts";
import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./filters/IFilterCondition";
import { FILTER_CHANGED, IFilterCondition } from "./filters/IFilterCondition";
import { RoomViewStore } from "../RoomViewStore";
import { Algorithm, LIST_UPDATED_EVENT } from "./algorithms/Algorithm";
import { EffectiveMembership, getEffectiveMembership } from "../../utils/membership";
import RoomListLayoutStore from "./RoomListLayoutStore";
import { MarkedExecution } from "../../utils/MarkedExecution";
import { AsyncStoreWithClient } from "../AsyncStoreWithClient";
import { NameFilterCondition } from "./filters/NameFilterCondition";
import { RoomNotificationStateStore } from "../notifications/RoomNotificationStateStore";
import { VisibilityProvider } from "./filters/VisibilityProvider";
import { SpaceWatcher } from "./SpaceWatcher";
@ -58,7 +57,6 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
private initialListsGenerated = false;
private algorithm = new Algorithm();
private filterConditions: IFilterCondition[] = [];
private prefilterConditions: IFilterCondition[] = [];
private updateFn = new MarkedExecution(() => {
for (const tagId of Object.keys(this.orderedLists)) {
@ -78,11 +76,6 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
new SpaceWatcher(this);
}
public get unfilteredLists(): ITagMap {
if (!this.algorithm) return {}; // No tags yet.
return this.algorithm.getUnfilteredRooms();
}
public get orderedLists(): ITagMap {
if (!this.algorithm) return {}; // No tags yet.
return this.algorithm.getOrderedRooms();
@ -91,7 +84,6 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
// Intended for test usage
public async resetStore() {
await this.reset();
this.filterConditions = [];
this.prefilterConditions = [];
this.initialListsGenerated = false;
@ -502,9 +494,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
let rooms = this.matrixClient.getVisibleRooms().filter(r => VisibilityProvider.instance.isRoomVisible(r));
// if spaces are enabled only consider the prefilter conditions when there are no runtime conditions
// for the search all spaces feature
if (this.prefilterConditions.length > 0 && !this.filterConditions.length) {
if (this.prefilterConditions.length > 0) {
rooms = rooms.filter(r => {
for (const filter of this.prefilterConditions) {
if (!filter.isVisible(r)) {
@ -556,20 +546,9 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
*/
public async addFilter(filter: IFilterCondition): Promise<void> {
let promise = Promise.resolve();
if (filter.kind === FilterKind.Prefilter) {
filter.on(FILTER_CHANGED, this.onPrefilterUpdated);
this.prefilterConditions.push(filter);
promise = this.recalculatePrefiltering();
} else {
this.filterConditions.push(filter);
// Runtime filters with spaces disable prefiltering for the search all spaces feature.
// this has to be awaited so that `setKnownRooms` is called in time for the `addFilterCondition` below
// this way the runtime filters are only evaluated on one dataset and not both.
await this.recalculatePrefiltering();
if (this.algorithm) {
this.algorithm.addFilterCondition(filter);
}
}
filter.on(FILTER_CHANGED, this.onPrefilterUpdated);
this.prefilterConditions.push(filter);
promise = this.recalculatePrefiltering();
promise.then(() => this.updateFn.trigger());
}
@ -582,20 +561,8 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
*/
public removeFilter(filter: IFilterCondition): void {
let promise = Promise.resolve();
let idx = this.filterConditions.indexOf(filter);
let removed = false;
if (idx >= 0) {
this.filterConditions.splice(idx, 1);
if (this.algorithm) {
this.algorithm.removeFilterCondition(filter);
}
// Runtime filters with spaces disable prefiltering for the search all spaces feature
promise = this.recalculatePrefiltering();
removed = true;
}
idx = this.prefilterConditions.indexOf(filter);
const idx = this.prefilterConditions.indexOf(filter);
if (idx >= 0) {
filter.off(FILTER_CHANGED, this.onPrefilterUpdated);
this.prefilterConditions.splice(idx, 1);
@ -608,20 +575,6 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
}
}
/**
* Gets the first (and ideally only) name filter condition. If one isn't present,
* this returns null.
* @returns The first name filter condition, or null if none.
*/
public getFirstNameFilterCondition(): NameFilterCondition | null {
for (const filter of this.filterConditions) {
if (filter instanceof NameFilterCondition) {
return filter;
}
}
return null;
}
/**
* Gets the tags for a room identified by the store. The returned set
* should never be empty, and will contain DefaultTagID.Untagged if

View file

@ -30,7 +30,6 @@ import {
ListAlgorithm,
SortAlgorithm,
} from "./models";
import { FILTER_CHANGED, IFilterCondition } from "../filters/IFilterCondition";
import { EffectiveMembership, getEffectiveMembership, splitRoomsByMembership } from "../../../utils/membership";
import { OrderingAlgorithm } from "./list-ordering/OrderingAlgorithm";
import { getListAlgorithmInstance } from "./list-ordering";
@ -67,7 +66,6 @@ interface IStickyRoom {
export class Algorithm extends EventEmitter {
private _cachedRooms: ITagMap = {};
private _cachedStickyRooms: ITagMap = {}; // a clone of the _cachedRooms, with the sticky room
private filteredRooms: ITagMap = {};
private _stickyRoom: IStickyRoom = null;
private _lastStickyRoom: IStickyRoom = null; // only not-null when changing the sticky room
private sortAlgorithms: ITagSortingMap;
@ -77,8 +75,6 @@ export class Algorithm extends EventEmitter {
private roomIdsToTags: {
[roomId: string]: TagID[];
} = {};
private allowedByFilter: Map<IFilterCondition, Room[]> = new Map<IFilterCondition, Room[]>();
private allowedRoomsByFilters: Set<Room> = new Set<Room>();
/**
* Set to true to suspend emissions of algorithm updates.
@ -107,13 +103,8 @@ export class Algorithm extends EventEmitter {
return !!this.sortAlgorithms;
}
protected get hasFilters(): boolean {
return this.allowedByFilter.size > 0;
}
protected set cachedRooms(val: ITagMap) {
this._cachedRooms = val;
this.recalculateFilteredRooms();
this.recalculateStickyRoom();
this.recalculateVideoRoom();
}
@ -151,7 +142,6 @@ export class Algorithm extends EventEmitter {
const algorithm: OrderingAlgorithm = this.algorithms[tagId];
algorithm.setSortAlgorithm(sort);
this._cachedRooms[tagId] = algorithm.orderedRooms;
this.recalculateFilteredRoomsForTag(tagId); // update filter to re-sort the list
this.recalculateStickyRoom(tagId); // update sticky room to make sure it appears if needed
this.recalculateVideoRoom(tagId);
}
@ -171,40 +161,10 @@ export class Algorithm extends EventEmitter {
algorithm.setRooms(this._cachedRooms[tagId]);
this._cachedRooms[tagId] = algorithm.orderedRooms;
this.recalculateFilteredRoomsForTag(tagId); // update filter to re-sort the list
this.recalculateStickyRoom(tagId); // update sticky room to make sure it appears if needed
this.recalculateVideoRoom(tagId);
}
public addFilterCondition(filterCondition: IFilterCondition): void {
// Populate the cache of the new filter
this.allowedByFilter.set(filterCondition, this.rooms.filter(r => filterCondition.isVisible(r)));
this.recalculateFilteredRooms();
filterCondition.on(FILTER_CHANGED, this.handleFilterChange.bind(this));
}
public removeFilterCondition(filterCondition: IFilterCondition): void {
filterCondition.off(FILTER_CHANGED, this.handleFilterChange.bind(this));
if (this.allowedByFilter.has(filterCondition)) {
this.allowedByFilter.delete(filterCondition);
this.recalculateFilteredRooms();
// If we removed the last filter, tell consumers that we've "updated" our filtered
// view. This will trick them into getting the complete room list.
if (!this.hasFilters && !this.updatesInhibited) {
this.emit(LIST_UPDATED_EVENT);
}
}
}
private handleFilterChange() {
this.recalculateFilteredRooms();
// re-emit the update so the list store can fire an off-cycle update if needed
if (this.updatesInhibited) return;
this.emit(FILTER_CHANGED);
}
private updateStickyRoom(val: Room) {
this.doUpdateStickyRoom(val);
this._lastStickyRoom = null; // clear to indicate we're done changing
@ -318,8 +278,6 @@ export class Algorithm extends EventEmitter {
// We update the filtered rooms just in case, as otherwise users will end up visiting
// a room while filtering and it'll disappear. We don't update the filter earlier in
// this function simply because we don't have to.
this.recalculateFilteredRoomsForTag(tag);
if (lastStickyRoom && lastStickyRoom.tag !== tag) this.recalculateFilteredRoomsForTag(lastStickyRoom.tag);
this.recalculateStickyRoom();
this.recalculateVideoRoom(tag);
if (lastStickyRoom && lastStickyRoom.tag !== tag) this.recalculateVideoRoom(lastStickyRoom.tag);
@ -334,7 +292,6 @@ export class Algorithm extends EventEmitter {
*/
public updateVideoRoom = () => {
// In case we're unsticking a video room, sort it back into natural order
this.recalculateFilteredRooms();
this.recalculateStickyRoom();
this.recalculateVideoRoom();
@ -345,63 +302,6 @@ export class Algorithm extends EventEmitter {
this.emit(LIST_UPDATED_EVENT, true);
};
protected recalculateFilteredRooms() {
if (!this.hasFilters) {
return;
}
logger.warn("Recalculating filtered room list");
const filters = Array.from(this.allowedByFilter.keys());
const newMap: ITagMap = {};
for (const tagId of Object.keys(this.cachedRooms)) {
// Cheaply clone the rooms so we can more easily do operations on the list.
// We optimize our lookups by trying to reduce sample size as much as possible
// to the rooms we know will be deduped by the Set.
const rooms = this.cachedRooms[tagId].map(r => r); // cheap clone
this.tryInsertStickyRoomToFilterSet(rooms, tagId);
const remainingRooms = rooms.map(r => r);
const allowedRoomsInThisTag = [];
for (const filter of filters) {
const filteredRooms = remainingRooms.filter(r => filter.isVisible(r));
for (const room of filteredRooms) {
const idx = remainingRooms.indexOf(room);
if (idx >= 0) remainingRooms.splice(idx, 1);
allowedRoomsInThisTag.push(room);
}
}
newMap[tagId] = allowedRoomsInThisTag;
}
const allowedRooms = Object.values(newMap).reduce((rv, v) => { rv.push(...v); return rv; }, <Room[]>[]);
this.allowedRoomsByFilters = new Set(allowedRooms);
this.filteredRooms = newMap;
if (this.updatesInhibited) return;
this.emit(LIST_UPDATED_EVENT);
}
protected recalculateFilteredRoomsForTag(tagId: TagID): void {
if (!this.hasFilters) return; // don't bother doing work if there's nothing to do
delete this.filteredRooms[tagId];
const rooms = this.cachedRooms[tagId].map(r => r); // cheap clone
this.tryInsertStickyRoomToFilterSet(rooms, tagId);
const filteredRooms = rooms.filter(r => this.allowedRoomsByFilters.has(r));
if (filteredRooms.length > 0) {
this.filteredRooms[tagId] = filteredRooms;
}
}
protected tryInsertStickyRoomToFilterSet(rooms: Room[], tagId: TagID) {
if (!this._stickyRoom || !this._stickyRoom.room || this._stickyRoom.tag !== tagId) return;
const position = this._stickyRoom.position;
if (position >= rooms.length) {
rooms.push(this._stickyRoom.room);
} else {
rooms.splice(position, 0, this._stickyRoom.room);
}
}
private initCachedStickyRooms() {
this._cachedStickyRooms = {};
for (const tagId of Object.keys(this.cachedRooms)) {
@ -520,18 +420,11 @@ export class Algorithm extends EventEmitter {
}
/**
* Gets an ordered set of rooms for the all known tags, filtered.
* Gets an ordered set of rooms for the all known tags.
* @returns {ITagMap} The cached list of rooms, ordered,
* for each tag. May be empty, but never null/undefined.
*/
public getOrderedRooms(): ITagMap {
if (!this.hasFilters) {
return this._cachedStickyRooms || this.cachedRooms;
}
return this.filteredRooms;
}
public getUnfilteredRooms(): ITagMap {
return this._cachedStickyRooms || this.cachedRooms;
}
@ -543,10 +436,7 @@ export class Algorithm extends EventEmitter {
* for each tag. May be empty, but never null/undefined.
*/
private getOrderedRoomsWithoutSticky(): ITagMap {
if (!this.hasFilters) {
return this.cachedRooms;
}
return this.filteredRooms;
return this.cachedRooms;
}
/**
@ -775,7 +665,6 @@ export class Algorithm extends EventEmitter {
if (!algorithm) throw new Error(`No algorithm for ${rmTag}`);
algorithm.handleRoomUpdate(room, RoomUpdateCause.RoomRemoved);
this._cachedRooms[rmTag] = algorithm.orderedRooms;
this.recalculateFilteredRoomsForTag(rmTag); // update filter to re-sort the list
this.recalculateStickyRoom(rmTag); // update sticky room to make sure it moves if needed
this.recalculateVideoRoom(rmTag);
}
@ -852,7 +741,6 @@ export class Algorithm extends EventEmitter {
this._cachedRooms[tag] = algorithm.orderedRooms;
// Flag that we've done something
this.recalculateFilteredRoomsForTag(tag); // update filter to re-sort the list
this.recalculateStickyRoom(tag); // update sticky room to make sure it appears if needed
this.recalculateVideoRoom(tag);
changed = true;

View file

@ -19,21 +19,6 @@ import { EventEmitter } from "events";
export const FILTER_CHANGED = "filter_changed";
export enum FilterKind {
/**
* A prefilter is one which coarsely determines which rooms are
* available for runtime filtering/rendering. Typically this will
* be things like Space selection.
*/
Prefilter,
/**
* Runtime filters operate on the data set exposed by prefilters.
* Typically these are dynamic values like room name searching.
*/
Runtime,
}
/**
* A filter condition for the room list, determining if a room
* should be shown or not.
@ -47,11 +32,6 @@ export enum FilterKind {
* as a change in the user's input), this emits FILTER_CHANGED.
*/
export interface IFilterCondition extends EventEmitter {
/**
* The kind of filter this presents.
*/
kind: FilterKind;
/**
* Determines if a given room should be visible under this
* condition.

View file

@ -1,72 +0,0 @@
/*
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { Room } from "matrix-js-sdk/src/models/room";
import { EventEmitter } from "events";
import { normalize } from "matrix-js-sdk/src/utils";
import { throttle } from "lodash";
import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./IFilterCondition";
/**
* A filter condition for the room list which reveals rooms of a particular
* name, or associated name (like a room alias).
*/
export class NameFilterCondition extends EventEmitter implements IFilterCondition {
private _search = "";
constructor() {
super();
}
public get kind(): FilterKind {
return FilterKind.Runtime;
}
public get search(): string {
return this._search;
}
public set search(val: string) {
this._search = val;
this.callUpdate();
}
private callUpdate = throttle(() => {
this.emit(FILTER_CHANGED);
}, 200, { trailing: true, leading: true });
public isVisible(room: Room): boolean {
const lcFilter = this.search.toLowerCase();
if (this.search[0] === '#') {
// Try and find rooms by alias
if (room.getCanonicalAlias() && room.getCanonicalAlias().toLowerCase().startsWith(lcFilter)) {
return true;
}
if (room.getAltAliases().some(a => a.toLowerCase().startsWith(lcFilter))) {
return true;
}
}
if (!room.name) return false; // should realistically not happen: the js-sdk always calculates a name
return this.matches(room.normalizedName);
}
public matches(normalizedName: string): boolean {
return normalizedName.includes(normalize(this.search));
}
}

View file

@ -17,7 +17,7 @@ limitations under the License.
import { EventEmitter } from "events";
import { Room } from "matrix-js-sdk/src/models/room";
import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./IFilterCondition";
import { FILTER_CHANGED, IFilterCondition } from "./IFilterCondition";
import { IDestroyable } from "../../../utils/IDestroyable";
import SpaceStore from "../../spaces/SpaceStore";
import { isMetaSpace, MetaSpace, SpaceKey } from "../../spaces";
@ -36,10 +36,6 @@ export class SpaceFilterCondition extends EventEmitter implements IFilterConditi
private showPeopleInSpace = true;
private space: SpaceKey = MetaSpace.Home;
public get kind(): FilterKind {
return FilterKind.Prefilter;
}
public isVisible(room: Room): boolean {
return SpaceStore.instance.isRoomInSpace(this.space, room.roomId);
}

View file

@ -187,7 +187,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
metricsTrigger: "WebSpacePanelNotificationBadge",
});
} else {
const lists = RoomListStore.instance.unfilteredLists;
const lists = RoomListStore.instance.orderedLists;
for (let i = 0; i < TAG_ORDER.length; i++) {
const t = TAG_ORDER[i];
const listRooms = lists[t];