Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 70d7a59

Browse files
authored
Merge pull request #5969 from matrix-org/t3chguy/fix/17044.1
Switch the Home Space out for an All rooms space
2 parents 95b43d1 + 90fa738 commit 70d7a59

File tree

8 files changed

+67
-124
lines changed

8 files changed

+67
-124
lines changed

src/components/structures/RoomSearch.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ import { Action } from "../../dispatcher/actions";
2727
import RoomListStore from "../../stores/room-list/RoomListStore";
2828
import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition";
2929
import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager";
30-
import {replaceableComponent} from "../../utils/replaceableComponent";
31-
import SpaceStore, {UPDATE_SELECTED_SPACE, UPDATE_TOP_LEVEL_SPACES} from "../../stores/SpaceStore";
30+
import { replaceableComponent } from "../../utils/replaceableComponent";
31+
import SpaceStore, { UPDATE_SELECTED_SPACE, UPDATE_TOP_LEVEL_SPACES } from "../../stores/SpaceStore";
3232

3333
interface IProps {
3434
isMinimized: boolean;

src/components/views/spaces/SpacePanel.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,27 @@ import {SpaceItem} from "./SpaceTreeLevel";
2626
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
2727
import {useEventEmitter} from "../../../hooks/useEventEmitter";
2828
import SpaceStore, {
29-
HOME_SPACE,
3029
UPDATE_INVITED_SPACES,
3130
UPDATE_SELECTED_SPACE,
3231
UPDATE_TOP_LEVEL_SPACES,
3332
} from "../../../stores/SpaceStore";
3433
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
35-
import {SpaceNotificationState} from "../../../stores/notifications/SpaceNotificationState";
3634
import NotificationBadge from "../rooms/NotificationBadge";
3735
import {
3836
RovingAccessibleButton,
3937
RovingAccessibleTooltipButton,
4038
RovingTabIndexProvider,
4139
} from "../../../accessibility/RovingTabIndex";
4240
import {Key} from "../../../Keyboard";
41+
import {RoomNotificationStateStore} from "../../../stores/notifications/RoomNotificationStateStore";
42+
import {NotificationState} from "../../../stores/notifications/NotificationState";
4343

4444
interface IButtonProps {
4545
space?: Room;
4646
className?: string;
4747
selected?: boolean;
4848
tooltip?: string;
49-
notificationState?: SpaceNotificationState;
49+
notificationState?: NotificationState;
5050
isNarrow?: boolean;
5151
onClick(): void;
5252
}
@@ -212,8 +212,8 @@ const SpacePanel = () => {
212212
className="mx_SpaceButton_home"
213213
onClick={() => SpaceStore.instance.setActiveSpace(null)}
214214
selected={!activeSpace}
215-
tooltip={_t("Home")}
216-
notificationState={SpaceStore.instance.getNotificationState(HOME_SPACE)}
215+
tooltip={_t("All rooms")}
216+
notificationState={RoomNotificationStateStore.instance.globalState}
217217
isNarrow={isPanelCollapsed}
218218
/>
219219
{ invites.map(s => <SpaceItem

src/i18n/strings/en_EN.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,7 @@
10121012
"Create": "Create",
10131013
"Expand space panel": "Expand space panel",
10141014
"Collapse space panel": "Collapse space panel",
1015-
"Home": "Home",
1015+
"All rooms": "All rooms",
10161016
"Click to copy": "Click to copy",
10171017
"Copied!": "Copied!",
10181018
"Failed to copy": "Failed to copy",
@@ -2016,10 +2016,10 @@
20162016
"Continue with %(provider)s": "Continue with %(provider)s",
20172017
"Sign in with single sign-on": "Sign in with single sign-on",
20182018
"And %(count)s more...|other": "And %(count)s more...",
2019+
"Home": "Home",
20192020
"Enter a server name": "Enter a server name",
20202021
"Looks good": "Looks good",
20212022
"Can't find this server or its room list": "Can't find this server or its room list",
2022-
"All rooms": "All rooms",
20232023
"Your server": "Your server",
20242024
"Are you sure you want to remove <b>%(serverName)s</b>": "Are you sure you want to remove <b>%(serverName)s</b>",
20252025
"Remove server": "Remove server",

src/stores/SpaceStore.tsx

Lines changed: 15 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -31,28 +31,23 @@ import {RoomNotificationStateStore} from "./notifications/RoomNotificationStateS
3131
import {DefaultTagID} from "./room-list/models";
3232
import {EnhancedMap, mapDiff} from "../utils/maps";
3333
import {setHasDiff} from "../utils/sets";
34-
import {objectDiff} from "../utils/objects";
35-
import {arrayHasDiff} from "../utils/arrays";
3634
import {ISpaceSummaryEvent, ISpaceSummaryRoom} from "../components/structures/SpaceRoomDirectory";
3735
import RoomViewStore from "./RoomViewStore";
3836

39-
type SpaceKey = string | symbol;
40-
4137
interface IState {}
4238

4339
const ACTIVE_SPACE_LS_KEY = "mx_active_space";
4440

45-
export const HOME_SPACE = Symbol("home-space");
4641
export const SUGGESTED_ROOMS = Symbol("suggested-rooms");
4742

4843
export const UPDATE_TOP_LEVEL_SPACES = Symbol("top-level-spaces");
4944
export const UPDATE_INVITED_SPACES = Symbol("invited-spaces");
5045
export const UPDATE_SELECTED_SPACE = Symbol("selected-space");
51-
// Space Room ID/HOME_SPACE will be emitted when a Space's children change
46+
// Space Room ID will be emitted when a Space's children change
5247

5348
const MAX_SUGGESTED_ROOMS = 20;
5449

55-
const getSpaceContextKey = (space?: Room) => `mx_space_context_${space?.roomId || "home_space"}`;
50+
const getSpaceContextKey = (space?: Room) => `mx_space_context_${space?.roomId || "ALL_ROOMS"}`;
5651

5752
const partitionSpacesAndRooms = (arr: Room[]): [Room[], Room[]] => { // [spaces, rooms]
5853
return arr.reduce((result, room: Room) => {
@@ -86,15 +81,13 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
8681

8782
// The spaces representing the roots of the various tree-like hierarchies
8883
private rootSpaces: Room[] = [];
89-
// The list of rooms not present in any currently joined spaces
90-
private orphanedRooms = new Set<string>();
9184
// Map from room ID to set of spaces which list it as a child
9285
private parentMap = new EnhancedMap<string, Set<string>>();
93-
// Map from space key to SpaceNotificationState instance representing that space
94-
private notificationStateMap = new Map<SpaceKey, SpaceNotificationState>();
86+
// Map from spaceId to SpaceNotificationState instance representing that space
87+
private notificationStateMap = new Map<string, SpaceNotificationState>();
9588
// Map from space key to Set of room IDs that should be shown as part of that space's filter
96-
private spaceFilteredRooms = new Map<string | symbol, Set<string>>();
97-
// The space currently selected in the Space Panel - if null then `Home` is selected
89+
private spaceFilteredRooms = new Map<string, Set<string>>();
90+
// The space currently selected in the Space Panel - if null then All Rooms is selected
9891
private _activeSpace?: Room = null;
9992
private _suggestedRooms: ISpaceSummaryRoom[] = [];
10093
private _invitedSpaces = new Set<Room>();
@@ -244,7 +237,10 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
244237
}
245238

246239
public getSpaceFilteredRoomIds = (space: Room | null): Set<string> => {
247-
return this.spaceFilteredRooms.get(space?.roomId || HOME_SPACE) || new Set();
240+
if (!space) {
241+
return new Set(this.matrixClient.getVisibleRooms().map(r => r.roomId));
242+
}
243+
return this.spaceFilteredRooms.get(space.roomId) || new Set();
248244
};
249245

250246
private rebuild = throttle(() => {
@@ -275,7 +271,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
275271
});
276272
});
277273

278-
const [rootSpaces, orphanedRooms] = partitionSpacesAndRooms(Array.from(unseenChildren));
274+
const [rootSpaces] = partitionSpacesAndRooms(Array.from(unseenChildren));
279275

280276
// somewhat algorithm to handle full-cycles
281277
const detachedNodes = new Set<Room>(spaces);
@@ -316,7 +312,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
316312
// rootSpaces.push(space);
317313
// });
318314

319-
this.orphanedRooms = new Set(orphanedRooms);
320315
this.rootSpaces = rootSpaces;
321316
this.parentMap = backrefs;
322317

@@ -337,25 +332,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
337332
this.rebuild();
338333
}
339334

340-
private showInHomeSpace = (room: Room) => {
341-
if (room.isSpaceRoom()) return false;
342-
return !this.parentMap.get(room.roomId)?.size // put all orphaned rooms in the Home Space
343-
|| DMRoomMap.shared().getUserIdForRoomId(room.roomId) // put all DMs in the Home Space
344-
|| RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite) // show all favourites
345-
};
346-
347-
// Update a given room due to its tag changing (e.g DM-ness or Fav-ness)
348-
// This can only change whether it shows up in the HOME_SPACE or not
349-
private onRoomUpdate = (room: Room) => {
350-
if (this.showInHomeSpace(room)) {
351-
this.spaceFilteredRooms.get(HOME_SPACE)?.add(room.roomId);
352-
this.emit(HOME_SPACE);
353-
} else if (!this.orphanedRooms.has(room.roomId)) {
354-
this.spaceFilteredRooms.get(HOME_SPACE)?.delete(room.roomId);
355-
this.emit(HOME_SPACE);
356-
}
357-
};
358-
359335
private onSpaceMembersChange = (ev: MatrixEvent) => {
360336
// skip this update if we do not have a DM with this user
361337
if (DMRoomMap.shared().getDMRoomsForUserId(ev.getStateKey()).length < 1) return;
@@ -369,16 +345,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
369345
const oldFilteredRooms = this.spaceFilteredRooms;
370346
this.spaceFilteredRooms = new Map();
371347

372-
// put all room invites in the Home Space
373-
const invites = visibleRooms.filter(r => !r.isSpaceRoom() && r.getMyMembership() === "invite");
374-
this.spaceFilteredRooms.set(HOME_SPACE, new Set<string>(invites.map(room => room.roomId)));
375-
376-
visibleRooms.forEach(room => {
377-
if (this.showInHomeSpace(room)) {
378-
this.spaceFilteredRooms.get(HOME_SPACE).add(room.roomId);
379-
}
380-
});
381-
382348
this.rootSpaces.forEach(s => {
383349
// traverse each space tree in DFS to build up the supersets as you go up,
384350
// reusing results from like subtrees.
@@ -425,13 +391,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
425391
// Update NotificationStates
426392
this.getNotificationState(s)?.setRooms(visibleRooms.filter(room => {
427393
if (roomIds.has(room.roomId)) {
428-
// Don't aggregate notifications for DMs except in the Home Space
429-
if (s !== HOME_SPACE) {
430-
return !DMRoomMap.shared().getUserIdForRoomId(room.roomId)
431-
|| RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite);
432-
}
433-
434-
return true;
394+
return !DMRoomMap.shared().getUserIdForRoomId(room.roomId)
395+
|| RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite);
435396
}
436397

437398
return false;
@@ -513,8 +474,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
513474
// TODO confirm this after implementing parenting behaviour
514475
if (room.isSpaceRoom()) {
515476
this.onSpaceUpdate();
516-
} else {
517-
this.onRoomUpdate(room);
518477
}
519478
this.emit(room.roomId);
520479
break;
@@ -527,38 +486,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
527486
}
528487
};
529488

530-
private onRoomAccountData = (ev: MatrixEvent, room: Room, lastEvent?: MatrixEvent) => {
531-
if (ev.getType() === EventType.Tag && !room.isSpaceRoom()) {
532-
// If the room was in favourites and now isn't or the opposite then update its position in the trees
533-
const oldTags = lastEvent?.getContent()?.tags || {};
534-
const newTags = ev.getContent()?.tags || {};
535-
if (!!oldTags[DefaultTagID.Favourite] !== !!newTags[DefaultTagID.Favourite]) {
536-
this.onRoomUpdate(room);
537-
}
538-
}
539-
}
540-
541-
private onAccountData = (ev: MatrixEvent, lastEvent: MatrixEvent) => {
542-
if (ev.getType() === EventType.Direct) {
543-
const lastContent = lastEvent.getContent();
544-
const content = ev.getContent();
545-
546-
const diff = objectDiff<Record<string, string[]>>(lastContent, content);
547-
// filter out keys which changed by reference only by checking whether the sets differ
548-
const changed = diff.changed.filter(k => arrayHasDiff(lastContent[k], content[k]));
549-
// DM tag changes, refresh relevant rooms
550-
new Set([...diff.added, ...diff.removed, ...changed]).forEach(roomId => {
551-
const room = this.matrixClient?.getRoom(roomId);
552-
if (room) {
553-
this.onRoomUpdate(room);
554-
}
555-
});
556-
}
557-
};
558-
559489
protected async reset() {
560490
this.rootSpaces = [];
561-
this.orphanedRooms = new Set();
562491
this.parentMap = new EnhancedMap();
563492
this.notificationStateMap = new Map();
564493
this.spaceFilteredRooms = new Map();
@@ -573,8 +502,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
573502
this.matrixClient.removeListener("Room", this.onRoom);
574503
this.matrixClient.removeListener("Room.myMembership", this.onRoom);
575504
this.matrixClient.removeListener("RoomState.events", this.onRoomState);
576-
this.matrixClient.removeListener("Room.accountData", this.onRoomAccountData);
577-
this.matrixClient.removeListener("accountData", this.onAccountData);
578505
}
579506
await this.reset();
580507
}
@@ -584,8 +511,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
584511
this.matrixClient.on("Room", this.onRoom);
585512
this.matrixClient.on("Room.myMembership", this.onRoom);
586513
this.matrixClient.on("RoomState.events", this.onRoomState);
587-
this.matrixClient.on("Room.accountData", this.onRoomAccountData);
588-
this.matrixClient.on("accountData", this.onAccountData);
589514

590515
await this.onSpaceUpdate(); // trigger an initial update
591516

@@ -610,7 +535,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
610535
// Don't context switch when navigating to the space room
611536
// as it will cause you to end up in the wrong room
612537
this.setActiveSpace(room, false);
613-
} else if (!this.getSpaceFilteredRoomIds(this.activeSpace).has(roomId)) {
538+
} else if (this.activeSpace && !this.getSpaceFilteredRoomIds(this.activeSpace).has(roomId)) {
614539
this.switchToRelatedSpace(roomId);
615540
}
616541

@@ -628,7 +553,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
628553
}
629554
}
630555

631-
public getNotificationState(key: SpaceKey): SpaceNotificationState {
556+
public getNotificationState(key: string): SpaceNotificationState {
632557
if (this.notificationStateMap.has(key)) {
633558
return this.notificationStateMap.get(key);
634559
}

src/stores/room-list/RoomListStore.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
680680
promise = this.recalculatePrefiltering();
681681
} else {
682682
this.filterConditions.push(filter);
683-
// Runtime filters with spaces disable prefiltering for the search all spaces effect
683+
// Runtime filters with spaces disable prefiltering for the search all spaces feature
684684
if (SettingsStore.getValue("feature_spaces")) {
685685
// this has to be awaited so that `setKnownRooms` is called in time for the `addFilterCondition` below
686686
// this way the runtime filters are only evaluated on one dataset and not both.
@@ -712,10 +712,10 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
712712

713713
if (this.algorithm) {
714714
this.algorithm.removeFilterCondition(filter);
715-
// Runtime filters with spaces disable prefiltering for the search all spaces effect
716-
if (SettingsStore.getValue("feature_spaces")) {
717-
promise = this.recalculatePrefiltering();
718-
}
715+
}
716+
// Runtime filters with spaces disable prefiltering for the search all spaces feature
717+
if (SettingsStore.getValue("feature_spaces")) {
718+
promise = this.recalculatePrefiltering();
719719
}
720720
}
721721
idx = this.prefilterConditions.indexOf(filter);

src/stores/room-list/SpaceWatcher.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,34 @@ import SpaceStore, { UPDATE_SELECTED_SPACE } from "../SpaceStore";
2424
* Watches for changes in spaces to manage the filter on the provided RoomListStore
2525
*/
2626
export class SpaceWatcher {
27-
private filter = new SpaceFilterCondition();
27+
private filter: SpaceFilterCondition;
2828
private activeSpace: Room = SpaceStore.instance.activeSpace;
2929

3030
constructor(private store: RoomListStoreClass) {
31-
this.updateFilter(); // get the filter into a consistent state
32-
store.addFilter(this.filter);
3331
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdated);
3432
}
3533

36-
private onSelectedSpaceUpdated = (activeSpace: Room) => {
34+
private onSelectedSpaceUpdated = (activeSpace?: Room) => {
3735
this.activeSpace = activeSpace;
38-
this.updateFilter();
36+
37+
if (this.filter) {
38+
if (activeSpace) {
39+
this.updateFilter();
40+
} else {
41+
this.store.removeFilter(this.filter);
42+
this.filter = null;
43+
}
44+
} else if (activeSpace) {
45+
this.filter = new SpaceFilterCondition();
46+
this.updateFilter();
47+
this.store.addFilter(this.filter);
48+
}
3949
};
4050

4151
private updateFilter = () => {
42-
if (this.activeSpace) {
43-
SpaceStore.instance.traverseSpace(this.activeSpace.roomId, roomId => {
44-
this.store.matrixClient?.getRoom(roomId)?.loadMembersIfNeeded();
45-
});
46-
}
52+
SpaceStore.instance.traverseSpace(this.activeSpace.roomId, roomId => {
53+
this.store.matrixClient?.getRoom(roomId)?.loadMembersIfNeeded();
54+
});
4755
this.filter.updateSpace(this.activeSpace);
4856
};
4957
}

src/stores/room-list/filters/SpaceFilterCondition.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { Room } from "matrix-js-sdk/src/models/room";
1919

2020
import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./IFilterCondition";
2121
import { IDestroyable } from "../../../utils/IDestroyable";
22-
import SpaceStore, {HOME_SPACE} from "../../SpaceStore";
22+
import SpaceStore from "../../SpaceStore";
2323
import { setHasDiff } from "../../../utils/sets";
2424

2525
/**
@@ -55,10 +55,12 @@ export class SpaceFilterCondition extends EventEmitter implements IFilterConditi
5555
}
5656
};
5757

58-
private getSpaceEventKey = (space: Room | null) => space ? space.roomId : HOME_SPACE;
58+
private getSpaceEventKey = (space: Room) => space.roomId;
5959

6060
public updateSpace(space: Room) {
61-
SpaceStore.instance.off(this.getSpaceEventKey(this.space), this.onStoreUpdate);
61+
if (this.space) {
62+
SpaceStore.instance.off(this.getSpaceEventKey(this.space), this.onStoreUpdate);
63+
}
6264
SpaceStore.instance.on(this.getSpaceEventKey(this.space = space), this.onStoreUpdate);
6365
this.onStoreUpdate(); // initial update from the change to the space
6466
}

0 commit comments

Comments
 (0)