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

Commit 5d6143a

Browse files
author
Germain
authored
Extract view/join room logic to room helper (#8329)
1 parent d5e911d commit 5d6143a

File tree

6 files changed

+225
-121
lines changed

6 files changed

+225
-121
lines changed

src/components/structures/RoomDirectory.tsx

Lines changed: 32 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ limitations under the License.
1616
*/
1717

1818
import React from "react";
19-
import { IFieldType, IInstance, IProtocol, IPublicRoomsChunkRoom } from "matrix-js-sdk/src/client";
19+
import { IFieldType, IPublicRoomsChunkRoom } from "matrix-js-sdk/src/client";
2020
import { Visibility } from "matrix-js-sdk/src/@types/partials";
2121
import { IRoomDirectoryOptions } from "matrix-js-sdk/src/@types/requests";
2222
import { logger } from "matrix-js-sdk/src/logger";
@@ -28,7 +28,7 @@ import { _t } from '../../languageHandler';
2828
import SdkConfig from '../../SdkConfig';
2929
import { instanceForInstanceId, protocolNameForInstanceId } from '../../utils/DirectoryUtils';
3030
import Analytics from '../../Analytics';
31-
import NetworkDropdown, { ALL_ROOMS, Protocols } from "../views/directory/NetworkDropdown";
31+
import NetworkDropdown from "../views/directory/NetworkDropdown";
3232
import SettingsStore from "../../settings/SettingsStore";
3333
import { IDialogProps } from "../views/dialogs/IDialogProps";
3434
import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton";
@@ -39,10 +39,11 @@ import DirectorySearchBox from "../views/elements/DirectorySearchBox";
3939
import ScrollPanel from "./ScrollPanel";
4040
import Spinner from "../views/elements/Spinner";
4141
import { getDisplayAliasForAliasSet } from "../../Rooms";
42-
import { Action } from "../../dispatcher/actions";
4342
import PosthogTrackers from "../../PosthogTrackers";
44-
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
4543
import { PublicRoomTile } from "../views/rooms/PublicRoomTile";
44+
import { getFieldsForThirdPartyLocation, joinRoomByAlias, showRoom } from "../../utils/rooms";
45+
import { GenericError } from "../../utils/error";
46+
import { ALL_ROOMS, Protocols } from "../../utils/DirectoryUtils";
4647

4748
const LAST_SERVER_KEY = "mx_last_room_directory_server";
4849
const LAST_INSTANCE_KEY = "mx_last_room_directory_instance";
@@ -350,44 +351,23 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
350351
};
351352

352353
private onJoinFromSearchClick = (alias: string) => {
353-
// If we don't have a particular instance id selected, just show that rooms alias
354-
if (!this.state.instanceId || this.state.instanceId === ALL_ROOMS) {
355-
// If the user specified an alias without a domain, add on whichever server is selected
356-
// in the dropdown
357-
if (alias.indexOf(':') == -1) {
358-
alias = alias + ':' + this.state.roomServer;
359-
}
360-
this.showRoomAlias(alias, true);
361-
} else {
362-
// This is a 3rd party protocol. Let's see if we can join it
363-
const protocolName = protocolNameForInstanceId(this.protocols, this.state.instanceId);
364-
const instance = instanceForInstanceId(this.protocols, this.state.instanceId);
365-
const fields = protocolName
366-
? this.getFieldsForThirdPartyLocation(alias, this.protocols[protocolName], instance)
367-
: null;
368-
if (!fields) {
369-
const brand = SdkConfig.get().brand;
370-
Modal.createTrackedDialog('Unable to join network', '', ErrorDialog, {
371-
title: _t('Unable to join network'),
372-
description: _t('%(brand)s does not know how to join a room on this network', { brand }),
354+
const cli = MatrixClientPeg.get();
355+
try {
356+
joinRoomByAlias(cli, alias, {
357+
instanceId: this.state.instanceId,
358+
roomServer: this.state.roomServer,
359+
protocols: this.protocols,
360+
metricsTrigger: "RoomDirectory",
361+
});
362+
} catch (e) {
363+
if (e instanceof GenericError) {
364+
Modal.createTrackedDialog(e.message, '', ErrorDialog, {
365+
title: e.message,
366+
description: e.description,
373367
});
374-
return;
368+
} else {
369+
throw e;
375370
}
376-
MatrixClientPeg.get().getThirdpartyLocation(protocolName, fields).then((resp) => {
377-
if (resp.length > 0 && resp[0].alias) {
378-
this.showRoomAlias(resp[0].alias, true);
379-
} else {
380-
Modal.createTrackedDialog('Room not found', '', ErrorDialog, {
381-
title: _t('Room not found'),
382-
description: _t('Couldn\'t find a matching Matrix room'),
383-
});
384-
}
385-
}, (e) => {
386-
Modal.createTrackedDialog('Fetching third party location failed', '', ErrorDialog, {
387-
title: _t('Fetching third party location failed'),
388-
description: _t('Unable to look up room ID from server'),
389-
});
390-
});
391371
}
392372
};
393373

@@ -401,55 +381,18 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
401381
PosthogTrackers.trackInteraction("WebRoomDirectoryCreateRoomButton", ev);
402382
};
403383

404-
private showRoomAlias(alias: string, autoJoin = false) {
405-
this.showRoom(null, alias, autoJoin);
406-
}
407-
408-
private showRoom = (room: IPublicRoomsChunkRoom, roomAlias?: string, autoJoin = false, shouldPeek = false) => {
384+
private onRoomClick = (room: IPublicRoomsChunkRoom, roomAlias?: string, autoJoin = false, shouldPeek = false) => {
409385
this.onFinished();
410-
const payload: ViewRoomPayload = {
411-
action: Action.ViewRoom,
412-
auto_join: autoJoin,
413-
should_peek: shouldPeek,
386+
const cli = MatrixClientPeg.get();
387+
showRoom(cli, room, {
388+
roomAlias,
389+
autoJoin,
390+
shouldPeek,
391+
roomServer: this.state.roomServer,
414392
metricsTrigger: "RoomDirectory",
415-
};
416-
if (room) {
417-
// Don't let the user view a room they won't be able to either
418-
// peek or join: fail earlier so they don't have to click back
419-
// to the directory.
420-
if (MatrixClientPeg.get().isGuest()) {
421-
if (!room.world_readable && !room.guest_can_join) {
422-
dis.dispatch({ action: 'require_registration' });
423-
return;
424-
}
425-
}
426-
427-
if (!roomAlias) {
428-
roomAlias = getDisplayAliasForRoom(room);
429-
}
430-
431-
payload.oob_data = {
432-
avatarUrl: room.avatar_url,
433-
// XXX: This logic is duplicated from the JS SDK which
434-
// would normally decide what the name is.
435-
name: room.name || roomAlias || _t('Unnamed room'),
436-
};
437-
438-
if (this.state.roomServer) {
439-
payload.via_servers = [this.state.roomServer];
440-
}
441-
}
442-
// It's not really possible to join Matrix rooms by ID because the HS has no way to know
443-
// which servers to start querying. However, there's no other way to join rooms in
444-
// this list without aliases at present, so if roomAlias isn't set here we have no
445-
// choice but to supply the ID.
446-
if (roomAlias) {
447-
payload.room_alias = roomAlias;
448-
} else {
449-
payload.room_id = room.room_id;
450-
}
451-
dis.dispatch(payload);
393+
});
452394
};
395+
453396
private stringLooksLikeId(s: string, fieldType: IFieldType) {
454397
let pat = /^#[^\s]+:[^\s]/;
455398
if (fieldType && fieldType.regexp) {
@@ -459,27 +402,11 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
459402
return pat.test(s);
460403
}
461404

462-
private getFieldsForThirdPartyLocation(userInput: string, protocol: IProtocol, instance: IInstance) {
463-
// make an object with the fields specified by that protocol. We
464-
// require that the values of all but the last field come from the
465-
// instance. The last is the user input.
466-
const requiredFields = protocol.location_fields;
467-
if (!requiredFields) return null;
468-
const fields = {};
469-
for (let i = 0; i < requiredFields.length - 1; ++i) {
470-
const thisField = requiredFields[i];
471-
if (instance.fields[thisField] === undefined) return null;
472-
fields[thisField] = instance.fields[thisField];
473-
}
474-
fields[requiredFields[requiredFields.length - 1]] = userInput;
475-
return fields;
476-
}
477-
478405
private onFinished = () => {
479406
this.props.onFinished(false);
480407
};
481408

482-
render() {
409+
public render() {
483410
let content;
484411
if (this.state.error) {
485412
content = this.state.error;
@@ -491,7 +418,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
491418
<PublicRoomTile
492419
key={room.room_id}
493420
room={room}
494-
showRoom={this.showRoom}
421+
showRoom={this.onRoomClick}
495422
removeFromDirectory={this.removeFromDirectory}
496423
/>,
497424
);
@@ -571,7 +498,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
571498
let showJoinButton = this.stringLooksLikeId(this.state.filterString, instanceExpectedFieldType);
572499
if (protocolName) {
573500
const instance = instanceForInstanceId(this.protocols, this.state.instanceId);
574-
if (this.getFieldsForThirdPartyLocation(
501+
if (getFieldsForThirdPartyLocation(
575502
this.state.filterString,
576503
this.protocols[protocolName],
577504
instance,

src/components/views/directory/NetworkDropdown.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ limitations under the License.
1717

1818
import React, { useEffect, useState } from "react";
1919
import { MatrixError } from "matrix-js-sdk/src/http-api";
20-
import { IProtocol } from "matrix-js-sdk/src/client";
2120

2221
import { MatrixClientPeg } from '../../../MatrixClientPeg';
2322
import { instanceForInstanceId } from '../../../utils/DirectoryUtils';
@@ -42,9 +41,7 @@ import UIStore from "../../../stores/UIStore";
4241
import { compare } from "../../../utils/strings";
4342
import { SnakedObject } from "../../../utils/SnakedObject";
4443
import { IConfigOptions } from "../../../IConfigOptions";
45-
46-
// XXX: We would ideally use a symbol here but we can't since we save this value to localStorage
47-
export const ALL_ROOMS = "ALL_ROOMS";
44+
import { ALL_ROOMS, Protocols } from "../../../utils/DirectoryUtils";
4845

4946
const SETTING_NAME = "room_directory_servers";
5047

@@ -85,8 +82,6 @@ const validServer = withValidation<undefined, { error?: MatrixError }>({
8582
],
8683
});
8784

88-
export type Protocols = Record<string, IProtocol>;
89-
9085
interface IProps {
9186
protocols: Protocols;
9287
selectedServerName: string;

src/i18n/strings/en_EN.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,13 @@
733733
"Common names and surnames are easy to guess": "Common names and surnames are easy to guess",
734734
"Straight rows of keys are easy to guess": "Straight rows of keys are easy to guess",
735735
"Short keyboard patterns are easy to guess": "Short keyboard patterns are easy to guess",
736+
"Unnamed room": "Unnamed room",
737+
"Unable to join network": "Unable to join network",
738+
"%(brand)s does not know how to join a room on this network": "%(brand)s does not know how to join a room on this network",
739+
"Room not found": "Room not found",
740+
"Couldn't find a matching Matrix room": "Couldn't find a matching Matrix room",
741+
"Fetching third party location failed": "Fetching third party location failed",
742+
"Unable to look up room ID from server": "Unable to look up room ID from server",
736743
"Error upgrading room": "Error upgrading room",
737744
"Double check that your server supports the room version chosen and try again.": "Double check that your server supports the room version chosen and try again.",
738745
"Invite to %(spaceName)s": "Invite to %(spaceName)s",
@@ -1753,7 +1760,6 @@
17531760
"Idle": "Idle",
17541761
"Offline": "Offline",
17551762
"Unknown": "Unknown",
1756-
"Unnamed room": "Unnamed room",
17571763
"Preview": "Preview",
17581764
"View": "View",
17591765
"Join": "Join",
@@ -3054,12 +3060,6 @@
30543060
"remove %(name)s from the directory.": "remove %(name)s from the directory.",
30553061
"delete the address.": "delete the address.",
30563062
"The server may be unavailable or overloaded": "The server may be unavailable or overloaded",
3057-
"Unable to join network": "Unable to join network",
3058-
"%(brand)s does not know how to join a room on this network": "%(brand)s does not know how to join a room on this network",
3059-
"Room not found": "Room not found",
3060-
"Couldn't find a matching Matrix room": "Couldn't find a matching Matrix room",
3061-
"Fetching third party location failed": "Fetching third party location failed",
3062-
"Unable to look up room ID from server": "Unable to look up room ID from server",
30633063
"Create new room": "Create new room",
30643064
"No results for \"%(query)s\"": "No results for \"%(query)s\"",
30653065
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.",

src/utils/DirectoryUtils.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2018 The Matrix.org Foundation C.I.C.
2+
Copyright 2018, 2022 The Matrix.org Foundation C.I.C.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -14,9 +14,12 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import { IInstance } from "matrix-js-sdk/src/client";
17+
import { IInstance, IProtocol } from "matrix-js-sdk/src/client";
1818

19-
import { Protocols } from "../components/views/directory/NetworkDropdown";
19+
// XXX: We would ideally use a symbol here but we can't since we save this value to localStorage
20+
export const ALL_ROOMS = "ALL_ROOMS";
21+
22+
export type Protocols = Record<string, IProtocol>;
2023

2124
// Find a protocol 'instance' with a given instance_id
2225
// in the supplied protocols dict

src/utils/error.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
Copyright 2022 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
export class GenericError extends Error {
18+
constructor(
19+
public readonly message: string,
20+
public readonly description?: string | undefined,
21+
) {
22+
super(message);
23+
}
24+
}

0 commit comments

Comments
 (0)