Merge pull request #6424 from matrix-org/t3chguy/fix/18071
This commit is contained in:
commit
94af6db201
9 changed files with 362 additions and 39 deletions
|
@ -88,6 +88,7 @@
|
||||||
@import "./views/dialogs/_InviteDialog.scss";
|
@import "./views/dialogs/_InviteDialog.scss";
|
||||||
@import "./views/dialogs/_JoinRuleDropdown.scss";
|
@import "./views/dialogs/_JoinRuleDropdown.scss";
|
||||||
@import "./views/dialogs/_KeyboardShortcutsDialog.scss";
|
@import "./views/dialogs/_KeyboardShortcutsDialog.scss";
|
||||||
|
@import "./views/dialogs/_LeaveSpaceDialog.scss";
|
||||||
@import "./views/dialogs/_ManageRestrictedJoinRuleDialog.scss";
|
@import "./views/dialogs/_ManageRestrictedJoinRuleDialog.scss";
|
||||||
@import "./views/dialogs/_MessageEditHistoryDialog.scss";
|
@import "./views/dialogs/_MessageEditHistoryDialog.scss";
|
||||||
@import "./views/dialogs/_ModalWidgetDialog.scss";
|
@import "./views/dialogs/_ModalWidgetDialog.scss";
|
||||||
|
|
|
@ -50,35 +50,6 @@ limitations under the License.
|
||||||
line-height: $font-15px;
|
line-height: $font-15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_AddExistingToSpace_entry {
|
|
||||||
display: flex;
|
|
||||||
margin-top: 12px;
|
|
||||||
|
|
||||||
.mx_DecoratedRoomAvatar, // we can't target .mx_BaseAvatar here as it'll break the decorated avatar styling
|
|
||||||
.mx_BaseAvatar.mx_RoomAvatar_isSpaceRoom {
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.mx_RoomAvatar_isSpaceRoom,
|
|
||||||
.mx_RoomAvatar_isSpaceRoom img {
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_AddExistingToSpace_entry_name {
|
|
||||||
font-size: $font-15px;
|
|
||||||
line-height: 30px;
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_Checkbox {
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_AccessibleButton_kind_link {
|
.mx_AccessibleButton_kind_link {
|
||||||
font-size: $font-12px;
|
font-size: $font-12px;
|
||||||
line-height: $font-15px;
|
line-height: $font-15px;
|
||||||
|
@ -255,3 +226,32 @@ limitations under the License.
|
||||||
line-height: $font-24px;
|
line-height: $font-24px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_AddExistingToSpace_entry {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 12px;
|
||||||
|
|
||||||
|
.mx_DecoratedRoomAvatar, // we can't target .mx_BaseAvatar here as it'll break the decorated avatar styling
|
||||||
|
.mx_BaseAvatar.mx_RoomAvatar_isSpaceRoom {
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.mx_RoomAvatar_isSpaceRoom,
|
||||||
|
.mx_RoomAvatar_isSpaceRoom img {
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_AddExistingToSpace_entry_name {
|
||||||
|
font-size: $font-15px;
|
||||||
|
line-height: 30px;
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Checkbox {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
96
res/css/views/dialogs/_LeaveSpaceDialog.scss
Normal file
96
res/css/views/dialogs/_LeaveSpaceDialog.scss
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.mx_LeaveSpaceDialog_wrapper {
|
||||||
|
.mx_Dialog {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 24px 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_LeaveSpaceDialog {
|
||||||
|
width: 440px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
max-height: 520px;
|
||||||
|
|
||||||
|
.mx_Dialog_content {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.mx_RadioButton + .mx_RadioButton {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_SearchBox {
|
||||||
|
// To match the space around the title
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
flex-grow: 0;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_LeaveSpaceDialog_noResults {
|
||||||
|
display: block;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_LeaveSpaceDialog_section {
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_LeaveSpaceDialog_section_warning {
|
||||||
|
position: relative;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 12px 0 0;
|
||||||
|
padding: 12px 8px 12px 42px;
|
||||||
|
background-color: $header-panel-bg-color;
|
||||||
|
|
||||||
|
font-size: $font-12px;
|
||||||
|
line-height: $font-15px;
|
||||||
|
color: $secondary-fg-color;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
top: calc(50% - 8px); // vertical centering
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
background-color: $secondary-fg-color;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-size: contain;
|
||||||
|
mask-image: url('$(res)/img/element-icons/room/room-summary.svg');
|
||||||
|
mask-position: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> p {
|
||||||
|
color: $primary-fg-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Dialog_buttons {
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.mx_Dialog_primary {
|
||||||
|
background-color: $notice-primary-color !important; // override default colour
|
||||||
|
border-color: $notice-primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
197
src/components/views/dialogs/LeaveSpaceDialog.tsx
Normal file
197
src/components/views/dialogs/LeaveSpaceDialog.tsx
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
import { JoinRule } from "matrix-js-sdk/src/@types/partials";
|
||||||
|
|
||||||
|
import { _t } from '../../../languageHandler';
|
||||||
|
import DialogButtons from "../elements/DialogButtons";
|
||||||
|
import BaseDialog from "../dialogs/BaseDialog";
|
||||||
|
import SpaceStore from "../../../stores/SpaceStore";
|
||||||
|
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
|
||||||
|
import { Entry } from "./AddExistingToSpaceDialog";
|
||||||
|
import SearchBox from "../../structures/SearchBox";
|
||||||
|
import QueryMatcher from "../../../autocomplete/QueryMatcher";
|
||||||
|
import StyledRadioGroup from "../elements/StyledRadioGroup";
|
||||||
|
|
||||||
|
enum RoomsToLeave {
|
||||||
|
All = "All",
|
||||||
|
Specific = "Specific",
|
||||||
|
None = "None",
|
||||||
|
}
|
||||||
|
|
||||||
|
const SpaceChildPicker = ({ filterPlaceholder, rooms, selected, onChange }) => {
|
||||||
|
const [query, setQuery] = useState("");
|
||||||
|
const lcQuery = query.toLowerCase().trim();
|
||||||
|
|
||||||
|
const filteredRooms = useMemo(() => {
|
||||||
|
if (!lcQuery) {
|
||||||
|
return rooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
const matcher = new QueryMatcher<Room>(rooms, {
|
||||||
|
keys: ["name"],
|
||||||
|
funcs: [r => [r.getCanonicalAlias(), ...r.getAltAliases()].filter(Boolean)],
|
||||||
|
shouldMatchWordsOnly: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return matcher.match(lcQuery);
|
||||||
|
}, [rooms, lcQuery]);
|
||||||
|
|
||||||
|
return <div className="mx_LeaveSpaceDialog_section">
|
||||||
|
<SearchBox
|
||||||
|
className="mx_textinput_icon mx_textinput_search"
|
||||||
|
placeholder={filterPlaceholder}
|
||||||
|
onSearch={setQuery}
|
||||||
|
autoComplete={true}
|
||||||
|
autoFocus={true}
|
||||||
|
/>
|
||||||
|
<AutoHideScrollbar className="mx_LeaveSpaceDialog_content">
|
||||||
|
{ filteredRooms.map(room => {
|
||||||
|
return <Entry
|
||||||
|
key={room.roomId}
|
||||||
|
room={room}
|
||||||
|
checked={selected.has(room)}
|
||||||
|
onChange={(checked) => {
|
||||||
|
onChange(checked, room);
|
||||||
|
}}
|
||||||
|
/>;
|
||||||
|
}) }
|
||||||
|
{ filteredRooms.length < 1 ? <span className="mx_LeaveSpaceDialog_noResults">
|
||||||
|
{ _t("No results") }
|
||||||
|
</span> : undefined }
|
||||||
|
</AutoHideScrollbar>
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const LeaveRoomsPicker = ({ space, spaceChildren, roomsToLeave, setRoomsToLeave }) => {
|
||||||
|
const selected = useMemo(() => new Set(roomsToLeave), [roomsToLeave]);
|
||||||
|
const [state, setState] = useState<string>(RoomsToLeave.All);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (state === RoomsToLeave.All) {
|
||||||
|
setRoomsToLeave(spaceChildren);
|
||||||
|
} else {
|
||||||
|
setRoomsToLeave([]);
|
||||||
|
}
|
||||||
|
}, [setRoomsToLeave, state, spaceChildren]);
|
||||||
|
|
||||||
|
return <div className="mx_LeaveSpaceDialog_section">
|
||||||
|
<StyledRadioGroup
|
||||||
|
name="roomsToLeave"
|
||||||
|
value={state}
|
||||||
|
onChange={setState}
|
||||||
|
definitions={[
|
||||||
|
{
|
||||||
|
value: RoomsToLeave.All,
|
||||||
|
label: _t("Leave all rooms and spaces"),
|
||||||
|
}, {
|
||||||
|
value: RoomsToLeave.None,
|
||||||
|
label: _t("Don't leave any"),
|
||||||
|
}, {
|
||||||
|
value: RoomsToLeave.Specific,
|
||||||
|
label: _t("Leave specific rooms and spaces"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{ state === RoomsToLeave.Specific && (
|
||||||
|
<SpaceChildPicker
|
||||||
|
filterPlaceholder={_t("Search %(spaceName)s", { spaceName: space.name })}
|
||||||
|
rooms={spaceChildren}
|
||||||
|
selected={selected}
|
||||||
|
onChange={(selected: boolean, room: Room) => {
|
||||||
|
if (selected) {
|
||||||
|
setRoomsToLeave([room, ...roomsToLeave]);
|
||||||
|
} else {
|
||||||
|
setRoomsToLeave(roomsToLeave.filter(r => r !== room));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) }
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
space: Room;
|
||||||
|
onFinished(leave: boolean, rooms?: Room[]): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isOnlyAdmin = (room: Room): boolean => {
|
||||||
|
return !room.getJoinedMembers().some(member => {
|
||||||
|
return member.userId !== room.client.credentials.userId && member.powerLevelNorm === 100;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
|
||||||
|
const spaceChildren = useMemo(() => SpaceStore.instance.getChildren(space.roomId), [space.roomId]);
|
||||||
|
const [roomsToLeave, setRoomsToLeave] = useState<Room[]>([]);
|
||||||
|
|
||||||
|
let rejoinWarning;
|
||||||
|
if (space.getJoinRule() !== JoinRule.Public) {
|
||||||
|
rejoinWarning = _t("You won't be able to rejoin unless you are re-invited.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let onlyAdminWarning;
|
||||||
|
if (isOnlyAdmin(space)) {
|
||||||
|
onlyAdminWarning = _t("You're the only admin of this space. " +
|
||||||
|
"Leaving it will mean no one has control over it.");
|
||||||
|
} else {
|
||||||
|
const numChildrenOnlyAdminIn = roomsToLeave.filter(isOnlyAdmin).length;
|
||||||
|
if (numChildrenOnlyAdminIn > 0) {
|
||||||
|
onlyAdminWarning = _t("You're the only admin of some of the rooms or spaces you wish to leave. " +
|
||||||
|
"Leaving them will leave them without any admins.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return <BaseDialog
|
||||||
|
title={_t("Leave %(spaceName)s", { spaceName: space.name })}
|
||||||
|
className="mx_LeaveSpaceDialog"
|
||||||
|
contentId="mx_LeaveSpaceDialog"
|
||||||
|
onFinished={() => onFinished(false)}
|
||||||
|
fixedWidth={false}
|
||||||
|
>
|
||||||
|
<div className="mx_Dialog_content" id="mx_LeaveSpaceDialog">
|
||||||
|
<p>
|
||||||
|
{ _t("Are you sure you want to leave <spaceName/>?", {}, {
|
||||||
|
spaceName: () => <b>{ space.name }</b>,
|
||||||
|
}) }
|
||||||
|
|
||||||
|
{ rejoinWarning }
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{ spaceChildren.length > 0 && <LeaveRoomsPicker
|
||||||
|
space={space}
|
||||||
|
spaceChildren={spaceChildren}
|
||||||
|
roomsToLeave={roomsToLeave}
|
||||||
|
setRoomsToLeave={setRoomsToLeave}
|
||||||
|
/> }
|
||||||
|
|
||||||
|
{ onlyAdminWarning && <div className="mx_LeaveSpaceDialog_section_warning">
|
||||||
|
{ onlyAdminWarning }
|
||||||
|
</div> }
|
||||||
|
</div>
|
||||||
|
<DialogButtons
|
||||||
|
primaryButton={_t("Leave space")}
|
||||||
|
onPrimaryButtonClick={() => onFinished(true, roomsToLeave)}
|
||||||
|
hasCancel={true}
|
||||||
|
onCancel={onFinished}
|
||||||
|
/>
|
||||||
|
</BaseDialog>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LeaveSpaceDialog;
|
|
@ -25,7 +25,7 @@ import SpaceBasicSettings from "./SpaceBasicSettings";
|
||||||
import { avatarUrlForRoom } from "../../../Avatar";
|
import { avatarUrlForRoom } from "../../../Avatar";
|
||||||
import { IDialogProps } from "../dialogs/IDialogProps";
|
import { IDialogProps } from "../dialogs/IDialogProps";
|
||||||
import { getTopic } from "../elements/RoomTopic";
|
import { getTopic } from "../elements/RoomTopic";
|
||||||
import { defaultDispatcher } from "../../../dispatcher/dispatcher";
|
import { leaveSpace } from "../../../utils/space";
|
||||||
|
|
||||||
interface IProps extends IDialogProps {
|
interface IProps extends IDialogProps {
|
||||||
matrixClient: MatrixClient;
|
matrixClient: MatrixClient;
|
||||||
|
@ -125,10 +125,7 @@ const SpaceSettingsGeneralTab = ({ matrixClient: cli, space, onFinished }: IProp
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="danger"
|
kind="danger"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
defaultDispatcher.dispatch({
|
leaveSpace(space);
|
||||||
action: "leave_room",
|
|
||||||
room_id: space.roomId,
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{ _t("Leave Space") }
|
{ _t("Leave Space") }
|
||||||
|
|
|
@ -31,6 +31,7 @@ import { _t } from "../../../languageHandler";
|
||||||
import { ContextMenuTooltipButton } from "../../../accessibility/context_menu/ContextMenuTooltipButton";
|
import { ContextMenuTooltipButton } from "../../../accessibility/context_menu/ContextMenuTooltipButton";
|
||||||
import { toRightOf } from "../../structures/ContextMenu";
|
import { toRightOf } from "../../structures/ContextMenu";
|
||||||
import {
|
import {
|
||||||
|
leaveSpace,
|
||||||
shouldShowSpaceSettings,
|
shouldShowSpaceSettings,
|
||||||
showAddExistingRooms,
|
showAddExistingRooms,
|
||||||
showCreateNewRoom,
|
showCreateNewRoom,
|
||||||
|
@ -213,10 +214,7 @@ export class SpaceItem extends React.PureComponent<IItemProps, IItemState> {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
defaultDispatcher.dispatch({
|
leaveSpace(this.props.space);
|
||||||
action: "leave_room",
|
|
||||||
room_id: this.props.space.roomId,
|
|
||||||
});
|
|
||||||
this.setState({ contextMenuPosition: null }); // also close the menu
|
this.setState({ contextMenuPosition: null }); // also close the menu
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2376,6 +2376,15 @@
|
||||||
"Clear cache and resync": "Clear cache and resync",
|
"Clear cache and resync": "Clear cache and resync",
|
||||||
"%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!",
|
"%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!",
|
||||||
"Updating %(brand)s": "Updating %(brand)s",
|
"Updating %(brand)s": "Updating %(brand)s",
|
||||||
|
"Leave all rooms and spaces": "Leave all rooms and spaces",
|
||||||
|
"Don't leave any": "Don't leave any",
|
||||||
|
"Leave specific rooms and spaces": "Leave specific rooms and spaces",
|
||||||
|
"Search %(spaceName)s": "Search %(spaceName)s",
|
||||||
|
"You won't be able to rejoin unless you are re-invited.": "You won't be able to rejoin unless you are re-invited.",
|
||||||
|
"You're the only admin of this space. Leaving it will mean no one has control over it.": "You're the only admin of this space. Leaving it will mean no one has control over it.",
|
||||||
|
"You're the only admin of some of the rooms or spaces you wish to leave. Leaving them will leave them without any admins.": "You're the only admin of some of the rooms or spaces you wish to leave. Leaving them will leave them without any admins.",
|
||||||
|
"Leave %(spaceName)s": "Leave %(spaceName)s",
|
||||||
|
"Are you sure you want to leave <spaceName/>?": "Are you sure you want to leave <spaceName/>?",
|
||||||
"Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.",
|
"Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.",
|
||||||
"Start using Key Backup": "Start using Key Backup",
|
"Start using Key Backup": "Start using Key Backup",
|
||||||
"I don't want my encrypted messages": "I don't want my encrypted messages",
|
"I don't want my encrypted messages": "I don't want my encrypted messages",
|
||||||
|
|
|
@ -329,7 +329,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
}, roomId);
|
}, roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getChildren(spaceId: string): Room[] {
|
public getChildren(spaceId: string): Room[] {
|
||||||
const room = this.matrixClient?.getRoom(spaceId);
|
const room = this.matrixClient?.getRoom(spaceId);
|
||||||
const childEvents = room?.currentState.getStateEvents(EventType.SpaceChild).filter(ev => ev.getContent()?.via);
|
const childEvents = room?.currentState.getStateEvents(EventType.SpaceChild).filter(ev => ev.getContent()?.via);
|
||||||
return sortBy(childEvents, ev => {
|
return sortBy(childEvents, ev => {
|
||||||
|
|
|
@ -33,6 +33,10 @@ import AddExistingSubspaceDialog from "../components/views/dialogs/AddExistingSu
|
||||||
import defaultDispatcher from "../dispatcher/dispatcher";
|
import defaultDispatcher from "../dispatcher/dispatcher";
|
||||||
import RoomViewStore from "../stores/RoomViewStore";
|
import RoomViewStore from "../stores/RoomViewStore";
|
||||||
import { Action } from "../dispatcher/actions";
|
import { Action } from "../dispatcher/actions";
|
||||||
|
import { leaveRoomBehaviour } from "./membership";
|
||||||
|
import Spinner from "../components/views/elements/Spinner";
|
||||||
|
import dis from "../dispatcher/dispatcher";
|
||||||
|
import LeaveSpaceDialog from "../components/views/dialogs/LeaveSpaceDialog";
|
||||||
|
|
||||||
export const shouldShowSpaceSettings = (space: Room) => {
|
export const shouldShowSpaceSettings = (space: Room) => {
|
||||||
const userId = space.client.getUserId();
|
const userId = space.client.getUserId();
|
||||||
|
@ -148,3 +152,24 @@ export const showCreateNewSubspace = (space: Room): void => {
|
||||||
"mx_CreateSubspaceDialog_wrapper",
|
"mx_CreateSubspaceDialog_wrapper",
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const leaveSpace = (space: Room) => {
|
||||||
|
Modal.createTrackedDialog("Leave Space", "", LeaveSpaceDialog, {
|
||||||
|
space,
|
||||||
|
onFinished: async (leave: boolean, rooms: Room[]) => {
|
||||||
|
if (!leave) return;
|
||||||
|
const modal = Modal.createDialog(Spinner, null, "mx_Dialog_spinner");
|
||||||
|
try {
|
||||||
|
await Promise.all(rooms.map(r => leaveRoomBehaviour(r.roomId)));
|
||||||
|
await leaveRoomBehaviour(space.roomId);
|
||||||
|
} finally {
|
||||||
|
modal.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
dis.dispatch({
|
||||||
|
action: "after_leave_room",
|
||||||
|
room_id: space.roomId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, "mx_LeaveSpaceDialog_wrapper");
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue