diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx
index 5e83fdc2a0..a37b7f0ac9 100644
--- a/src/HtmlUtils.tsx
+++ b/src/HtmlUtils.tsx
@@ -25,7 +25,6 @@ import _linkifyElement from 'linkifyjs/element';
import _linkifyString from 'linkifyjs/string';
import classNames from 'classnames';
import EMOJIBASE_REGEX from 'emojibase-regex';
-import url from 'url';
import katex from 'katex';
import { AllHtmlEntities } from 'html-entities';
import { IContent } from 'matrix-js-sdk/src/models/event';
@@ -153,10 +152,8 @@ export function getHtmlText(insaneHtml: string): string {
*/
export function isUrlPermitted(inputUrl: string): boolean {
try {
- const parsed = url.parse(inputUrl);
- if (!parsed.protocol) return false;
// URL parser protocol includes the trailing colon
- return PERMITTED_URL_SCHEMES.includes(parsed.protocol.slice(0, -1));
+ return PERMITTED_URL_SCHEMES.includes(new URL(inputUrl).protocol.slice(0, -1));
} catch (e) {
return false;
}
diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts
index 61ded93833..410124a637 100644
--- a/src/Lifecycle.ts
+++ b/src/Lifecycle.ts
@@ -21,6 +21,7 @@ import { createClient } from 'matrix-js-sdk/src/matrix';
import { InvalidStoreError } from "matrix-js-sdk/src/errors";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { decryptAES, encryptAES, IEncryptedPayload } from "matrix-js-sdk/src/crypto/aes";
+import { QueryDict } from 'matrix-js-sdk/src/utils';
import { IMatrixClientCreds, MatrixClientPeg } from './MatrixClientPeg';
import SecurityCustomisations from "./customisations/Security";
@@ -65,7 +66,7 @@ interface ILoadSessionOpts {
guestIsUrl?: string;
ignoreGuest?: boolean;
defaultDeviceDisplayName?: string;
- fragmentQueryParams?: Record;
+ fragmentQueryParams?: QueryDict;
}
/**
@@ -118,8 +119,8 @@ export async function loadSession(opts: ILoadSessionOpts = {}): Promise
) {
console.log("Using guest access credentials");
return doSetLoggedIn({
- userId: fragmentQueryParams.guest_user_id,
- accessToken: fragmentQueryParams.guest_access_token,
+ userId: fragmentQueryParams.guest_user_id as string,
+ accessToken: fragmentQueryParams.guest_access_token as string,
homeserverUrl: guestHsUrl,
identityServerUrl: guestIsUrl,
guest: true,
@@ -173,7 +174,7 @@ export async function getStoredSessionOwner(): Promise<[string, boolean]> {
* login, else false
*/
export function attemptTokenLogin(
- queryParams: Record,
+ queryParams: QueryDict,
defaultDeviceDisplayName?: string,
fragmentAfterLogin?: string,
): Promise {
@@ -198,7 +199,7 @@ export function attemptTokenLogin(
homeserver,
identityServer,
"m.login.token", {
- token: queryParams.loginToken,
+ token: queryParams.loginToken as string,
initial_device_display_name: defaultDeviceDisplayName,
},
).then(function(creds) {
diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx
index 15536f260d..785838ffca 100644
--- a/src/components/structures/MatrixChat.tsx
+++ b/src/components/structures/MatrixChat.tsx
@@ -19,7 +19,7 @@ import { createClient } from "matrix-js-sdk/src/matrix";
import { InvalidStoreError } from "matrix-js-sdk/src/errors";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
-import { sleep, defer, IDeferred } from "matrix-js-sdk/src/utils";
+import { sleep, defer, IDeferred, QueryDict } from "matrix-js-sdk/src/utils";
// focus-visible is a Polyfill for the :focus-visible CSS pseudo-attribute used by _AccessibleButton.scss
import 'focus-visible';
@@ -155,7 +155,7 @@ const ONBOARDING_FLOW_STARTERS = [
interface IScreen {
screen: string;
- params?: object;
+ params?: QueryDict;
}
/* eslint-disable camelcase */
@@ -185,9 +185,9 @@ interface IProps { // TODO type things better
onNewScreen: (screen: string, replaceLast: boolean) => void;
enableGuest?: boolean;
// the queryParams extracted from the [real] query-string of the URI
- realQueryParams?: Record;
+ realQueryParams?: QueryDict;
// the initial queryParams extracted from the hash-fragment of the URI
- startingFragmentQueryParams?: Record;
+ startingFragmentQueryParams?: QueryDict;
// called when we have completed a token login
onTokenLoginCompleted?: () => void;
// Represents the screen to display as a result of parsing the initial window.location
@@ -195,7 +195,7 @@ interface IProps { // TODO type things better
// displayname, if any, to set on the device when logging in/registering.
defaultDeviceDisplayName?: string;
// A function that makes a registration URL
- makeRegistrationUrl: (object) => string;
+ makeRegistrationUrl: (params: QueryDict) => string;
}
interface IState {
@@ -298,7 +298,7 @@ export default class MatrixChat extends React.PureComponent {
if (this.screenAfterLogin.screen.startsWith("room/") && params['signurl'] && params['email']) {
// probably a threepid invite - try to store it
const roomId = this.screenAfterLogin.screen.substring("room/".length);
- ThreepidInviteStore.instance.storeInvite(roomId, params as IThreepidInviteWireFormat);
+ ThreepidInviteStore.instance.storeInvite(roomId, params as unknown as IThreepidInviteWireFormat);
}
}
@@ -1952,7 +1952,7 @@ export default class MatrixChat extends React.PureComponent {
this.setState({ serverConfig });
};
- private makeRegistrationUrl = (params: {[key: string]: string}) => {
+ private makeRegistrationUrl = (params: QueryDict) => {
if (this.props.startingFragmentQueryParams.referrer) {
params.referrer = this.props.startingFragmentQueryParams.referrer;
}
@@ -2107,7 +2107,7 @@ export default class MatrixChat extends React.PureComponent {
onForgotPasswordClick={showPasswordReset ? this.onForgotPasswordClick : undefined}
onServerConfigChange={this.onServerConfigChange}
fragmentAfterLogin={fragmentAfterLogin}
- defaultUsername={this.props.startingFragmentQueryParams.defaultUsername}
+ defaultUsername={this.props.startingFragmentQueryParams.defaultUsername as string}
{...this.getServerProperties()}
/>
);
diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx
index fce9e297a1..8d825a2b53 100644
--- a/src/components/views/rooms/RoomSublist.tsx
+++ b/src/components/views/rooms/RoomSublist.tsx
@@ -408,10 +408,10 @@ export default class RoomSublist extends React.Component {
this.setState({ addRoomContextMenuPosition: null });
};
- private onUnreadFirstChanged = async () => {
+ private onUnreadFirstChanged = () => {
const isUnreadFirst = RoomListStore.instance.getListOrder(this.props.tagId) === ListAlgorithm.Importance;
const newAlgorithm = isUnreadFirst ? ListAlgorithm.Natural : ListAlgorithm.Importance;
- await RoomListStore.instance.setListOrder(this.props.tagId, newAlgorithm);
+ RoomListStore.instance.setListOrder(this.props.tagId, newAlgorithm);
this.forceUpdate(); // because if the sublist doesn't have any changes then we will miss the list order change
};
diff --git a/src/stores/room-list/RoomListStore.ts b/src/stores/room-list/RoomListStore.ts
index bedbfebd7f..3913a2220f 100644
--- a/src/stores/room-list/RoomListStore.ts
+++ b/src/stores/room-list/RoomListStore.ts
@@ -132,8 +132,8 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
// Update any settings here, as some may have happened before we were logically ready.
console.log("Regenerating room lists: Startup");
await this.readAndCacheSettingsFromStore();
- await this.regenerateAllLists({ trigger: false });
- await this.handleRVSUpdate({ trigger: false }); // fake an RVS update to adjust sticky room, if needed
+ this.regenerateAllLists({ trigger: false });
+ this.handleRVSUpdate({ trigger: false }); // fake an RVS update to adjust sticky room, if needed
this.updateFn.mark(); // we almost certainly want to trigger an update.
this.updateFn.trigger();
@@ -150,7 +150,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
await this.updateState({
tagsEnabled,
});
- await this.updateAlgorithmInstances();
+ this.updateAlgorithmInstances();
}
/**
@@ -158,23 +158,23 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
* @param trigger Set to false to prevent a list update from being sent. Should only
* be used if the calling code will manually trigger the update.
*/
- private async handleRVSUpdate({ trigger = true }) {
+ private handleRVSUpdate({ trigger = true }) {
if (!this.matrixClient) return; // We assume there won't be RVS updates without a client
const activeRoomId = RoomViewStore.getRoomId();
if (!activeRoomId && this.algorithm.stickyRoom) {
- await this.algorithm.setStickyRoom(null);
+ this.algorithm.setStickyRoom(null);
} else if (activeRoomId) {
const activeRoom = this.matrixClient.getRoom(activeRoomId);
if (!activeRoom) {
console.warn(`${activeRoomId} is current in RVS but missing from client - clearing sticky room`);
- await this.algorithm.setStickyRoom(null);
+ this.algorithm.setStickyRoom(null);
} else if (activeRoom !== this.algorithm.stickyRoom) {
if (SettingsStore.getValue("advancedRoomListLogging")) {
// TODO: Remove debug: https://github.com/vector-im/element-web/issues/14602
console.log(`Changing sticky room to ${activeRoomId}`);
}
- await this.algorithm.setStickyRoom(activeRoom);
+ this.algorithm.setStickyRoom(activeRoom);
}
}
@@ -226,7 +226,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
console.log("Regenerating room lists: Settings changed");
await this.readAndCacheSettingsFromStore();
- await this.regenerateAllLists({ trigger: false }); // regenerate the lists now
+ this.regenerateAllLists({ trigger: false }); // regenerate the lists now
this.updateFn.trigger();
}
}
@@ -368,7 +368,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
// TODO: Remove debug: https://github.com/vector-im/element-web/issues/14602
console.log(`[RoomListDebug] Clearing sticky room due to room upgrade`);
}
- await this.algorithm.setStickyRoom(null);
+ this.algorithm.setStickyRoom(null);
}
// Note: we hit the algorithm instead of our handleRoomUpdate() function to
@@ -377,7 +377,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
// TODO: Remove debug: https://github.com/vector-im/element-web/issues/14602
console.log(`[RoomListDebug] Removing previous room from room list`);
}
- await this.algorithm.handleRoomUpdate(prevRoom, RoomUpdateCause.RoomRemoved);
+ this.algorithm.handleRoomUpdate(prevRoom, RoomUpdateCause.RoomRemoved);
}
}
@@ -433,7 +433,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
return; // don't do anything on new/moved rooms which ought not to be shown
}
- const shouldUpdate = await this.algorithm.handleRoomUpdate(room, cause);
+ const shouldUpdate = this.algorithm.handleRoomUpdate(room, cause);
if (shouldUpdate) {
if (SettingsStore.getValue("advancedRoomListLogging")) {
// TODO: Remove debug: https://github.com/vector-im/element-web/issues/14602
@@ -462,13 +462,13 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
// Reset the sticky room before resetting the known rooms so the algorithm
// doesn't freak out.
- await this.algorithm.setStickyRoom(null);
- await this.algorithm.setKnownRooms(rooms);
+ this.algorithm.setStickyRoom(null);
+ this.algorithm.setKnownRooms(rooms);
// Set the sticky room back, if needed, now that we have updated the store.
// This will use relative stickyness to the new room set.
if (stickyIsStillPresent) {
- await this.algorithm.setStickyRoom(currentSticky);
+ this.algorithm.setStickyRoom(currentSticky);
}
// Finally, mark an update and resume updates from the algorithm
@@ -477,12 +477,12 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
}
public async setTagSorting(tagId: TagID, sort: SortAlgorithm) {
- await this.setAndPersistTagSorting(tagId, sort);
+ this.setAndPersistTagSorting(tagId, sort);
this.updateFn.trigger();
}
- private async setAndPersistTagSorting(tagId: TagID, sort: SortAlgorithm) {
- await this.algorithm.setTagSorting(tagId, sort);
+ private setAndPersistTagSorting(tagId: TagID, sort: SortAlgorithm) {
+ this.algorithm.setTagSorting(tagId, sort);
// TODO: Per-account? https://github.com/vector-im/element-web/issues/14114
localStorage.setItem(`mx_tagSort_${tagId}`, sort);
}
@@ -520,13 +520,13 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
return tagSort;
}
- public async setListOrder(tagId: TagID, order: ListAlgorithm) {
- await this.setAndPersistListOrder(tagId, order);
+ public setListOrder(tagId: TagID, order: ListAlgorithm) {
+ this.setAndPersistListOrder(tagId, order);
this.updateFn.trigger();
}
- private async setAndPersistListOrder(tagId: TagID, order: ListAlgorithm) {
- await this.algorithm.setListOrdering(tagId, order);
+ private setAndPersistListOrder(tagId: TagID, order: ListAlgorithm) {
+ this.algorithm.setListOrdering(tagId, order);
// TODO: Per-account? https://github.com/vector-im/element-web/issues/14114
localStorage.setItem(`mx_listOrder_${tagId}`, order);
}
@@ -563,7 +563,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
return listOrder;
}
- private async updateAlgorithmInstances() {
+ private updateAlgorithmInstances() {
// We'll require an update, so mark for one. Marking now also prevents the calls
// to setTagSorting and setListOrder from causing triggers.
this.updateFn.mark();
@@ -576,10 +576,10 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
const listOrder = this.calculateListOrder(tag);
if (tagSort !== definedSort) {
- await this.setAndPersistTagSorting(tag, tagSort);
+ this.setAndPersistTagSorting(tag, tagSort);
}
if (listOrder !== definedOrder) {
- await this.setAndPersistListOrder(tag, listOrder);
+ this.setAndPersistListOrder(tag, listOrder);
}
}
}
@@ -632,7 +632,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
* @param trigger Set to false to prevent a list update from being sent. Should only
* be used if the calling code will manually trigger the update.
*/
- public async regenerateAllLists({ trigger = true }) {
+ public regenerateAllLists({ trigger = true }) {
console.warn("Regenerating all room lists");
const rooms = this.getPlausibleRooms();
@@ -656,8 +656,8 @@ export class RoomListStoreClass extends AsyncStoreWithClient {
RoomListLayoutStore.instance.ensureLayoutExists(tagId);
}
- await this.algorithm.populateTags(sorts, orders);
- await this.algorithm.setKnownRooms(rooms);
+ this.algorithm.populateTags(sorts, orders);
+ this.algorithm.setKnownRooms(rooms);
this.initialListsGenerated = true;
diff --git a/src/stores/room-list/algorithms/Algorithm.ts b/src/stores/room-list/algorithms/Algorithm.ts
index f50d112248..8574f095d6 100644
--- a/src/stores/room-list/algorithms/Algorithm.ts
+++ b/src/stores/room-list/algorithms/Algorithm.ts
@@ -16,8 +16,9 @@ limitations under the License.
import { Room } from "matrix-js-sdk/src/models/room";
import { isNullOrUndefined } from "matrix-js-sdk/src/utils";
-import DMRoomMap from "../../../utils/DMRoomMap";
import { EventEmitter } from "events";
+
+import DMRoomMap from "../../../utils/DMRoomMap";
import { arrayDiff, arrayHasDiff } from "../../../utils/arrays";
import { DefaultTagID, RoomUpdateCause, TagID } from "../models";
import {
@@ -122,8 +123,8 @@ export class Algorithm extends EventEmitter {
* Awaitable version of the sticky room setter.
* @param val The new room to sticky.
*/
- public async setStickyRoom(val: Room) {
- await this.updateStickyRoom(val);
+ public setStickyRoom(val: Room) {
+ this.updateStickyRoom(val);
}
public getTagSorting(tagId: TagID): SortAlgorithm {
@@ -131,13 +132,13 @@ export class Algorithm extends EventEmitter {
return this.sortAlgorithms[tagId];
}
- public async setTagSorting(tagId: TagID, sort: SortAlgorithm) {
+ public setTagSorting(tagId: TagID, sort: SortAlgorithm) {
if (!tagId) throw new Error("Tag ID must be defined");
if (!sort) throw new Error("Algorithm must be defined");
this.sortAlgorithms[tagId] = sort;
const algorithm: OrderingAlgorithm = this.algorithms[tagId];
- await algorithm.setSortAlgorithm(sort);
+ 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
@@ -148,7 +149,7 @@ export class Algorithm extends EventEmitter {
return this.listAlgorithms[tagId];
}
- public async setListOrdering(tagId: TagID, order: ListAlgorithm) {
+ public setListOrdering(tagId: TagID, order: ListAlgorithm) {
if (!tagId) throw new Error("Tag ID must be defined");
if (!order) throw new Error("Algorithm must be defined");
this.listAlgorithms[tagId] = order;
@@ -156,7 +157,7 @@ export class Algorithm extends EventEmitter {
const algorithm = getListAlgorithmInstance(order, tagId, this.sortAlgorithms[tagId]);
this.algorithms[tagId] = algorithm;
- await algorithm.setRooms(this._cachedRooms[tagId]);
+ 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
@@ -183,31 +184,25 @@ export class Algorithm extends EventEmitter {
}
}
- private async handleFilterChange() {
- await this.recalculateFilteredRooms();
+ 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 async updateStickyRoom(val: Room) {
- try {
- return await this.doUpdateStickyRoom(val);
- } finally {
- this._lastStickyRoom = null; // clear to indicate we're done changing
- }
+ private updateStickyRoom(val: Room) {
+ this.doUpdateStickyRoom(val);
+ this._lastStickyRoom = null; // clear to indicate we're done changing
}
- private async doUpdateStickyRoom(val: Room) {
+ private doUpdateStickyRoom(val: Room) {
if (SpaceStore.spacesEnabled && val?.isSpaceRoom() && val.getMyMembership() !== "invite") {
// no-op sticky rooms for spaces - they're effectively virtual rooms
val = null;
}
- // Note throughout: We need async so we can wait for handleRoomUpdate() to do its thing,
- // otherwise we risk duplicating rooms.
-
if (val && !VisibilityProvider.instance.isRoomVisible(val)) {
val = null; // the room isn't visible - lie to the rest of this function
}
@@ -223,7 +218,7 @@ export class Algorithm extends EventEmitter {
this._stickyRoom = null; // clear before we go to update the algorithm
// Lie to the algorithm and re-add the room to the algorithm
- await this.handleRoomUpdate(stickyRoom, RoomUpdateCause.NewRoom);
+ this.handleRoomUpdate(stickyRoom, RoomUpdateCause.NewRoom);
return;
}
return;
@@ -269,10 +264,10 @@ export class Algorithm extends EventEmitter {
// referential checks as the references can differ through the lifecycle.
if (lastStickyRoom && lastStickyRoom.room && lastStickyRoom.room.roomId !== val.roomId) {
// Lie to the algorithm and re-add the room to the algorithm
- await this.handleRoomUpdate(lastStickyRoom.room, RoomUpdateCause.NewRoom);
+ this.handleRoomUpdate(lastStickyRoom.room, RoomUpdateCause.NewRoom);
}
// Lie to the algorithm and remove the room from it's field of view
- await this.handleRoomUpdate(val, RoomUpdateCause.RoomRemoved);
+ this.handleRoomUpdate(val, RoomUpdateCause.RoomRemoved);
// Check for tag & position changes while we're here. We also check the room to ensure
// it is still the same room.
@@ -462,9 +457,8 @@ export class Algorithm extends EventEmitter {
* them.
* @param {ITagSortingMap} tagSortingMap The tags to generate.
* @param {IListOrderingMap} listOrderingMap The ordering of those tags.
- * @returns {Promise<*>} A promise which resolves when complete.
*/
- public async populateTags(tagSortingMap: ITagSortingMap, listOrderingMap: IListOrderingMap): Promise {
+ public populateTags(tagSortingMap: ITagSortingMap, listOrderingMap: IListOrderingMap): void {
if (!tagSortingMap) throw new Error(`Sorting map cannot be null or empty`);
if (!listOrderingMap) throw new Error(`Ordering ma cannot be null or empty`);
if (arrayHasDiff(Object.keys(tagSortingMap), Object.keys(listOrderingMap))) {
@@ -513,9 +507,8 @@ export class Algorithm extends EventEmitter {
* Seeds the Algorithm with a set of rooms. The algorithm will discard all
* previously known information and instead use these rooms instead.
* @param {Room[]} rooms The rooms to force the algorithm to use.
- * @returns {Promise<*>} A promise which resolves when complete.
*/
- public async setKnownRooms(rooms: Room[]): Promise {
+ public setKnownRooms(rooms: Room[]): void {
if (isNullOrUndefined(rooms)) throw new Error(`Array of rooms cannot be null`);
if (!this.sortAlgorithms) throw new Error(`Cannot set known rooms without a tag sorting map`);
@@ -529,7 +522,7 @@ export class Algorithm extends EventEmitter {
// Before we go any further we need to clear (but remember) the sticky room to
// avoid accidentally duplicating it in the list.
const oldStickyRoom = this._stickyRoom;
- await this.updateStickyRoom(null);
+ if (oldStickyRoom) this.updateStickyRoom(null);
this.rooms = rooms;
@@ -541,7 +534,7 @@ export class Algorithm extends EventEmitter {
// If we can avoid doing work, do so.
if (!rooms.length) {
- await this.generateFreshTags(newTags); // just in case it wants to do something
+ this.generateFreshTags(newTags); // just in case it wants to do something
this.cachedRooms = newTags;
return;
}
@@ -578,7 +571,7 @@ export class Algorithm extends EventEmitter {
}
}
- await this.generateFreshTags(newTags);
+ this.generateFreshTags(newTags);
this.cachedRooms = newTags; // this recalculates the filtered rooms for us
this.updateTagsFromCache();
@@ -587,7 +580,7 @@ export class Algorithm extends EventEmitter {
// it was. It's entirely possible that it changed lists though, so if it did then
// we also have to update the position of it.
if (oldStickyRoom && oldStickyRoom.room) {
- await this.updateStickyRoom(oldStickyRoom.room);
+ this.updateStickyRoom(oldStickyRoom.room);
if (this._stickyRoom && this._stickyRoom.room) { // just in case the update doesn't go according to plan
if (this._stickyRoom.tag !== oldStickyRoom.tag) {
// We put the sticky room at the top of the list to treat it as an obvious tag change.
@@ -652,16 +645,15 @@ export class Algorithm extends EventEmitter {
* @param {ITagMap} updatedTagMap The tag map which needs populating. Each tag
* will already have the rooms which belong to it - they just need ordering. Must
* be mutated in place.
- * @returns {Promise<*>} A promise which resolves when complete.
*/
- private async generateFreshTags(updatedTagMap: ITagMap): Promise {
+ private generateFreshTags(updatedTagMap: ITagMap): void {
if (!this.algorithms) throw new Error("Not ready: no algorithms to determine tags from");
for (const tag of Object.keys(updatedTagMap)) {
const algorithm: OrderingAlgorithm = this.algorithms[tag];
if (!algorithm) throw new Error(`No algorithm for ${tag}`);
- await algorithm.setRooms(updatedTagMap[tag]);
+ algorithm.setRooms(updatedTagMap[tag]);
updatedTagMap[tag] = algorithm.orderedRooms;
}
}
@@ -673,11 +665,10 @@ export class Algorithm extends EventEmitter {
* may no-op this request if no changes are required.
* @param {Room} room The room which might have affected sorting.
* @param {RoomUpdateCause} cause The reason for the update being triggered.
- * @returns {Promise} A promise which resolve to true or false
- * depending on whether or not getOrderedRooms() should be called after
- * processing.
+ * @returns {Promise} A boolean of whether or not getOrderedRooms()
+ * should be called after processing.
*/
- public async handleRoomUpdate(room: Room, cause: RoomUpdateCause): Promise {
+ public handleRoomUpdate(room: Room, cause: RoomUpdateCause): boolean {
if (SettingsStore.getValue("advancedRoomListLogging")) {
// TODO: Remove debug: https://github.com/vector-im/element-web/issues/14602
console.log(`Handle room update for ${room.roomId} called with cause ${cause}`);
@@ -685,9 +676,9 @@ export class Algorithm extends EventEmitter {
if (!this.algorithms) throw new Error("Not ready: no algorithms to determine tags from");
// Note: check the isSticky against the room ID just in case the reference is wrong
- const isSticky = this._stickyRoom && this._stickyRoom.room && this._stickyRoom.room.roomId === room.roomId;
+ const isSticky = this._stickyRoom?.room?.roomId === room.roomId;
if (cause === RoomUpdateCause.NewRoom) {
- const isForLastSticky = this._lastStickyRoom && this._lastStickyRoom.room === room;
+ const isForLastSticky = this._lastStickyRoom?.room === room;
const roomTags = this.roomIdsToTags[room.roomId];
const hasTags = roomTags && roomTags.length > 0;
@@ -744,7 +735,7 @@ export class Algorithm extends EventEmitter {
}
const algorithm: OrderingAlgorithm = this.algorithms[rmTag];
if (!algorithm) throw new Error(`No algorithm for ${rmTag}`);
- await algorithm.handleRoomUpdate(room, RoomUpdateCause.RoomRemoved);
+ 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
@@ -756,7 +747,7 @@ export class Algorithm extends EventEmitter {
}
const algorithm: OrderingAlgorithm = this.algorithms[addTag];
if (!algorithm) throw new Error(`No algorithm for ${addTag}`);
- await algorithm.handleRoomUpdate(room, RoomUpdateCause.NewRoom);
+ algorithm.handleRoomUpdate(room, RoomUpdateCause.NewRoom);
this._cachedRooms[addTag] = algorithm.orderedRooms;
}
@@ -789,7 +780,7 @@ export class Algorithm extends EventEmitter {
};
} else {
// We have to clear the lock as the sticky room change will trigger updates.
- await this.setStickyRoom(room);
+ this.setStickyRoom(room);
}
}
}
@@ -852,7 +843,7 @@ export class Algorithm extends EventEmitter {
const algorithm: OrderingAlgorithm = this.algorithms[tag];
if (!algorithm) throw new Error(`No algorithm for ${tag}`);
- await algorithm.handleRoomUpdate(room, cause);
+ algorithm.handleRoomUpdate(room, cause);
this._cachedRooms[tag] = algorithm.orderedRooms;
// Flag that we've done something
diff --git a/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts b/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts
index 80bdf74afb..1d35df331d 100644
--- a/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts
+++ b/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts
@@ -94,15 +94,15 @@ export class ImportanceAlgorithm extends OrderingAlgorithm {
return state.color;
}
- public async setRooms(rooms: Room[]): Promise {
+ public setRooms(rooms: Room[]): void {
if (this.sortingAlgorithm === SortAlgorithm.Manual) {
- this.cachedOrderedRooms = await sortRoomsWithAlgorithm(rooms, this.tagId, this.sortingAlgorithm);
+ this.cachedOrderedRooms = sortRoomsWithAlgorithm(rooms, this.tagId, this.sortingAlgorithm);
} else {
// Every other sorting type affects the categories, not the whole tag.
const categorized = this.categorizeRooms(rooms);
for (const category of Object.keys(categorized)) {
const roomsToOrder = categorized[category];
- categorized[category] = await sortRoomsWithAlgorithm(roomsToOrder, this.tagId, this.sortingAlgorithm);
+ categorized[category] = sortRoomsWithAlgorithm(roomsToOrder, this.tagId, this.sortingAlgorithm);
}
const newlyOrganized: Room[] = [];
@@ -118,12 +118,12 @@ export class ImportanceAlgorithm extends OrderingAlgorithm {
}
}
- private async handleSplice(room: Room, cause: RoomUpdateCause): Promise {
+ private handleSplice(room: Room, cause: RoomUpdateCause): boolean {
if (cause === RoomUpdateCause.NewRoom) {
const category = this.getRoomCategory(room);
this.alterCategoryPositionBy(category, 1, this.indices);
this.cachedOrderedRooms.splice(this.indices[category], 0, room); // splice in the new room (pre-adjusted)
- await this.sortCategory(category);
+ this.sortCategory(category);
} else if (cause === RoomUpdateCause.RoomRemoved) {
const roomIdx = this.getRoomIndex(room);
if (roomIdx === -1) {
@@ -141,55 +141,49 @@ export class ImportanceAlgorithm extends OrderingAlgorithm {
return true;
}
- public async handleRoomUpdate(room: Room, cause: RoomUpdateCause): Promise {
- try {
- await this.updateLock.acquireAsync();
-
- if (cause === RoomUpdateCause.NewRoom || cause === RoomUpdateCause.RoomRemoved) {
- return this.handleSplice(room, cause);
- }
-
- if (cause !== RoomUpdateCause.Timeline && cause !== RoomUpdateCause.ReadReceipt) {
- throw new Error(`Unsupported update cause: ${cause}`);
- }
-
- const category = this.getRoomCategory(room);
- if (this.sortingAlgorithm === SortAlgorithm.Manual) {
- return; // Nothing to do here.
- }
-
- const roomIdx = this.getRoomIndex(room);
- if (roomIdx === -1) {
- throw new Error(`Room ${room.roomId} has no index in ${this.tagId}`);
- }
-
- // Try to avoid doing array operations if we don't have to: only move rooms within
- // the categories if we're jumping categories
- const oldCategory = this.getCategoryFromIndices(roomIdx, this.indices);
- if (oldCategory !== category) {
- // Move the room and update the indices
- this.moveRoomIndexes(1, oldCategory, category, this.indices);
- this.cachedOrderedRooms.splice(roomIdx, 1); // splice out the old index (fixed position)
- this.cachedOrderedRooms.splice(this.indices[category], 0, room); // splice in the new room (pre-adjusted)
- // Note: if moveRoomIndexes() is called after the splice then the insert operation
- // will happen in the wrong place. Because we would have already adjusted the index
- // for the category, we don't need to determine how the room is moving in the list.
- // If we instead tried to insert before updating the indices, we'd have to determine
- // whether the room was moving later (towards IDLE) or earlier (towards RED) from its
- // current position, as it'll affect the category's start index after we remove the
- // room from the array.
- }
-
- // Sort the category now that we've dumped the room in
- await this.sortCategory(category);
-
- return true; // change made
- } finally {
- await this.updateLock.release();
+ public handleRoomUpdate(room: Room, cause: RoomUpdateCause): boolean {
+ if (cause === RoomUpdateCause.NewRoom || cause === RoomUpdateCause.RoomRemoved) {
+ return this.handleSplice(room, cause);
}
+
+ if (cause !== RoomUpdateCause.Timeline && cause !== RoomUpdateCause.ReadReceipt) {
+ throw new Error(`Unsupported update cause: ${cause}`);
+ }
+
+ const category = this.getRoomCategory(room);
+ if (this.sortingAlgorithm === SortAlgorithm.Manual) {
+ return; // Nothing to do here.
+ }
+
+ const roomIdx = this.getRoomIndex(room);
+ if (roomIdx === -1) {
+ throw new Error(`Room ${room.roomId} has no index in ${this.tagId}`);
+ }
+
+ // Try to avoid doing array operations if we don't have to: only move rooms within
+ // the categories if we're jumping categories
+ const oldCategory = this.getCategoryFromIndices(roomIdx, this.indices);
+ if (oldCategory !== category) {
+ // Move the room and update the indices
+ this.moveRoomIndexes(1, oldCategory, category, this.indices);
+ this.cachedOrderedRooms.splice(roomIdx, 1); // splice out the old index (fixed position)
+ this.cachedOrderedRooms.splice(this.indices[category], 0, room); // splice in the new room (pre-adjusted)
+ // Note: if moveRoomIndexes() is called after the splice then the insert operation
+ // will happen in the wrong place. Because we would have already adjusted the index
+ // for the category, we don't need to determine how the room is moving in the list.
+ // If we instead tried to insert before updating the indices, we'd have to determine
+ // whether the room was moving later (towards IDLE) or earlier (towards RED) from its
+ // current position, as it'll affect the category's start index after we remove the
+ // room from the array.
+ }
+
+ // Sort the category now that we've dumped the room in
+ this.sortCategory(category);
+
+ return true; // change made
}
- private async sortCategory(category: NotificationColor) {
+ private sortCategory(category: NotificationColor) {
// This should be relatively quick because the room is usually inserted at the top of the
// category, and most popular sorting algorithms will deal with trying to keep the active
// room at the top/start of the category. For the few algorithms that will have to move the
@@ -201,7 +195,7 @@ export class ImportanceAlgorithm extends OrderingAlgorithm {
const startIdx = this.indices[category];
const numSort = nextCategoryStartIdx - startIdx; // splice() returns up to the max, so MAX_SAFE_INT is fine
const unsortedSlice = this.cachedOrderedRooms.splice(startIdx, numSort);
- const sorted = await sortRoomsWithAlgorithm(unsortedSlice, this.tagId, this.sortingAlgorithm);
+ const sorted = sortRoomsWithAlgorithm(unsortedSlice, this.tagId, this.sortingAlgorithm);
this.cachedOrderedRooms.splice(startIdx, 0, ...sorted);
}
diff --git a/src/stores/room-list/algorithms/list-ordering/NaturalAlgorithm.ts b/src/stores/room-list/algorithms/list-ordering/NaturalAlgorithm.ts
index cc2a28d892..91182dee16 100644
--- a/src/stores/room-list/algorithms/list-ordering/NaturalAlgorithm.ts
+++ b/src/stores/room-list/algorithms/list-ordering/NaturalAlgorithm.ts
@@ -29,42 +29,32 @@ export class NaturalAlgorithm extends OrderingAlgorithm {
super(tagId, initialSortingAlgorithm);
}
- public async setRooms(rooms: Room[]): Promise {
- this.cachedOrderedRooms = await sortRoomsWithAlgorithm(rooms, this.tagId, this.sortingAlgorithm);
+ public setRooms(rooms: Room[]): void {
+ this.cachedOrderedRooms = sortRoomsWithAlgorithm(rooms, this.tagId, this.sortingAlgorithm);
}
- public async handleRoomUpdate(room, cause): Promise {
- try {
- await this.updateLock.acquireAsync();
-
- const isSplice = cause === RoomUpdateCause.NewRoom || cause === RoomUpdateCause.RoomRemoved;
- const isInPlace = cause === RoomUpdateCause.Timeline || cause === RoomUpdateCause.ReadReceipt;
- if (!isSplice && !isInPlace) {
- throw new Error(`Unsupported update cause: ${cause}`);
- }
-
- if (cause === RoomUpdateCause.NewRoom) {
- this.cachedOrderedRooms.push(room);
- } else if (cause === RoomUpdateCause.RoomRemoved) {
- const idx = this.getRoomIndex(room);
- if (idx >= 0) {
- this.cachedOrderedRooms.splice(idx, 1);
- } else {
- console.warn(`Tried to remove unknown room from ${this.tagId}: ${room.roomId}`);
- }
- }
-
- // TODO: Optimize this to avoid useless operations: https://github.com/vector-im/element-web/issues/14457
- // For example, we can skip updates to alphabetic (sometimes) and manually ordered tags
- this.cachedOrderedRooms = await sortRoomsWithAlgorithm(
- this.cachedOrderedRooms,
- this.tagId,
- this.sortingAlgorithm,
- );
-
- return true;
- } finally {
- await this.updateLock.release();
+ public handleRoomUpdate(room, cause): boolean {
+ const isSplice = cause === RoomUpdateCause.NewRoom || cause === RoomUpdateCause.RoomRemoved;
+ const isInPlace = cause === RoomUpdateCause.Timeline || cause === RoomUpdateCause.ReadReceipt;
+ if (!isSplice && !isInPlace) {
+ throw new Error(`Unsupported update cause: ${cause}`);
}
+
+ if (cause === RoomUpdateCause.NewRoom) {
+ this.cachedOrderedRooms.push(room);
+ } else if (cause === RoomUpdateCause.RoomRemoved) {
+ const idx = this.getRoomIndex(room);
+ if (idx >= 0) {
+ this.cachedOrderedRooms.splice(idx, 1);
+ } else {
+ console.warn(`Tried to remove unknown room from ${this.tagId}: ${room.roomId}`);
+ }
+ }
+
+ // TODO: Optimize this to avoid useless operations: https://github.com/vector-im/element-web/issues/14457
+ // For example, we can skip updates to alphabetic (sometimes) and manually ordered tags
+ this.cachedOrderedRooms = sortRoomsWithAlgorithm(this.cachedOrderedRooms, this.tagId, this.sortingAlgorithm);
+
+ return true;
}
}
diff --git a/src/stores/room-list/algorithms/list-ordering/OrderingAlgorithm.ts b/src/stores/room-list/algorithms/list-ordering/OrderingAlgorithm.ts
index c47a35523c..9d7b5f9ddb 100644
--- a/src/stores/room-list/algorithms/list-ordering/OrderingAlgorithm.ts
+++ b/src/stores/room-list/algorithms/list-ordering/OrderingAlgorithm.ts
@@ -17,7 +17,6 @@ limitations under the License.
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomUpdateCause, TagID } from "../../models";
import { SortAlgorithm } from "../models";
-import AwaitLock from "await-lock";
/**
* Represents a list ordering algorithm. Subclasses should populate the
@@ -26,7 +25,6 @@ import AwaitLock from "await-lock";
export abstract class OrderingAlgorithm {
protected cachedOrderedRooms: Room[];
protected sortingAlgorithm: SortAlgorithm;
- protected readonly updateLock = new AwaitLock();
protected constructor(protected tagId: TagID, initialSortingAlgorithm: SortAlgorithm) {
// noinspection JSIgnoredPromiseFromCall
@@ -45,21 +43,20 @@ export abstract class OrderingAlgorithm {
* @param newAlgorithm The new algorithm. Must be defined.
* @returns Resolves when complete.
*/
- public async setSortAlgorithm(newAlgorithm: SortAlgorithm) {
+ public setSortAlgorithm(newAlgorithm: SortAlgorithm) {
if (!newAlgorithm) throw new Error("A sorting algorithm must be defined");
this.sortingAlgorithm = newAlgorithm;
// Force regeneration of the rooms
- await this.setRooms(this.orderedRooms);
+ this.setRooms(this.orderedRooms);
}
/**
* Sets the rooms the algorithm should be handling, implying a reconstruction
* of the ordering.
* @param rooms The rooms to use going forward.
- * @returns Resolves when complete.
*/
- public abstract setRooms(rooms: Room[]): Promise;
+ public abstract setRooms(rooms: Room[]): void;
/**
* Handle a room update. The Algorithm will only call this for causes which
@@ -69,7 +66,7 @@ export abstract class OrderingAlgorithm {
* @param cause The cause of the update.
* @returns True if the update requires the Algorithm to update the presentation layers.
*/
- public abstract handleRoomUpdate(room: Room, cause: RoomUpdateCause): Promise;
+ public abstract handleRoomUpdate(room: Room, cause: RoomUpdateCause): boolean;
protected getRoomIndex(room: Room): number {
let roomIdx = this.cachedOrderedRooms.indexOf(room);
diff --git a/src/stores/room-list/algorithms/tag-sorting/AlphabeticAlgorithm.ts b/src/stores/room-list/algorithms/tag-sorting/AlphabeticAlgorithm.ts
index b016a4256c..45f6eaf843 100644
--- a/src/stores/room-list/algorithms/tag-sorting/AlphabeticAlgorithm.ts
+++ b/src/stores/room-list/algorithms/tag-sorting/AlphabeticAlgorithm.ts
@@ -23,7 +23,7 @@ import { compare } from "../../../../utils/strings";
* Sorts rooms according to the browser's determination of alphabetic.
*/
export class AlphabeticAlgorithm implements IAlgorithm {
- public async sortRooms(rooms: Room[], tagId: TagID): Promise {
+ public sortRooms(rooms: Room[], tagId: TagID): Room[] {
return rooms.sort((a, b) => {
return compare(a.name, b.name);
});
diff --git a/src/stores/room-list/algorithms/tag-sorting/IAlgorithm.ts b/src/stores/room-list/algorithms/tag-sorting/IAlgorithm.ts
index 6c22ee0c9c..588bbbffc9 100644
--- a/src/stores/room-list/algorithms/tag-sorting/IAlgorithm.ts
+++ b/src/stores/room-list/algorithms/tag-sorting/IAlgorithm.ts
@@ -25,7 +25,7 @@ export interface IAlgorithm {
* Sorts the given rooms according to the sorting rules of the algorithm.
* @param {Room[]} rooms The rooms to sort.
* @param {TagID} tagId The tag ID in which the rooms are being sorted.
- * @returns {Promise} Resolves to the sorted rooms.
+ * @returns {Room[]} Returns the sorted rooms.
*/
- sortRooms(rooms: Room[], tagId: TagID): Promise;
+ sortRooms(rooms: Room[], tagId: TagID): Room[];
}
diff --git a/src/stores/room-list/algorithms/tag-sorting/ManualAlgorithm.ts b/src/stores/room-list/algorithms/tag-sorting/ManualAlgorithm.ts
index b8c0357633..9be8ba5262 100644
--- a/src/stores/room-list/algorithms/tag-sorting/ManualAlgorithm.ts
+++ b/src/stores/room-list/algorithms/tag-sorting/ManualAlgorithm.ts
@@ -22,7 +22,7 @@ import { IAlgorithm } from "./IAlgorithm";
* Sorts rooms according to the tag's `order` property on the room.
*/
export class ManualAlgorithm implements IAlgorithm {
- public async sortRooms(rooms: Room[], tagId: TagID): Promise {
+ public sortRooms(rooms: Room[], tagId: TagID): Room[] {
const getOrderProp = (r: Room) => r.tags[tagId].order || 0;
return rooms.sort((a, b) => {
return getOrderProp(a) - getOrderProp(b);
diff --git a/src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm.ts b/src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm.ts
index 49cfd9e520..f47458d1b1 100644
--- a/src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm.ts
+++ b/src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm.ts
@@ -97,7 +97,7 @@ export const sortRooms = (rooms: Room[]): Room[] => {
* useful to the user.
*/
export class RecentAlgorithm implements IAlgorithm {
- public async sortRooms(rooms: Room[], tagId: TagID): Promise {
+ public sortRooms(rooms: Room[], tagId: TagID): Room[] {
return sortRooms(rooms);
}
}
diff --git a/src/stores/room-list/algorithms/tag-sorting/index.ts b/src/stores/room-list/algorithms/tag-sorting/index.ts
index c22865f5ba..368c76f111 100644
--- a/src/stores/room-list/algorithms/tag-sorting/index.ts
+++ b/src/stores/room-list/algorithms/tag-sorting/index.ts
@@ -46,8 +46,8 @@ export function getSortingAlgorithmInstance(algorithm: SortAlgorithm): IAlgorith
* @param {Room[]} rooms The rooms to sort.
* @param {TagID} tagId The tag in which the sorting is occurring.
* @param {SortAlgorithm} algorithm The algorithm to use for sorting.
- * @returns {Promise} Resolves to the sorted rooms.
+ * @returns {Room[]} Returns the sorted rooms.
*/
-export function sortRoomsWithAlgorithm(rooms: Room[], tagId: TagID, algorithm: SortAlgorithm): Promise {
+export function sortRoomsWithAlgorithm(rooms: Room[], tagId: TagID, algorithm: SortAlgorithm): Room[] {
return getSortingAlgorithmInstance(algorithm).sortRooms(rooms, tagId);
}
diff --git a/src/utils/HostingLink.js b/src/utils/HostingLink.js
index ff7b0c221c..134e045ca2 100644
--- a/src/utils/HostingLink.js
+++ b/src/utils/HostingLink.js
@@ -14,9 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import url from 'url';
-import qs from 'qs';
-
import SdkConfig from '../SdkConfig';
import { MatrixClientPeg } from '../MatrixClientPeg';
@@ -28,11 +25,8 @@ export function getHostingLink(campaign) {
if (MatrixClientPeg.get().getDomain() !== 'matrix.org') return null;
try {
- const hostingUrl = url.parse(hostingLink);
- const params = qs.parse(hostingUrl.query);
- params.utm_campaign = campaign;
- hostingUrl.search = undefined;
- hostingUrl.query = params;
+ const hostingUrl = new URL(hostingLink);
+ hostingUrl.searchParams.set("utm_campaign", campaign);
return hostingUrl.format();
} catch (e) {
return hostingLink;