Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/fix/18798
Conflicts: src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx
This commit is contained in:
commit
630835961b
18 changed files with 138 additions and 88 deletions
24
.github/workflows/typecheck.yaml
vendored
Normal file
24
.github/workflows/typecheck.yaml
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
name: Type Check
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [develop]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: c-hive/gha-yarn-cache@v2
|
||||||
|
- name: Install Deps
|
||||||
|
run: "./scripts/ci/install-deps.sh --ignore-scripts"
|
||||||
|
- name: Typecheck
|
||||||
|
run: "yarn run lint:types"
|
||||||
|
- name: Switch js-sdk to release mode
|
||||||
|
run: |
|
||||||
|
scripts/ci/js-sdk-to-release.js
|
||||||
|
cd node_modules/matrix-js-sdk
|
||||||
|
yarn install
|
||||||
|
yarn run build:compile
|
||||||
|
yarn run build:types
|
||||||
|
- name: Typecheck (release mode)
|
||||||
|
run: "yarn run lint:types"
|
||||||
|
|
17
scripts/ci/js-sdk-to-release.js
Executable file
17
scripts/ci/js-sdk-to-release.js
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const fsProm = require('fs/promises');
|
||||||
|
|
||||||
|
const PKGJSON = 'node_modules/matrix-js-sdk/package.json';
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const pkgJson = JSON.parse(await fsProm.readFile(PKGJSON, 'utf8'));
|
||||||
|
for (const field of ['main', 'typings']) {
|
||||||
|
if (pkgJson["matrix_lib_"+field] !== undefined) {
|
||||||
|
pkgJson[field] = pkgJson["matrix_lib_"+field];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await fsProm.writeFile(PKGJSON, JSON.stringify(pkgJson, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
|
@ -1,21 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# This changes the js-sdk into 'release mode', that is:
|
|
||||||
# * The entry point for the library is the babel-compiled lib/index.js rather than src/index.ts
|
|
||||||
# * There's a 'typings' entry referencing the types output by tsc
|
|
||||||
# We do this so we can test that each PR still builds / type checks correctly when built
|
|
||||||
# against the released js-sdk, because if you do things like `import { User } from 'matrix-js-sdk';`
|
|
||||||
# rather than `import { User } from 'matrix-js-sdk/src/models/user';` it will work fine with the
|
|
||||||
# js-sdk in development mode but then break at release time.
|
|
||||||
# We can't use the last release of the js-sdk though: it might not be up to date enough.
|
|
||||||
|
|
||||||
cd node_modules/matrix-js-sdk
|
|
||||||
for i in main typings
|
|
||||||
do
|
|
||||||
lib_value=$(jq -r ".matrix_lib_$i" package.json)
|
|
||||||
if [ "$lib_value" != "null" ]; then
|
|
||||||
jq ".$i = .matrix_lib_$i" package.json > package.json.new && mv package.json.new package.json
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
yarn run build:compile
|
|
||||||
yarn run build:types
|
|
|
@ -399,7 +399,9 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
mx_LeftPanel_exploreButton_space: !!this.state.activeSpace,
|
mx_LeftPanel_exploreButton_space: !!this.state.activeSpace,
|
||||||
})}
|
})}
|
||||||
onClick={this.onExplore}
|
onClick={this.onExplore}
|
||||||
title={_t("Explore rooms")}
|
title={this.state.activeSpace
|
||||||
|
? _t("Explore %(spaceName)s", { spaceName: this.state.activeSpace.name })
|
||||||
|
: _t("Explore rooms")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -269,7 +269,7 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
case RightPanelPhases.EncryptionPanel:
|
case RightPanelPhases.EncryptionPanel:
|
||||||
panel = <UserInfo
|
panel = <UserInfo
|
||||||
user={this.state.member}
|
user={this.state.member}
|
||||||
room={this.state.phase === RightPanelPhases.SpaceMemberInfo ? this.state.space : this.props.room}
|
room={this.context.getRoom(this.state.member.roomId) ?? this.props.room}
|
||||||
key={roomId || this.state.member.userId}
|
key={roomId || this.state.member.userId}
|
||||||
onClose={this.onClose}
|
onClose={this.onClose}
|
||||||
phase={this.state.phase}
|
phase={this.state.phase}
|
||||||
|
|
|
@ -168,7 +168,7 @@ const SpaceContextMenu = ({ space, onFinished, ...props }: IProps) => {
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
||||||
action: Action.SetRightPanelPhase,
|
action: Action.SetRightPanelPhase,
|
||||||
phase: RightPanelPhases.SpaceMemberList,
|
phase: RightPanelPhases.SpaceMemberList,
|
||||||
refireParams: { space: space },
|
refireParams: { space },
|
||||||
});
|
});
|
||||||
onFinished();
|
onFinished();
|
||||||
};
|
};
|
||||||
|
|
|
@ -79,7 +79,10 @@ export default class RoomSettingsDialog extends React.Component<IProps> {
|
||||||
ROOM_SECURITY_TAB,
|
ROOM_SECURITY_TAB,
|
||||||
_td("Security & Privacy"),
|
_td("Security & Privacy"),
|
||||||
"mx_RoomSettingsDialog_securityIcon",
|
"mx_RoomSettingsDialog_securityIcon",
|
||||||
<SecurityRoomSettingsTab roomId={this.props.roomId} />,
|
<SecurityRoomSettingsTab
|
||||||
|
roomId={this.props.roomId}
|
||||||
|
closeSettingsFn={() => this.props.onFinished(true)}
|
||||||
|
/>,
|
||||||
));
|
));
|
||||||
tabs.push(new Tab(
|
tabs.push(new Tab(
|
||||||
ROOM_ROLES_TAB,
|
ROOM_ROLES_TAB,
|
||||||
|
|
|
@ -60,7 +60,7 @@ const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFin
|
||||||
SpaceSettingsTab.Visibility,
|
SpaceSettingsTab.Visibility,
|
||||||
_td("Visibility"),
|
_td("Visibility"),
|
||||||
"mx_SpaceSettingsDialog_visibilityIcon",
|
"mx_SpaceSettingsDialog_visibilityIcon",
|
||||||
<SpaceSettingsVisibilityTab matrixClient={cli} space={space} />,
|
<SpaceSettingsVisibilityTab matrixClient={cli} space={space} closeSettingsFn={onFinished} />,
|
||||||
),
|
),
|
||||||
SettingsStore.getValue(UIFeature.AdvancedSettings)
|
SettingsStore.getValue(UIFeature.AdvancedSettings)
|
||||||
? new Tab(
|
? new Tab(
|
||||||
|
|
|
@ -57,7 +57,7 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
|
||||||
// state to show a spinner immediately after clicking "start verification",
|
// state to show a spinner immediately after clicking "start verification",
|
||||||
// before we have a request
|
// before we have a request
|
||||||
const [isRequesting, setRequesting] = useState(false);
|
const [isRequesting, setRequesting] = useState(false);
|
||||||
const [phase, setPhase] = useState(request && request.phase);
|
const [phase, setPhase] = useState(request?.phase);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRequest(verificationRequest);
|
setRequest(verificationRequest);
|
||||||
if (verificationRequest) {
|
if (verificationRequest) {
|
||||||
|
|
|
@ -1278,7 +1278,9 @@ const BasicUserInfo: React.FC<{
|
||||||
// hide the Roles section for DMs as it doesn't make sense there
|
// hide the Roles section for DMs as it doesn't make sense there
|
||||||
if (!DMRoomMap.shared().getUserIdForRoomId((member as RoomMember).roomId)) {
|
if (!DMRoomMap.shared().getUserIdForRoomId((member as RoomMember).roomId)) {
|
||||||
memberDetails = <div className="mx_UserInfo_container">
|
memberDetails = <div className="mx_UserInfo_container">
|
||||||
<h3>{ _t("Role") }</h3>
|
<h3>{ _t("Role in <RoomName/>", {}, {
|
||||||
|
RoomName: () => <b>{ room.name }</b>,
|
||||||
|
}) }</h3>
|
||||||
<PowerLevelSection
|
<PowerLevelSection
|
||||||
powerLevels={powerLevels}
|
powerLevels={powerLevels}
|
||||||
user={member as RoomMember}
|
user={member as RoomMember}
|
||||||
|
@ -1573,11 +1575,12 @@ const UserInfo: React.FC<IProps> = ({
|
||||||
// We have no previousPhase for when viewing a UserInfo from a Group or without a Room at this time
|
// We have no previousPhase for when viewing a UserInfo from a Group or without a Room at this time
|
||||||
if (room && phase === RightPanelPhases.EncryptionPanel) {
|
if (room && phase === RightPanelPhases.EncryptionPanel) {
|
||||||
previousPhase = RightPanelPhases.RoomMemberInfo;
|
previousPhase = RightPanelPhases.RoomMemberInfo;
|
||||||
refireParams = { member: member };
|
refireParams = { member };
|
||||||
|
} else if (room?.isSpaceRoom() && SpaceStore.spacesEnabled) {
|
||||||
|
previousPhase = previousPhase = RightPanelPhases.SpaceMemberList;
|
||||||
|
refireParams = { space: room };
|
||||||
} else if (room) {
|
} else if (room) {
|
||||||
previousPhase = previousPhase = SpaceStore.spacesEnabled && room.isSpaceRoom()
|
previousPhase = RightPanelPhases.RoomMemberList;
|
||||||
? RightPanelPhases.SpaceMemberList
|
|
||||||
: RightPanelPhases.RoomMemberList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const onEncryptionPanelClose = () => {
|
const onEncryptionPanelClose = () => {
|
||||||
|
|
|
@ -29,43 +29,27 @@ import VerificationQRCode from "../elements/crypto/VerificationQRCode";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import SdkConfig from "../../../SdkConfig";
|
import SdkConfig from "../../../SdkConfig";
|
||||||
import E2EIcon from "../rooms/E2EIcon";
|
import E2EIcon from "../rooms/E2EIcon";
|
||||||
import {
|
import { Phase } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||||
PHASE_READY,
|
|
||||||
PHASE_DONE,
|
|
||||||
PHASE_STARTED,
|
|
||||||
PHASE_CANCELLED,
|
|
||||||
} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
|
||||||
import Spinner from "../elements/Spinner";
|
import Spinner from "../elements/Spinner";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
import VerificationShowSas from "../verification/VerificationShowSas";
|
import VerificationShowSas from "../verification/VerificationShowSas";
|
||||||
|
|
||||||
// XXX: Should be defined in matrix-js-sdk
|
|
||||||
enum VerificationPhase {
|
|
||||||
PHASE_UNSENT,
|
|
||||||
PHASE_REQUESTED,
|
|
||||||
PHASE_READY,
|
|
||||||
PHASE_DONE,
|
|
||||||
PHASE_STARTED,
|
|
||||||
PHASE_CANCELLED,
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
layout: string;
|
layout: string;
|
||||||
request: VerificationRequest;
|
request: VerificationRequest;
|
||||||
member: RoomMember | User;
|
member: RoomMember | User;
|
||||||
phase: VerificationPhase;
|
phase: Phase;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
isRoomEncrypted: boolean;
|
isRoomEncrypted: boolean;
|
||||||
inDialog: boolean;
|
inDialog: boolean;
|
||||||
key: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
sasEvent?: SAS;
|
sasEvent?: SAS["sasEvent"];
|
||||||
emojiButtonClicked?: boolean;
|
emojiButtonClicked?: boolean;
|
||||||
reciprocateButtonClicked?: boolean;
|
reciprocateButtonClicked?: boolean;
|
||||||
reciprocateQREvent?: ReciprocateQRCode;
|
reciprocateQREvent?: ReciprocateQRCode["reciprocateQREvent"];
|
||||||
}
|
}
|
||||||
|
|
||||||
@replaceableComponent("views.right_panel.VerificationPanel")
|
@replaceableComponent("views.right_panel.VerificationPanel")
|
||||||
|
@ -321,9 +305,9 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
||||||
const displayName = (member as User).displayName || (member as RoomMember).name || member.userId;
|
const displayName = (member as User).displayName || (member as RoomMember).name || member.userId;
|
||||||
|
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case PHASE_READY:
|
case Phase.Ready:
|
||||||
return this.renderQRPhase();
|
return this.renderQRPhase();
|
||||||
case PHASE_STARTED:
|
case Phase.Started:
|
||||||
switch (request.chosenMethod) {
|
switch (request.chosenMethod) {
|
||||||
case verificationMethods.RECIPROCATE_QR_CODE:
|
case verificationMethods.RECIPROCATE_QR_CODE:
|
||||||
return this.renderQRReciprocatePhase();
|
return this.renderQRReciprocatePhase();
|
||||||
|
@ -346,9 +330,9 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
case PHASE_DONE:
|
case Phase.Done:
|
||||||
return this.renderVerifiedPhase();
|
return this.renderVerifiedPhase();
|
||||||
case PHASE_CANCELLED:
|
case Phase.Cancelled:
|
||||||
return this.renderCancelledPhase();
|
return this.renderCancelledPhase();
|
||||||
}
|
}
|
||||||
console.error("VerificationPanel unhandled phase:", phase);
|
console.error("VerificationPanel unhandled phase:", phase);
|
||||||
|
@ -375,7 +359,8 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
||||||
|
|
||||||
private updateVerifierState = () => {
|
private updateVerifierState = () => {
|
||||||
const { request } = this.props;
|
const { request } = this.props;
|
||||||
const { sasEvent, reciprocateQREvent } = request.verifier;
|
const sasEvent = (request.verifier as SAS).sasEvent;
|
||||||
|
const reciprocateQREvent = (request.verifier as ReciprocateQRCode).reciprocateQREvent;
|
||||||
request.verifier.off('show_sas', this.updateVerifierState);
|
request.verifier.off('show_sas', this.updateVerifierState);
|
||||||
request.verifier.off('show_reciprocate_qr', this.updateVerifierState);
|
request.verifier.off('show_reciprocate_qr', this.updateVerifierState);
|
||||||
this.setState({ sasEvent, reciprocateQREvent });
|
this.setState({ sasEvent, reciprocateQREvent });
|
||||||
|
@ -402,7 +387,8 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
||||||
const { request } = this.props;
|
const { request } = this.props;
|
||||||
request.on("change", this.onRequestChange);
|
request.on("change", this.onRequestChange);
|
||||||
if (request.verifier) {
|
if (request.verifier) {
|
||||||
const { sasEvent, reciprocateQREvent } = request.verifier;
|
const sasEvent = (request.verifier as SAS).sasEvent;
|
||||||
|
const reciprocateQREvent = (request.verifier as ReciprocateQRCode).reciprocateQREvent;
|
||||||
this.setState({ sasEvent, reciprocateQREvent });
|
this.setState({ sasEvent, reciprocateQREvent });
|
||||||
}
|
}
|
||||||
this.onRequestChange();
|
this.onRequestChange();
|
||||||
|
|
|
@ -48,6 +48,7 @@ import SpaceStore, { ISuggestedRoom, SUGGESTED_ROOMS } from "../../../stores/Spa
|
||||||
import { showAddExistingRooms, showCreateNewRoom, showSpaceInvite } from "../../../utils/space";
|
import { showAddExistingRooms, showCreateNewRoom, showSpaceInvite } from "../../../utils/space";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import RoomAvatar from "../avatars/RoomAvatar";
|
import RoomAvatar from "../avatars/RoomAvatar";
|
||||||
|
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onKeyDown: (ev: React.KeyboardEvent) => void;
|
onKeyDown: (ev: React.KeyboardEvent) => void;
|
||||||
|
@ -522,20 +523,23 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
||||||
} else if (
|
} else if (
|
||||||
this.props.activeSpace?.canInvite(userId) || this.props.activeSpace?.getMyMembership() === "join"
|
this.props.activeSpace?.canInvite(userId) || this.props.activeSpace?.getMyMembership() === "join"
|
||||||
) {
|
) {
|
||||||
|
const spaceName = this.props.activeSpace.name;
|
||||||
explorePrompt = <div className="mx_RoomList_explorePrompt">
|
explorePrompt = <div className="mx_RoomList_explorePrompt">
|
||||||
<div>{ _t("Quick actions") }</div>
|
<div>{ _t("Quick actions") }</div>
|
||||||
{ this.props.activeSpace.canInvite(userId) && <AccessibleButton
|
{ this.props.activeSpace.canInvite(userId) && <AccessibleTooltipButton
|
||||||
className="mx_RoomList_explorePrompt_spaceInvite"
|
className="mx_RoomList_explorePrompt_spaceInvite"
|
||||||
onClick={this.onSpaceInviteClick}
|
onClick={this.onSpaceInviteClick}
|
||||||
|
title={_t("Invite to %(spaceName)s", { spaceName })}
|
||||||
>
|
>
|
||||||
{ _t("Invite people") }
|
{ _t("Invite people") }
|
||||||
</AccessibleButton> }
|
</AccessibleTooltipButton> }
|
||||||
{ this.props.activeSpace.getMyMembership() === "join" && <AccessibleButton
|
{ this.props.activeSpace.getMyMembership() === "join" && <AccessibleTooltipButton
|
||||||
className="mx_RoomList_explorePrompt_spaceExplore"
|
className="mx_RoomList_explorePrompt_spaceExplore"
|
||||||
onClick={this.onExplore}
|
onClick={this.onExplore}
|
||||||
|
title={_t("Explore %(spaceName)s", { spaceName })}
|
||||||
>
|
>
|
||||||
{ _t("Explore rooms") }
|
{ _t("Explore rooms") }
|
||||||
</AccessibleButton> }
|
</AccessibleTooltipButton> }
|
||||||
</div>;
|
</div>;
|
||||||
} else if (Object.values(this.state.sublists).some(list => list.length > 0)) {
|
} else if (Object.values(this.state.sublists).some(list => list.length > 0)) {
|
||||||
const unfilteredLists = RoomListStore.instance.unfilteredLists;
|
const unfilteredLists = RoomListStore.instance.unfilteredLists;
|
||||||
|
|
|
@ -31,15 +31,18 @@ import RoomUpgradeWarningDialog from "../dialogs/RoomUpgradeWarningDialog";
|
||||||
import { upgradeRoom } from "../../../utils/RoomUpgrade";
|
import { upgradeRoom } from "../../../utils/RoomUpgrade";
|
||||||
import { arrayHasDiff } from "../../../utils/arrays";
|
import { arrayHasDiff } from "../../../utils/arrays";
|
||||||
import { useLocalEcho } from "../../../hooks/useLocalEcho";
|
import { useLocalEcho } from "../../../hooks/useLocalEcho";
|
||||||
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
|
import { ROOM_SECURITY_TAB } from "../dialogs/RoomSettingsDialog";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
room: Room;
|
room: Room;
|
||||||
promptUpgrade?: boolean;
|
promptUpgrade?: boolean;
|
||||||
|
closeSettingsFn(): void;
|
||||||
onError(error: Error): void;
|
onError(error: Error): void;
|
||||||
beforeChange?(joinRule: JoinRule): Promise<boolean>; // if returns false then aborts the change
|
beforeChange?(joinRule: JoinRule): Promise<boolean>; // if returns false then aborts the change
|
||||||
}
|
}
|
||||||
|
|
||||||
const JoinRuleSettings = ({ room, promptUpgrade, onError, beforeChange }: IProps) => {
|
const JoinRuleSettings = ({ room, promptUpgrade, onError, beforeChange, closeSettingsFn }: IProps) => {
|
||||||
const cli = room.client;
|
const cli = room.client;
|
||||||
|
|
||||||
const restrictedRoomCapabilities = SpaceStore.instance.restrictedJoinRuleSupport;
|
const restrictedRoomCapabilities = SpaceStore.instance.restrictedJoinRuleSupport;
|
||||||
|
@ -208,9 +211,20 @@ const JoinRuleSettings = ({ room, promptUpgrade, onError, beforeChange }: IProps
|
||||||
targetVersion,
|
targetVersion,
|
||||||
description: _t("This upgrade will allow members of selected spaces " +
|
description: _t("This upgrade will allow members of selected spaces " +
|
||||||
"access to this room without an invite."),
|
"access to this room without an invite."),
|
||||||
onFinished: (resp) => {
|
onFinished: async (resp) => {
|
||||||
if (!resp?.continue) return;
|
if (!resp?.continue) return;
|
||||||
upgradeRoom(room, targetVersion, resp.invite);
|
const roomId = await upgradeRoom(room, targetVersion, resp.invite, true, true, true);
|
||||||
|
closeSettingsFn();
|
||||||
|
// switch to the new room in the background
|
||||||
|
dis.dispatch({
|
||||||
|
action: "view_room",
|
||||||
|
room_id: roomId,
|
||||||
|
});
|
||||||
|
// open new settings on this tab
|
||||||
|
dis.dispatch({
|
||||||
|
action: "open_room_settings",
|
||||||
|
initial_tab_id: ROOM_SECURITY_TAB,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -38,6 +38,7 @@ import ErrorDialog from "../../../dialogs/ErrorDialog";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
roomId: string;
|
roomId: string;
|
||||||
|
closeSettingsFn: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
|
@ -276,6 +277,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
|
||||||
room={room}
|
room={room}
|
||||||
beforeChange={this.onBeforeJoinRuleChange}
|
beforeChange={this.onBeforeJoinRuleChange}
|
||||||
onError={this.onJoinRuleChangeError}
|
onError={this.onJoinRuleChangeError}
|
||||||
|
closeSettingsFn={this.props.closeSettingsFn}
|
||||||
promptUpgrade={true}
|
promptUpgrade={true}
|
||||||
/>
|
/>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
|
@ -31,9 +31,10 @@ import JoinRuleSettings from "../settings/JoinRuleSettings";
|
||||||
interface IProps {
|
interface IProps {
|
||||||
matrixClient: MatrixClient;
|
matrixClient: MatrixClient;
|
||||||
space: Room;
|
space: Room;
|
||||||
|
closeSettingsFn(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SpaceSettingsVisibilityTab = ({ matrixClient: cli, space }: IProps) => {
|
const SpaceSettingsVisibilityTab = ({ matrixClient: cli, space, closeSettingsFn }: IProps) => {
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
const userId = cli.getUserId();
|
const userId = cli.getUserId();
|
||||||
|
@ -119,6 +120,7 @@ const SpaceSettingsVisibilityTab = ({ matrixClient: cli, space }: IProps) => {
|
||||||
<JoinRuleSettings
|
<JoinRuleSettings
|
||||||
room={space}
|
room={space}
|
||||||
onError={() => setError(_t("Failed to update the visibility of this space"))}
|
onError={() => setError(_t("Failed to update the visibility of this space"))}
|
||||||
|
closeSettingsFn={closeSettingsFn}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SAS } from "matrix-js-sdk/src/crypto/verification/SAS";
|
import { IGeneratedSas } from "matrix-js-sdk/src/crypto/verification/SAS";
|
||||||
import { DeviceInfo } from "matrix-js-sdk/src//crypto/deviceinfo";
|
import { DeviceInfo } from "matrix-js-sdk/src//crypto/deviceinfo";
|
||||||
import { _t, _td } from '../../../languageHandler';
|
import { _t, _td } from '../../../languageHandler';
|
||||||
import { PendingActionSpinner } from "../right_panel/EncryptionInfo";
|
import { PendingActionSpinner } from "../right_panel/EncryptionInfo";
|
||||||
|
@ -30,7 +30,7 @@ interface IProps {
|
||||||
device?: DeviceInfo;
|
device?: DeviceInfo;
|
||||||
onDone: () => void;
|
onDone: () => void;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
sas: SAS.sas;
|
sas: IGeneratedSas;
|
||||||
isSelf?: boolean;
|
isSelf?: boolean;
|
||||||
inDialog?: boolean; // whether this component is being shown in a dialog and to use DialogButtons
|
inDialog?: boolean; // whether this component is being shown in a dialog and to use DialogButtons
|
||||||
}
|
}
|
||||||
|
|
|
@ -1642,6 +1642,7 @@
|
||||||
"Start a new chat": "Start a new chat",
|
"Start a new chat": "Start a new chat",
|
||||||
"Explore all public rooms": "Explore all public rooms",
|
"Explore all public rooms": "Explore all public rooms",
|
||||||
"Quick actions": "Quick actions",
|
"Quick actions": "Quick actions",
|
||||||
|
"Explore %(spaceName)s": "Explore %(spaceName)s",
|
||||||
"Use the + to make a new room or explore existing ones below": "Use the + to make a new room or explore existing ones below",
|
"Use the + to make a new room or explore existing ones below": "Use the + to make a new room or explore existing ones below",
|
||||||
"%(count)s results in all spaces|other": "%(count)s results in all spaces",
|
"%(count)s results in all spaces|other": "%(count)s results in all spaces",
|
||||||
"%(count)s results in all spaces|one": "%(count)s result in all spaces",
|
"%(count)s results in all spaces|one": "%(count)s result in all spaces",
|
||||||
|
@ -1865,7 +1866,7 @@
|
||||||
"Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?",
|
"Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?",
|
||||||
"Deactivate user": "Deactivate user",
|
"Deactivate user": "Deactivate user",
|
||||||
"Failed to deactivate user": "Failed to deactivate user",
|
"Failed to deactivate user": "Failed to deactivate user",
|
||||||
"Role": "Role",
|
"Role in <RoomName/>": "Role in <RoomName/>",
|
||||||
"This client does not support end-to-end encryption.": "This client does not support end-to-end encryption.",
|
"This client does not support end-to-end encryption.": "This client does not support end-to-end encryption.",
|
||||||
"Edit devices": "Edit devices",
|
"Edit devices": "Edit devices",
|
||||||
"Security": "Security",
|
"Security": "Security",
|
||||||
|
|
|
@ -22,6 +22,7 @@ import Modal from "../Modal";
|
||||||
import { _t } from "../languageHandler";
|
import { _t } from "../languageHandler";
|
||||||
import ErrorDialog from "../components/views/dialogs/ErrorDialog";
|
import ErrorDialog from "../components/views/dialogs/ErrorDialog";
|
||||||
import SpaceStore from "../stores/SpaceStore";
|
import SpaceStore from "../stores/SpaceStore";
|
||||||
|
import Spinner from "../components/views/elements/Spinner";
|
||||||
|
|
||||||
export async function upgradeRoom(
|
export async function upgradeRoom(
|
||||||
room: Room,
|
room: Room,
|
||||||
|
@ -29,8 +30,10 @@ export async function upgradeRoom(
|
||||||
inviteUsers = false,
|
inviteUsers = false,
|
||||||
handleError = true,
|
handleError = true,
|
||||||
updateSpaces = true,
|
updateSpaces = true,
|
||||||
|
awaitRoom = false,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const cli = room.client;
|
const cli = room.client;
|
||||||
|
const spinnerModal = Modal.createDialog(Spinner, null, "mx_Dialog_spinner");
|
||||||
|
|
||||||
let newRoomId: string;
|
let newRoomId: string;
|
||||||
try {
|
try {
|
||||||
|
@ -46,14 +49,27 @@ export async function upgradeRoom(
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (awaitRoom || inviteUsers) {
|
||||||
|
await new Promise<void>(resolve => {
|
||||||
|
// already have the room
|
||||||
|
if (room.client.getRoom(newRoomId)) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// We have to wait for the js-sdk to give us the room back so
|
// We have to wait for the js-sdk to give us the room back so
|
||||||
// we can more effectively abuse the MultiInviter behaviour
|
// we can more effectively abuse the MultiInviter behaviour
|
||||||
// which heavily relies on the Room object being available.
|
// which heavily relies on the Room object being available.
|
||||||
if (inviteUsers) {
|
const checkForRoomFn = (newRoom: Room) => {
|
||||||
const checkForUpgradeFn = async (newRoom: Room): Promise<void> => {
|
|
||||||
// The upgradePromise should be done by the time we await it here.
|
|
||||||
if (newRoom.roomId !== newRoomId) return;
|
if (newRoom.roomId !== newRoomId) return;
|
||||||
|
resolve();
|
||||||
|
cli.off("Room", checkForRoomFn);
|
||||||
|
};
|
||||||
|
cli.on("Room", checkForRoomFn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inviteUsers) {
|
||||||
const toInvite = [
|
const toInvite = [
|
||||||
...room.getMembersWithMembership("join"),
|
...room.getMembersWithMembership("join"),
|
||||||
...room.getMembersWithMembership("invite"),
|
...room.getMembersWithMembership("invite"),
|
||||||
|
@ -63,10 +79,6 @@ export async function upgradeRoom(
|
||||||
// Errors are handled internally to this function
|
// Errors are handled internally to this function
|
||||||
await inviteUsersToRoom(newRoomId, toInvite);
|
await inviteUsersToRoom(newRoomId, toInvite);
|
||||||
}
|
}
|
||||||
|
|
||||||
cli.removeListener('Room', checkForUpgradeFn);
|
|
||||||
};
|
|
||||||
cli.on('Room', checkForUpgradeFn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateSpaces) {
|
if (updateSpaces) {
|
||||||
|
@ -89,5 +101,6 @@ export async function upgradeRoom(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spinnerModal.close();
|
||||||
return newRoomId;
|
return newRoomId;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue