;
+};
+
+export default SpaceBasicSettings;
diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx
new file mode 100644
index 0000000000..9d0543a6c5
--- /dev/null
+++ b/src/components/views/spaces/SpaceCreateMenu.tsx
@@ -0,0 +1,175 @@
+/*
+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, {useContext, useState} from "react";
+import classNames from "classnames";
+import {EventType, RoomType, RoomCreateTypeField} from "matrix-js-sdk/src/@types/event";
+
+import {_t} from "../../../languageHandler";
+import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
+import {ChevronFace, ContextMenu} from "../../structures/ContextMenu";
+import FormButton from "../elements/FormButton";
+import createRoom, {IStateEvent, Preset} from "../../../createRoom";
+import MatrixClientContext from "../../../contexts/MatrixClientContext";
+import SpaceBasicSettings from "./SpaceBasicSettings";
+import AccessibleButton from "../elements/AccessibleButton";
+import FocusLock from "react-focus-lock";
+
+const SpaceCreateMenuType = ({ title, description, className, onClick }) => {
+ return (
+
+
;
+};
+
+export default class SpaceRoomView extends React.PureComponent {
+ static contextType = MatrixClientContext;
+
+ private readonly creator: string;
+ private readonly dispatcherRef: string;
+ private readonly rightPanelStoreToken: EventSubscription;
+
+ constructor(props, context) {
+ super(props, context);
+
+ let phase = Phase.Landing;
+
+ this.creator = this.props.space.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender();
+ const showSetup = this.props.justCreatedOpts && this.context.getUserId() === this.creator;
+
+ if (showSetup) {
+ phase = this.props.justCreatedOpts.createOpts.preset === Preset.PublicChat
+ ? Phase.PublicCreateRooms : Phase.PrivateScope;
+ }
+
+ this.state = {
+ phase,
+ showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
+ };
+
+ this.dispatcherRef = defaultDispatcher.register(this.onAction);
+ this.rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelStoreUpdate);
+ }
+
+ componentWillUnmount() {
+ defaultDispatcher.unregister(this.dispatcherRef);
+ this.rightPanelStoreToken.remove();
+ }
+
+ private onRightPanelStoreUpdate = () => {
+ this.setState({
+ showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
+ });
+ };
+
+ private onAction = (payload: ActionPayload) => {
+ if (payload.action !== Action.ViewUser && payload.action !== "view_3pid_invite") return;
+
+ if (payload.action === Action.ViewUser && payload.member) {
+ defaultDispatcher.dispatch({
+ action: Action.SetRightPanelPhase,
+ phase: RightPanelPhases.SpaceMemberInfo,
+ refireParams: {
+ space: this.props.space,
+ member: payload.member,
+ },
+ });
+ } else if (payload.action === "view_3pid_invite" && payload.event) {
+ defaultDispatcher.dispatch({
+ action: Action.SetRightPanelPhase,
+ phase: RightPanelPhases.Space3pidMemberInfo,
+ refireParams: {
+ space: this.props.space,
+ event: payload.event,
+ },
+ });
+ } else {
+ defaultDispatcher.dispatch({
+ action: Action.SetRightPanelPhase,
+ phase: RightPanelPhases.SpaceMemberList,
+ refireParams: { space: this.props.space },
+ });
+ }
+ };
+
+ private renderBody() {
+ switch (this.state.phase) {
+ case Phase.Landing:
+ return ;
+
+ case Phase.PublicCreateRooms:
+ return this.setState({ phase: Phase.PublicShare })}
+ />;
+ case Phase.PublicShare:
+ return this.setState({ phase: Phase.Landing })}
+ />;
+
+ case Phase.PrivateScope:
+ return {
+ this.setState({ phase: invite ? Phase.PrivateInvite : Phase.PrivateCreateRooms });
+ }}
+ />;
+ case Phase.PrivateInvite:
+ return this.setState({ phase: Phase.PrivateCreateRooms })}
+ />;
+ case Phase.PrivateCreateRooms:
+ return this.setState({ phase: Phase.Landing })}
+ />;
+ }
+ }
+
+ render() {
+ const rightPanel = this.state.showRightPanel && this.state.phase === Phase.Landing
+ ?
+ : null;
+
+ return
+
+
+ { this.renderBody() }
+
+
+ ;
+ }
+}
diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx
index 5b936e822c..9bc5b6476f 100644
--- a/src/components/views/dialogs/InviteDialog.tsx
+++ b/src/components/views/dialogs/InviteDialog.tsx
@@ -15,7 +15,7 @@ limitations under the License.
*/
import React, {createRef} from 'react';
-import {_t} from "../../../languageHandler";
+import {_t, _td} from "../../../languageHandler";
import * as sdk from "../../../index";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import {makeRoomPermalink, makeUserPermalink} from "../../../utils/permalinks/Permalinks";
@@ -48,6 +48,7 @@ import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
export const KIND_DM = "dm";
export const KIND_INVITE = "invite";
+export const KIND_SPACE_INVITE = "space_invite";
export const KIND_CALL_TRANSFER = "call_transfer";
const INITIAL_ROOMS_SHOWN = 3; // Number of rooms to show at first
@@ -309,7 +310,7 @@ interface IInviteDialogProps {
// not provided.
kind: string,
- // The room ID this dialog is for. Only required for KIND_INVITE.
+ // The room ID this dialog is for. Only required for KIND_INVITE and KIND_SPACE_INVITE.
roomId: string,
// The call to transfer. Only required for KIND_CALL_TRANSFER.
@@ -348,8 +349,8 @@ export default class InviteDialog extends React.PureComponent) or " +
- "share this room.",
- {},
- {
- userId: () =>
- {userId},
- a: (sub) =>
-
- {sub}
- ,
- },
- );
- } else {
- helpText = _t(
- "Invite someone using their name, username (like ) or share this room.",
- {},
- {
- userId: () =>
- {userId},
- a: (sub) =>
-
- {sub}
- ,
- },
- );
+ let helpTextUntranslated;
+ if (this.props.kind === KIND_INVITE) {
+ if (identityServersEnabled) {
+ helpTextUntranslated = _td("Invite someone using their name, email address, username " +
+ "(like ) or share this room.");
+ } else {
+ helpTextUntranslated = _td("Invite someone using their name, username " +
+ "(like ) or share this room.");
+ }
+ } else { // KIND_SPACE_INVITE
+ if (identityServersEnabled) {
+ helpTextUntranslated = _td("Invite someone using their name, email address, username " +
+ "(like ) or share this space.");
+ } else {
+ helpTextUntranslated = _td("Invite someone using their name, username " +
+ "(like ) or share this space.");
+ }
}
+ helpText = _t(helpTextUntranslated, {}, {
+ userId: () =>
+ {userId},
+ a: (sub) =>
+ {sub},
+ });
+
buttonText = _t("Invite");
goButtonFn = this._inviteUsers;
} else if (this.props.kind === KIND_CALL_TRANSFER) {
diff --git a/src/components/views/spaces/SpacePublicShare.tsx b/src/components/views/spaces/SpacePublicShare.tsx
new file mode 100644
index 0000000000..064d1640a2
--- /dev/null
+++ b/src/components/views/spaces/SpacePublicShare.tsx
@@ -0,0 +1,65 @@
+/*
+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, {useState} from "react";
+import {Room} from "matrix-js-sdk/src/models/room";
+
+import {_t} from "../../../languageHandler";
+import AccessibleButton from "../elements/AccessibleButton";
+import {copyPlaintext} from "../../../utils/strings";
+import {sleep} from "../../../utils/promise";
+import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks";
+import {showSpaceInviteDialog} from "../../../RoomInvite";
+
+interface IProps {
+ space: Room;
+ onFinished(): void;
+}
+
+const SpacePublicShare = ({ space, onFinished }: IProps) => {
+ const [copiedText, setCopiedText] = useState(_t("Click to copy"));
+
+ return
+ {
+ const permalinkCreator = new RoomPermalinkCreator(space);
+ permalinkCreator.load();
+ const success = await copyPlaintext(permalinkCreator.forRoom());
+ const text = success ? _t("Copied!") : _t("Failed to copy");
+ setCopiedText(text);
+ await sleep(10);
+ if (copiedText === text) { // if the text hasn't changed by another click then clear it after some time
+ setCopiedText(_t("Click to copy"));
+ }
+ }}
+ >
+ { _t("Share invite link") }
+ { copiedText }
+
+ {
+ showSpaceInviteDialog(space.roomId);
+ onFinished();
+ }}
+ >
+ { _t("Invite by email or username") }
+
+
;
+};
+
+export default SpacePublicShare;
diff --git a/src/dispatcher/payloads/SetRightPanelPhasePayload.ts b/src/dispatcher/payloads/SetRightPanelPhasePayload.ts
index 4126e8a669..430fad6145 100644
--- a/src/dispatcher/payloads/SetRightPanelPhasePayload.ts
+++ b/src/dispatcher/payloads/SetRightPanelPhasePayload.ts
@@ -15,6 +15,7 @@ limitations under the License.
*/
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
+import { Room } from "matrix-js-sdk/src/models/room";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
import { ActionPayload } from "../payloads";
@@ -35,4 +36,5 @@ export interface SetRightPanelPhaseRefireParams {
// XXX: The type for event should 'view_3pid_invite' action's payload
event?: any;
widgetId?: string;
+ space?: Room;
}
diff --git a/src/hooks/useStateArray.ts b/src/hooks/useStateArray.ts
new file mode 100644
index 0000000000..e8ff6efff0
--- /dev/null
+++ b/src/hooks/useStateArray.ts
@@ -0,0 +1,29 @@
+/*
+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 {useState} from "react";
+
+// Hook to simplify managing state of arrays of a common type
+export const useStateArray = (initialSize: number, initialState: T | T[]): [T[], (i: number, v: T) => void] => {
+ const [data, setData] = useState(() => {
+ return Array.isArray(initialState) ? initialState : new Array(initialSize).fill(initialState);
+ });
+ return [data, (index: number, value: T) => setData(data => {
+ const copy = [...data];
+ copy[index] = value;
+ return copy;
+ })]
+};
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 1b29e65b40..ae12b195a0 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -998,6 +998,11 @@
"Expand space panel": "Expand space panel",
"Collapse space panel": "Collapse space panel",
"Home": "Home",
+ "Click to copy": "Click to copy",
+ "Copied!": "Copied!",
+ "Failed to copy": "Failed to copy",
+ "Share invite link": "Share invite link",
+ "Invite by email or username": "Invite by email or username",
"Remove": "Remove",
"This bridge was provisioned by .": "This bridge was provisioned by .",
"This bridge is managed by .": "This bridge is managed by .",
@@ -1814,8 +1819,6 @@
"%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s changed the room avatar to ",
"Click here to see older messages.": "Click here to see older messages.",
"This room is a continuation of another conversation.": "This room is a continuation of another conversation.",
- "Copied!": "Copied!",
- "Failed to copy": "Failed to copy",
"Add an Integration": "Add an Integration",
"You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?",
"Edited at %(date)s": "Edited at %(date)s",
@@ -2164,8 +2167,11 @@
"Start a conversation with someone using their name or username (like ).": "Start a conversation with someone using their name or username (like ).",
"This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here": "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here",
"Go": "Go",
+ "Invite to this space": "Invite to this space",
"Invite someone using their name, email address, username (like ) or share this room.": "Invite someone using their name, email address, username (like ) or share this room.",
"Invite someone using their name, username (like ) or share this room.": "Invite someone using their name, username (like ) or share this room.",
+ "Invite someone using their name, email address, username (like ) or share this space.": "Invite someone using their name, email address, username (like ) or share this space.",
+ "Invite someone using their name, username (like ) or share this space.": "Invite someone using their name, username (like ) or share this space.",
"Transfer": "Transfer",
"a new master key signature": "a new master key signature",
"a new cross-signing key signature": "a new cross-signing key signature",
@@ -2550,6 +2556,37 @@
"Failed to reject invite": "Failed to reject invite",
"You have %(count)s unread notifications in a prior version of this room.|other": "You have %(count)s unread notifications in a prior version of this room.",
"You have %(count)s unread notifications in a prior version of this room.|one": "You have %(count)s unread notification in a prior version of this room.",
+ "Accept Invite": "Accept Invite",
+ "%(count)s members|other": "%(count)s members",
+ "%(count)s members|one": "%(count)s member",
+ " invited you to ": " invited you to ",
+ "You have been invited to ": "You have been invited to ",
+ "Your public space ": "Your public space ",
+ "Your private space ": "Your private space ",
+ "Welcome to ": "Welcome to ",
+ "Random": "Random",
+ "Support": "Support",
+ "Room name": "Room name",
+ "Failed to create initial space rooms": "Failed to create initial space rooms",
+ "Skip for now": "Skip for now",
+ "Creating rooms...": "Creating rooms...",
+ "Share your public space": "Share your public space",
+ "At the moment only you can see it.": "At the moment only you can see it.",
+ "Finish": "Finish",
+ "Who are you working with?": "Who are you working with?",
+ "Ensure the right people have access to the space.": "Ensure the right people have access to the space.",
+ "Just Me": "Just Me",
+ "A private space just for you": "A private space just for you",
+ "Me and my teammates": "Me and my teammates",
+ "A private space for you and your teammates": "A private space for you and your teammates",
+ "Failed to invite the following users to your space: %(csvUsers)s": "Failed to invite the following users to your space: %(csvUsers)s",
+ "Invite your teammates": "Invite your teammates",
+ "Invite by username": "Invite by username",
+ "Inviting...": "Inviting...",
+ "What discussions do you want to have?": "What discussions do you want to have?",
+ "We'll create rooms for each topic.": "We'll create rooms for each topic.",
+ "What projects are you working on?": "What projects are you working on?",
+ "We'll create rooms for each of them. You can add existing rooms after setup.": "We'll create rooms for each of them. You can add existing rooms after setup.",
"Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.",
"Tried to load a specific point in this room's timeline, but was unable to find it.": "Tried to load a specific point in this room's timeline, but was unable to find it.",
"Failed to load timeline position": "Failed to load timeline position",
diff --git a/src/stores/RightPanelStorePhases.ts b/src/stores/RightPanelStorePhases.ts
index 11b51dfc2d..aea78c7460 100644
--- a/src/stores/RightPanelStorePhases.ts
+++ b/src/stores/RightPanelStorePhases.ts
@@ -31,6 +31,11 @@ export enum RightPanelPhases {
GroupRoomList = 'GroupRoomList',
GroupRoomInfo = 'GroupRoomInfo',
GroupMemberInfo = 'GroupMemberInfo',
+
+ // Space stuff
+ SpaceMemberList = "SpaceMemberList",
+ SpaceMemberInfo = "SpaceMemberInfo",
+ Space3pidMemberInfo = "Space3pidMemberInfo",
}
// These are the phases that are safe to persist (the ones that don't require additional
@@ -43,3 +48,10 @@ export const RIGHT_PANEL_PHASES_NO_ARGS = [
RightPanelPhases.GroupMemberList,
RightPanelPhases.GroupRoomList,
];
+
+// Subset of phases visible in the Space View
+export const RIGHT_PANEL_SPACE_PHASES = [
+ RightPanelPhases.SpaceMemberList,
+ RightPanelPhases.Space3pidMemberInfo,
+ RightPanelPhases.SpaceMemberInfo,
+];
diff --git a/src/utils/space.ts b/src/utils/space.ts
new file mode 100644
index 0000000000..85faedf5d6
--- /dev/null
+++ b/src/utils/space.ts
@@ -0,0 +1,28 @@
+/*
+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 {Room} from "matrix-js-sdk/src/models/room";
+import {MatrixClient} from "matrix-js-sdk/src/client";
+import {EventType} from "matrix-js-sdk/src/@types/event";
+
+export const shouldShowSpaceSettings = (cli: MatrixClient, space: Room) => {
+ const userId = cli.getUserId();
+ return space.getMyMembership() === "join"
+ && (space.currentState.maySendStateEvent(EventType.RoomAvatar, userId)
+ || space.currentState.maySendStateEvent(EventType.RoomName, userId)
+ || space.currentState.maySendStateEvent(EventType.RoomTopic, userId)
+ || space.currentState.maySendStateEvent(EventType.RoomJoinRules, userId));
+};
From 1a7a0e619d72eb3c0ec3f3626ebd802195a27a07 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Mon, 1 Mar 2021 19:05:50 +0000
Subject: [PATCH 4/4] extend createRoom for creating rooms in a space
---
src/createRoom.ts | 17 +++++++++++++++++
src/utils/permalinks/Permalinks.js | 16 ++++++++++++++--
src/utils/space.ts | 11 +++++++++++
3 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/src/createRoom.ts b/src/createRoom.ts
index 00a970eedc..a5343076ac 100644
--- a/src/createRoom.ts
+++ b/src/createRoom.ts
@@ -17,6 +17,7 @@ limitations under the License.
import { MatrixClient } from "matrix-js-sdk/src/client";
import { Room } from "matrix-js-sdk/src/models/room";
+import { EventType } from "matrix-js-sdk/src/@types/event";
import { MatrixClientPeg } from './MatrixClientPeg';
import Modal from './Modal';
@@ -31,6 +32,8 @@ import GroupStore from "./stores/GroupStore";
import CountlyAnalytics from "./CountlyAnalytics";
import { isJoinedOrNearlyJoined } from "./utils/membership";
import { VIRTUAL_ROOM_EVENT_TYPE } from "./CallHandler";
+import SpaceStore from "./stores/SpaceStore";
+import { makeSpaceParentEvent } from "./utils/space";
// we define a number of interfaces which take their names from the js-sdk
/* eslint-disable camelcase */
@@ -84,6 +87,7 @@ export interface IOpts {
inlineErrors?: boolean;
andView?: boolean;
associatedWithCommunity?: string;
+ parentSpace?: Room;
}
/**
@@ -175,6 +179,16 @@ export default function createRoom(opts: IOpts): Promise {
});
}
+ if (opts.parentSpace) {
+ opts.createOpts.initial_state.push(makeSpaceParentEvent(opts.parentSpace, true));
+ opts.createOpts.initial_state.push({
+ type: EventType.RoomHistoryVisibility,
+ content: {
+ "history_visibility": opts.createOpts.preset === Preset.PublicChat ? "world_readable" : "invited",
+ },
+ });
+ }
+
let modal;
if (opts.spinner) modal = Modal.createDialog(Loader, null, 'mx_Dialog_spinner');
@@ -189,6 +203,9 @@ export default function createRoom(opts: IOpts): Promise {
return Promise.resolve();
}
}).then(() => {
+ if (opts.parentSpace) {
+ return SpaceStore.instance.addRoomToSpace(opts.parentSpace, roomId, [client.getDomain()], true);
+ }
if (opts.associatedWithCommunity) {
return GroupStore.addRoomToGroup(opts.associatedWithCommunity, roomId, false);
}
diff --git a/src/utils/permalinks/Permalinks.js b/src/utils/permalinks/Permalinks.js
index 086abc669d..bcf4d87136 100644
--- a/src/utils/permalinks/Permalinks.js
+++ b/src/utils/permalinks/Permalinks.js
@@ -14,9 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import {MatrixClientPeg} from "../../MatrixClientPeg";
import isIp from "is-ip";
-import * as utils from 'matrix-js-sdk/src/utils';
+import * as utils from "matrix-js-sdk/src/utils";
+import {Room} from "matrix-js-sdk/src/models/room";
+
+import {MatrixClientPeg} from "../../MatrixClientPeg";
import SpecPermalinkConstructor, {baseUrl as matrixtoBaseUrl} from "./SpecPermalinkConstructor";
import PermalinkConstructor, {PermalinkParts} from "./PermalinkConstructor";
import ElementPermalinkConstructor from "./ElementPermalinkConstructor";
@@ -121,6 +123,10 @@ export class RoomPermalinkCreator {
this._started = false;
}
+ get serverCandidates() {
+ return this._serverCandidates;
+ }
+
isStarted() {
return this._started;
}
@@ -451,3 +457,9 @@ function isHostnameIpAddress(hostname) {
return isIp(hostname);
}
+
+export const calculateRoomVia = (room: Room) => {
+ const permalinkCreator = new RoomPermalinkCreator(room);
+ permalinkCreator.load();
+ return permalinkCreator.serverCandidates;
+};
diff --git a/src/utils/space.ts b/src/utils/space.ts
index 85faedf5d6..98801cabd0 100644
--- a/src/utils/space.ts
+++ b/src/utils/space.ts
@@ -18,6 +18,8 @@ import {Room} from "matrix-js-sdk/src/models/room";
import {MatrixClient} from "matrix-js-sdk/src/client";
import {EventType} from "matrix-js-sdk/src/@types/event";
+import {calculateRoomVia} from "../utils/permalinks/Permalinks";
+
export const shouldShowSpaceSettings = (cli: MatrixClient, space: Room) => {
const userId = cli.getUserId();
return space.getMyMembership() === "join"
@@ -26,3 +28,12 @@ export const shouldShowSpaceSettings = (cli: MatrixClient, space: Room) => {
|| space.currentState.maySendStateEvent(EventType.RoomTopic, userId)
|| space.currentState.maySendStateEvent(EventType.RoomJoinRules, userId));
};
+
+export const makeSpaceParentEvent = (room: Room, canonical = false) => ({
+ type: EventType.SpaceParent,
+ content: {
+ "via": calculateRoomVia(room),
+ "canonical": canonical,
+ },
+ state_key: room.roomId,
+});