From 2818cdf3d4bf3ad990317c7629b063a40261642e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 22 Mar 2021 17:46:50 +0000 Subject: [PATCH 01/24] Fix space hierarchy exploding when encountering an empty subspace --- src/components/structures/SpaceRoomDirectory.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/SpaceRoomDirectory.tsx b/src/components/structures/SpaceRoomDirectory.tsx index 0a53f38238..ab273887c2 100644 --- a/src/components/structures/SpaceRoomDirectory.tsx +++ b/src/components/structures/SpaceRoomDirectory.tsx @@ -260,7 +260,7 @@ export const HierarchyLevel = ({ const space = cli.getRoom(spaceId); const hasPermissions = space?.currentState.maySendStateEvent(EventType.SpaceChild, cli.getUserId()) - const sortedChildren = sortBy([...relations.get(spaceId)?.values()], ev => ev.content.order || null); + const sortedChildren = sortBy([...(relations.get(spaceId)?.values() || [])], ev => ev.content.order || null); const [subspaces, childRooms] = sortedChildren.reduce((result, ev: ISpaceSummaryEvent) => { const roomId = ev.state_key; if (!rooms.has(roomId)) return result; From 796bfd851de39878ae8d082a9a3eb72f3d53cd1a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 22 Mar 2021 17:47:48 +0000 Subject: [PATCH 02/24] Fix left spaces not disappearing from the space panel --- src/stores/SpaceStore.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/stores/SpaceStore.tsx b/src/stores/SpaceStore.tsx index b82acfd0ed..dba3f1d8a9 100644 --- a/src/stores/SpaceStore.tsx +++ b/src/stores/SpaceStore.tsx @@ -196,13 +196,16 @@ export class SpaceStoreClass extends AsyncStoreWithClient { }; public rebuild = throttle(() => { // exported for tests - const visibleRooms = this.matrixClient.getVisibleRooms(); + // get all most-upgraded rooms & spaces except spaces which have been left (historical) + const visibleRooms = this.matrixClient.getVisibleRooms().filter(r => { + return !r.isSpaceRoom() || r.getMyMembership() === "join"; + }); + + const unseenChildren = new Set(visibleRooms); + const backrefs = new EnhancedMap>(); // Sort spaces by room ID to force the loop breaking to be deterministic - const spaces = sortBy(this.getSpaces(), space => space.roomId); - const unseenChildren = new Set([...visibleRooms, ...spaces]); - - const backrefs = new EnhancedMap>(); + const spaces = sortBy(visibleRooms.filter(r => r.isSpaceRoom()), space => space.roomId); // TODO handle cleaning up links when a Space is removed spaces.forEach(space => { From fb46815b6a5bbc2b17286f67b3fef70af53111bc Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 13:15:31 +0000 Subject: [PATCH 03/24] Spaces move away from Form Buttons --- res/css/structures/_SpaceRoomView.scss | 2 +- .../views/dialogs/_SpaceSettingsDialog.scss | 2 +- res/css/views/spaces/_SpaceCreateMenu.scss | 2 +- src/components/structures/SpaceRoomView.tsx | 41 ++++++++++++------- .../dialogs/AddExistingToSpaceDialog.tsx | 9 ++-- .../views/dialogs/SpaceSettingsDialog.tsx | 12 +++--- .../views/spaces/SpaceCreateMenu.tsx | 9 ++-- 7 files changed, 44 insertions(+), 33 deletions(-) diff --git a/res/css/structures/_SpaceRoomView.scss b/res/css/structures/_SpaceRoomView.scss index a7ce630b96..080773b49b 100644 --- a/res/css/structures/_SpaceRoomView.scss +++ b/res/css/structures/_SpaceRoomView.scss @@ -89,7 +89,7 @@ $SpaceRoomViewInnerWidth: 428px; width: $SpaceRoomViewInnerWidth; text-align: right; // button alignment right - .mx_FormButton { + .mx_AccessibleButton_hasKind { padding: 8px 22px; margin-left: 16px; } diff --git a/res/css/views/dialogs/_SpaceSettingsDialog.scss b/res/css/views/dialogs/_SpaceSettingsDialog.scss index c1fa539e9b..6e5fd9c8c8 100644 --- a/res/css/views/dialogs/_SpaceSettingsDialog.scss +++ b/res/css/views/dialogs/_SpaceSettingsDialog.scss @@ -49,7 +49,7 @@ limitations under the License. } } - .mx_FormButton { + .mx_AccessibleButton_hasKind { padding: 8px 22px; } } diff --git a/res/css/views/spaces/_SpaceCreateMenu.scss b/res/css/views/spaces/_SpaceCreateMenu.scss index bea39e2389..ef3fea351b 100644 --- a/res/css/views/spaces/_SpaceCreateMenu.scss +++ b/res/css/views/spaces/_SpaceCreateMenu.scss @@ -79,7 +79,7 @@ $spacePanelWidth: 71px; } } - .mx_FormButton { + .mx_AccessibleButton_kind_primary { padding: 8px 22px; margin-left: auto; display: block; diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 95846d8e21..46ff37dc14 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -26,7 +26,6 @@ import AccessibleButton from "../views/elements/AccessibleButton"; import RoomName from "../views/elements/RoomName"; import RoomTopic from "../views/elements/RoomTopic"; import InlineSpinner from "../views/elements/InlineSpinner"; -import FormButton from "../views/elements/FormButton"; import {inviteMultipleToRoom, showRoomInviteDialog} from "../../RoomInvite"; import {useRoomMembers} from "../../hooks/useRoomMembers"; import createRoom, {IOpts, Preset} from "../../createRoom"; @@ -124,30 +123,36 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) => } joinButtons = <> - { setBusy(true); onRejectButtonClicked(); - }} /> - + { _t("Reject") } + + { setBusy(true); onJoinButtonClicked(); }} - /> + > + { _t("Accept") } + ; } else { joinButtons = ( - { setBusy(true); onJoinButtonClicked(); }} - /> + > + { _t("Join") } + ) } @@ -407,11 +412,13 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => { { fields }
- + > + { buttonLabel } +
; }; @@ -426,7 +433,9 @@ const SpaceSetupPublicShare = ({ space, onFinished }) => {
- + + { _t("Go to my first room") } +
; }; @@ -545,7 +554,9 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
- + + { buttonLabel } +
; }; diff --git a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx index 500637244a..e3e28e4fbe 100644 --- a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx +++ b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx @@ -22,7 +22,6 @@ import {MatrixClient} from "matrix-js-sdk/src/client"; import {_t} from '../../../languageHandler'; import {IDialogProps} from "./IDialogProps"; import BaseDialog from "./BaseDialog"; -import FormButton from "../elements/FormButton"; import Dropdown from "../elements/Dropdown"; import SearchBox from "../../structures/SearchBox"; import SpaceStore from "../../../stores/SpaceStore"; @@ -185,8 +184,8 @@ const AddExistingToSpaceDialog: React.FC = ({ matrixClient: cli, space, - { setBusy(true); @@ -200,7 +199,9 @@ const AddExistingToSpaceDialog: React.FC = ({ matrixClient: cli, space, } setBusy(false); }} - /> + > + { busy ? _t("Adding...") : _t("Add") } + ; }; diff --git a/src/components/views/dialogs/SpaceSettingsDialog.tsx b/src/components/views/dialogs/SpaceSettingsDialog.tsx index f6bf5b87e6..b016e320eb 100644 --- a/src/components/views/dialogs/SpaceSettingsDialog.tsx +++ b/src/components/views/dialogs/SpaceSettingsDialog.tsx @@ -28,7 +28,6 @@ import {getTopic} from "../elements/RoomTopic"; import {avatarUrlForRoom} from "../../../Avatar"; import ToggleSwitch from "../elements/ToggleSwitch"; import AccessibleButton from "../elements/AccessibleButton"; -import FormButton from "../elements/FormButton"; import Modal from "../../../Modal"; import defaultDispatcher from "../../../dispatcher/dispatcher"; import {allSettled} from "../../../utils/promise"; @@ -134,16 +133,17 @@ const SpaceSettingsDialog: React.FC = ({ matrixClient: cli, space, onFin /> - { defaultDispatcher.dispatch({ action: "leave_room", room_id: space.roomId, }); }} - /> + > + { _t("Leave Space") } +
Modal.createDialog(DevtoolsDialog, {roomId: space.roomId})}> @@ -152,7 +152,9 @@ const SpaceSettingsDialog: React.FC = ({ matrixClient: cli, space, onFin { _t("Cancel") } - + + { busy ? _t("Saving...") : _t("Save Changes") } +
; diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx index 879cf929e0..6269de1c50 100644 --- a/src/components/views/spaces/SpaceCreateMenu.tsx +++ b/src/components/views/spaces/SpaceCreateMenu.tsx @@ -21,7 +21,6 @@ import {EventType, RoomType, RoomCreateTypeField} from "matrix-js-sdk/src/@types 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"; @@ -148,11 +147,9 @@ const SpaceCreateMenu = ({ onFinished }) => { - + + { busy ? _t("Creating...") : _t("Create") } + ; } From 4e9a2df3b0689e11dfb18241a5c8a86a6d6b4a2f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 14:00:52 +0000 Subject: [PATCH 04/24] Spaces autofocus and prefill the search box --- src/components/structures/SearchBox.js | 5 ++++- src/components/structures/SpaceRoomDirectory.tsx | 2 ++ src/components/views/dialogs/AddExistingToSpaceDialog.tsx | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js index 6daa8526bc..abeb858274 100644 --- a/src/components/structures/SearchBox.js +++ b/src/components/structures/SearchBox.js @@ -32,6 +32,8 @@ export default class SearchBox extends React.Component { onKeyDown: PropTypes.func, className: PropTypes.string, placeholder: PropTypes.string.isRequired, + autoFocus: PropTypes.bool, + initialValue: PropTypes.string, // If true, the search box will focus and clear itself // on room search focus action (it would be nicer to take @@ -49,7 +51,7 @@ export default class SearchBox extends React.Component { this._search = createRef(); this.state = { - searchTerm: "", + searchTerm: this.props.initialValue || "", blurred: true, }; } @@ -158,6 +160,7 @@ export default class SearchBox extends React.Component { onBlur={this._onBlur} placeholder={ placeholder } autoComplete="off" + autoFocus={this.props.autoFocus} /> { clearButton } diff --git a/src/components/structures/SpaceRoomDirectory.tsx b/src/components/structures/SpaceRoomDirectory.tsx index ab273887c2..2fb0101f88 100644 --- a/src/components/structures/SpaceRoomDirectory.tsx +++ b/src/components/structures/SpaceRoomDirectory.tsx @@ -570,6 +570,8 @@ const SpaceRoomDirectory: React.FC = ({ space, initialText = "", onFinis className="mx_textinput_icon mx_textinput_search" placeholder={ _t("Search names and description") } onSearch={setQuery} + autoFocus={true} + initialValue={initialText} /> { content } diff --git a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx index e3e28e4fbe..fec1a178ca 100644 --- a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx +++ b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx @@ -127,6 +127,7 @@ const AddExistingToSpaceDialog: React.FC = ({ matrixClient: cli, space, className="mx_textinput_icon mx_textinput_search" placeholder={ _t("Filter your rooms and spaces") } onSearch={setQuery} + autoComplete={true} /> { spaces.length > 0 ? ( From d8737913693551141841100554527e7515423e8f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 14:01:24 +0000 Subject: [PATCH 05/24] update comments --- src/stores/SpaceStore.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stores/SpaceStore.tsx b/src/stores/SpaceStore.tsx index dba3f1d8a9..e4b537169e 100644 --- a/src/stores/SpaceStore.tsx +++ b/src/stores/SpaceStore.tsx @@ -195,7 +195,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { return this.spaceFilteredRooms.get(space?.roomId || HOME_SPACE) || new Set(); }; - public rebuild = throttle(() => { // exported for tests + private rebuild = throttle(() => { // get all most-upgraded rooms & spaces except spaces which have been left (historical) const visibleRooms = this.matrixClient.getVisibleRooms().filter(r => { return !r.isSpaceRoom() || r.getMyMembership() === "join"; @@ -204,7 +204,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { const unseenChildren = new Set(visibleRooms); const backrefs = new EnhancedMap>(); - // Sort spaces by room ID to force the loop breaking to be deterministic + // Sort spaces by room ID to force the cycle breaking to be deterministic const spaces = sortBy(visibleRooms.filter(r => r.isSpaceRoom()), space => space.roomId); // TODO handle cleaning up links when a Space is removed @@ -219,7 +219,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { const [rootSpaces, orphanedRooms] = partitionSpacesAndRooms(Array.from(unseenChildren)); - // untested algorithm to handle full-cycles + // somewhat algorithm to handle full-cycles const detachedNodes = new Set(spaces); const markTreeChildren = (rootSpace: Room, unseen: Set) => { From f7a3805eed1b987d644f81cbdcd3d3c14fc32709 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 14:02:25 +0000 Subject: [PATCH 06/24] Fix styling inconsistency in space room view --- res/css/structures/_SpaceRoomView.scss | 2 +- src/components/structures/SpaceRoomView.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_SpaceRoomView.scss b/res/css/structures/_SpaceRoomView.scss index 080773b49b..3d3b5d1bb8 100644 --- a/res/css/structures/_SpaceRoomView.scss +++ b/res/css/structures/_SpaceRoomView.scss @@ -22,7 +22,7 @@ $SpaceRoomViewInnerWidth: 428px; width: 432px; box-sizing: border-box; border-radius: 8px; - border: 1px solid $input-darker-bg-color; + border: 1px solid $space-button-outline-color; font-size: $font-15px; margin: 20px 0; diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 46ff37dc14..0c2f1638d1 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -426,7 +426,7 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => { const SpaceSetupPublicShare = ({ space, onFinished }) => { return

{ _t("Share %(name)s", { name: space.name }) }

-
+
{ _t("It's just you at the moment, it will be even better with others.") }
From 6e0ab8616866e0d37a9998837e847e131cab3cd3 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 14:10:26 +0000 Subject: [PATCH 07/24] Small usability tweaks to the add existing to space dialog --- .../dialogs/_AddExistingToSpaceDialog.scss | 25 ++++++++--- .../dialogs/AddExistingToSpaceDialog.tsx | 44 +++++++++---------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/res/css/views/dialogs/_AddExistingToSpaceDialog.scss b/res/css/views/dialogs/_AddExistingToSpaceDialog.scss index 0c9d8e3840..a7cfd7bde6 100644 --- a/res/css/views/dialogs/_AddExistingToSpaceDialog.scss +++ b/res/css/views/dialogs/_AddExistingToSpaceDialog.scss @@ -28,22 +28,23 @@ limitations under the License. flex-direction: column; flex-wrap: nowrap; min-height: 0; + height: 80vh; .mx_Dialog_title { display: flex; - .mx_BaseAvatar { - display: inline-flex; - margin: 5px 16px 5px 5px; - vertical-align: middle; - } - .mx_BaseAvatar_image { border-radius: 8px; margin: 0; vertical-align: unset; } + .mx_BaseAvatar { + display: inline-flex; + margin: 5px 16px 5px 5px; + vertical-align: middle; + } + > div { > h1 { font-weight: $font-semi-bold; @@ -101,6 +102,7 @@ limitations under the License. .mx_SearchBox { margin: 0; + flex-grow: 0; } .mx_AddExistingToSpaceDialog_errorText { @@ -112,7 +114,10 @@ limitations under the License. } .mx_AddExistingToSpaceDialog_content { + flex-grow: 1; + .mx_AddExistingToSpaceDialog_noResults { + display: block; margin-top: 24px; } } @@ -162,8 +167,14 @@ limitations under the License. > span { flex-grow: 1; - font-size: $font-12px; + font-size: $font-14px; line-height: $font-15px; + font-weight: $font-semi-bold; + + .mx_AccessibleButton { + font-size: inherit; + display: inline-block; + } > * { vertical-align: middle; diff --git a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx index fec1a178ca..04bec39238 100644 --- a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx +++ b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx @@ -109,7 +109,7 @@ const AddExistingToSpaceDialog: React.FC = ({ matrixClient: cli, space, const title =
-

{ _t("Add existing spaces/rooms") }

+

{ _t("Add existing rooms") }

{ spaceOptionSection }
; @@ -130,27 +130,6 @@ const AddExistingToSpaceDialog: React.FC = ({ matrixClient: cli, space, autoComplete={true} /> - { spaces.length > 0 ? ( -
-

{ _t("Spaces") }

- { spaces.map(space => { - return { - if (checked) { - selectedToAdd.add(space); - } else { - selectedToAdd.delete(space); - } - setSelectedToAdd(new Set(selectedToAdd)); - }} - />; - }) } -
- ) : null } - { rooms.length > 0 ? (

{ _t("Rooms") }

@@ -172,6 +151,27 @@ const AddExistingToSpaceDialog: React.FC = ({ matrixClient: cli, space,
) : undefined } + { spaces.length > 0 ? ( +
+

{ _t("Spaces") }

+ { spaces.map(space => { + return { + if (checked) { + selectedToAdd.add(space); + } else { + selectedToAdd.delete(space); + } + setSelectedToAdd(new Set(selectedToAdd)); + }} + />; + }) } +
+ ) : null } + { spaces.length + rooms.length < 1 ? { _t("No results") } : undefined } From a2a1e37fa3cb3011508e93043ce507b6a0b64249 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 14:18:06 +0000 Subject: [PATCH 08/24] Add prompt to bottom of room list to invite to space --- res/css/views/rooms/_RoomList.scss | 24 +++++++--- res/img/element-icons/roomlist/browse.svg | 4 ++ src/components/views/rooms/RoomList.tsx | 55 +++++++++++++++++++++-- 3 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 res/img/element-icons/roomlist/browse.svg diff --git a/res/css/views/rooms/_RoomList.scss b/res/css/views/rooms/_RoomList.scss index d49ed4b736..641b434af4 100644 --- a/res/css/views/rooms/_RoomList.scss +++ b/res/css/views/rooms/_RoomList.scss @@ -35,28 +35,32 @@ limitations under the License. margin: 4px 12px 4px; padding-top: 12px; border-top: 1px solid $tertiary-fg-color; - font-size: $font-13px; + font-size: $font-14px; div:first-child { font-weight: $font-semi-bold; + line-height: $font-18px; + color: $primary-fg-color; } .mx_AccessibleButton { - color: $secondary-fg-color; + color: $primary-fg-color; position: relative; - padding: 0 0 0 24px; + padding: 8px 8px 8px 32px; font-size: inherit; - margin-top: 8px; + margin-top: 12px; display: block; text-align: start; + background-color: $roomlist-button-bg-color; + border-radius: 4px; &::before { content: ''; width: 16px; height: 16px; position: absolute; - top: 0; - left: 0; + top: 8px; + left: 8px; background: $secondary-fg-color; mask-position: center; mask-size: contain; @@ -70,5 +74,13 @@ limitations under the License. &.mx_RoomList_explorePrompt_explore::before { mask-image: url('$(res)/img/element-icons/roomlist/explore.svg'); } + + &.mx_RoomList_explorePrompt_spaceInvite::before { + mask-image: url('$(res)/img/element-icons/room/invite.svg'); + } + + &.mx_RoomList_explorePrompt_spaceExplore::before { + mask-image: url('$(res)/img/element-icons/roomlist/browse.svg'); + } } } diff --git a/res/img/element-icons/roomlist/browse.svg b/res/img/element-icons/roomlist/browse.svg new file mode 100644 index 0000000000..04714e2881 --- /dev/null +++ b/res/img/element-icons/roomlist/browse.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx index 4378154d8f..01affc8b2f 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/RoomList.tsx @@ -20,6 +20,7 @@ import React, { ReactComponentElement } from "react"; import { Dispatcher } from "flux"; import { Room } from "matrix-js-sdk/src/models/room"; import * as fbEmitter from "fbemitter"; +import { EventType } from "matrix-js-sdk/src/@types/event"; import { _t, _td } from "../../../languageHandler"; import { RovingTabIndexProvider } from "../../../accessibility/RovingTabIndex"; @@ -48,12 +49,15 @@ import { IconizedContextMenuOption, IconizedContextMenuOptionList } from "../con import AccessibleButton from "../elements/AccessibleButton"; import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore"; import CallHandler from "../../../CallHandler"; -import SpaceStore, { SUGGESTED_ROOMS } from "../../../stores/SpaceStore"; +import SpaceStore, {SUGGESTED_ROOMS, UPDATE_SELECTED_SPACE} from "../../../stores/SpaceStore"; import { showAddExistingRooms, showCreateNewRoom } from "../../../utils/space"; -import { EventType } from "matrix-js-sdk/src/@types/event"; import {replaceableComponent} from "../../../utils/replaceableComponent"; import RoomAvatar from "../avatars/RoomAvatar"; import { ISpaceSummaryRoom } from "../../structures/SpaceRoomDirectory"; +import { showRoomInviteDialog } from "../../../RoomInvite"; +import Modal from "../../../Modal"; +import SpacePublicShare from "../spaces/SpacePublicShare"; +import InfoDialog from "../dialogs/InfoDialog"; interface IProps { onKeyDown: (ev: React.KeyboardEvent) => void; @@ -68,6 +72,7 @@ interface IState { sublists: ITagMap; isNameFiltering: boolean; currentRoomId?: string; + activeSpace: Room; suggestedRooms: ISpaceSummaryRoom[]; } @@ -194,7 +199,7 @@ const TAG_AESTHETICS: ITagAestheticsMap = { : _t("You do not have permissions to add rooms to this space")} /> { e.preventDefault(); @@ -282,6 +287,7 @@ export default class RoomList extends React.PureComponent { this.state = { sublists: {}, isNameFiltering: !!RoomListStore.instance.getFirstNameFilterCondition(), + activeSpace: SpaceStore.instance.activeSpace, suggestedRooms: SpaceStore.instance.suggestedRooms, }; @@ -294,6 +300,7 @@ export default class RoomList extends React.PureComponent { } public componentDidMount(): void { + SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.updateActiveSpace); SpaceStore.instance.on(SUGGESTED_ROOMS, this.updateSuggestedRooms); RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.updateLists); this.customTagStoreRef = CustomRoomTagStore.addListener(this.updateLists); @@ -301,6 +308,7 @@ export default class RoomList extends React.PureComponent { } public componentWillUnmount() { + SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateActiveSpace); SpaceStore.instance.off(SUGGESTED_ROOMS, this.updateSuggestedRooms); RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.updateLists); defaultDispatcher.unregister(this.dispatcherRef); @@ -366,6 +374,10 @@ export default class RoomList extends React.PureComponent { return room; }; + private updateActiveSpace = (activeSpace: Room) => { + this.setState({ activeSpace }); + }; + private updateSuggestedRooms = (suggestedRooms: ISpaceSummaryRoom[]) => { this.setState({ suggestedRooms }); }; @@ -424,6 +436,25 @@ export default class RoomList extends React.PureComponent { dis.dispatch({ action: Action.ViewRoomDirectory, initialText }); }; + private onSpaceInviteClick = () => { + const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search; + if (this.state.activeSpace.getJoinRule() === "public") { + const modal = Modal.createTrackedDialog("Space Invite", "User Menu", InfoDialog, { + title: _t("Invite to %(spaceName)s", { spaceName: this.state.activeSpace.name }), + description: + { _t("Share your public space") } + modal.close()} /> + , + fixedWidth: false, + button: false, + className: "mx_SpacePanel_sharePublicSpace", + hasCloseButton: true, + }); + } else { + showRoomInviteDialog(this.state.activeSpace.roomId, initialText); + } + }; + private renderSuggestedRooms(): ReactComponentElement[] { return this.state.suggestedRooms.map(room => { const name = room.name || room.canonical_alias || room.aliases.pop() || _t("Empty room"); @@ -569,7 +600,23 @@ export default class RoomList extends React.PureComponent { kind="link" onClick={this.onExplore} > - {_t("Explore all public rooms")} + { this.state.activeSpace ? _t("Explore rooms") : _t("Explore all public rooms") } + +
; + } else if (this.state.activeSpace) { + explorePrompt =
+
{ _t("Quick actions") }
+ { this.state.activeSpace.canInvite(MatrixClientPeg.get().getUserId()) && + {_t("Invite people")} + } + + {_t("Explore rooms")}
; } else if (Object.values(this.state.sublists).some(list => list.length > 0)) { From 3df3baea14f931251b1a76cc995a52f0fb2ea7bf Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 14:19:10 +0000 Subject: [PATCH 09/24] Tweak behaviour during space creation --- src/components/structures/SpaceRoomView.tsx | 2 +- src/components/views/spaces/SpacePublicShare.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 0c2f1638d1..16028f0975 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -430,7 +430,7 @@ const SpaceSetupPublicShare = ({ space, onFinished }) => { { _t("It's just you at the moment, it will be even better with others.") }
- +
diff --git a/src/components/views/spaces/SpacePublicShare.tsx b/src/components/views/spaces/SpacePublicShare.tsx index b2d3b7ce29..fa81b75525 100644 --- a/src/components/views/spaces/SpacePublicShare.tsx +++ b/src/components/views/spaces/SpacePublicShare.tsx @@ -26,7 +26,7 @@ import {showRoomInviteDialog} from "../../../RoomInvite"; interface IProps { space: Room; - onFinished(): void; + onFinished?(): void; } const SpacePublicShare = ({ space, onFinished }: IProps) => { @@ -54,7 +54,7 @@ const SpacePublicShare = ({ space, onFinished }: IProps) => { className="mx_SpacePublicShare_inviteButton" onClick={() => { showRoomInviteDialog(space.roomId); - onFinished(); + if (onFinished) onFinished(); }} >

{ _t("Invite people") }

From ea760e8f296cfbcf0b8acc172c7a3b16e8a54adf Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 15:26:56 +0000 Subject: [PATCH 10/24] Fix space room directory behaviour --- src/components/structures/SpaceRoomDirectory.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/components/structures/SpaceRoomDirectory.tsx b/src/components/structures/SpaceRoomDirectory.tsx index 2fb0101f88..877a4283f1 100644 --- a/src/components/structures/SpaceRoomDirectory.tsx +++ b/src/components/structures/SpaceRoomDirectory.tsx @@ -77,7 +77,6 @@ export interface ISpaceSummaryEvent { interface ITileProps { room: ISpaceSummaryRoom; - editing?: boolean; suggested?: boolean; selected?: boolean; numChildRooms?: number; @@ -88,7 +87,6 @@ interface ITileProps { const Tile: React.FC = ({ room, - editing, suggested, selected, hasPermissions, @@ -170,12 +168,6 @@ const Tile: React.FC = ({
; - if (editing) { - return
- { content } -
- } - let childToggle; let childSection; if (children) { @@ -201,7 +193,7 @@ const Tile: React.FC = ({ className={classNames("mx_SpaceRoomDirectory_roomTile", { mx_SpaceRoomDirectory_subspace: room.room_type === RoomType.Space, })} - onClick={hasPermissions ? onToggleClick : onPreviewClick} + onClick={(hasPermissions && onToggleClick) ? onToggleClick : onPreviewClick} > { content } { childToggle } From 65a7d0621d5b14b340a9647049cc85b350ba7381 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 15:30:03 +0000 Subject: [PATCH 11/24] Add invite to space button to room intro --- res/css/views/rooms/_NewRoomIntro.scss | 7 +++- src/components/views/rooms/NewRoomIntro.tsx | 46 +++++++++++++++++---- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/res/css/views/rooms/_NewRoomIntro.scss b/res/css/views/rooms/_NewRoomIntro.scss index 4322ba341c..9c2a428cb3 100644 --- a/res/css/views/rooms/_NewRoomIntro.scss +++ b/res/css/views/rooms/_NewRoomIntro.scss @@ -33,8 +33,13 @@ limitations under the License. .mx_AccessibleButton { line-height: $font-24px; + display: inline-block; - &::before { + & + .mx_AccessibleButton { + margin-left: 12px; + } + + &:not(.mx_AccessibleButton_kind_primary_outline)::before { content: ''; display: inline-block; background-color: $button-fg-color; diff --git a/src/components/views/rooms/NewRoomIntro.tsx b/src/components/views/rooms/NewRoomIntro.tsx index ce426a64ed..c85b9d7868 100644 --- a/src/components/views/rooms/NewRoomIntro.tsx +++ b/src/components/views/rooms/NewRoomIntro.tsx @@ -28,6 +28,7 @@ import defaultDispatcher from "../../../dispatcher/dispatcher"; import {ViewUserPayload} from "../../../dispatcher/payloads/ViewUserPayload"; import {Action} from "../../../dispatcher/actions"; import dis from "../../../dispatcher/dispatcher"; +import SpaceStore from "../../../stores/SpaceStore"; const NewRoomIntro = () => { const cli = useContext(MatrixClientContext); @@ -100,17 +101,48 @@ const NewRoomIntro = () => { }); } - let buttons; - if (room.canInvite(cli.getUserId())) { - const onInviteClick = () => { - dis.dispatch({ action: "view_invite", roomId }); - }; + let parentSpace; + if ( + SpaceStore.instance.activeSpace?.canInvite(cli.getUserId()) && + SpaceStore.instance.getSpaceFilteredRoomIds(SpaceStore.instance.activeSpace).has(room.roomId) + ) { + parentSpace = SpaceStore.instance.activeSpace; + } + let buttons; + if (parentSpace) { buttons =
- + { + dis.dispatch({ action: "view_invite", roomId }); + }} + > + {_t("Invite to %(spaceName)s", { spaceName: parentSpace.name })} + + { room.canInvite(cli.getUserId()) && { + dis.dispatch({ action: "view_invite", roomId }); + }} + > + {_t("Invite to just this room")} + } +
; + } else if (room.canInvite(cli.getUserId())) { + buttons =
+ { + dis.dispatch({ action: "view_invite", roomId }); + }} + > {_t("Invite to this room")} -
+ ; } const avatarUrl = room.currentState.getStateEvents(EventType.RoomAvatar, "")?.getContent()?.url; From 11fbd081f146bce1ce53c07a064300afacf8036f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 15:30:36 +0000 Subject: [PATCH 12/24] Iterate space panel context menu --- .../views/spaces/SpaceTreeLevel.tsx | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index 83bc2296e7..1b86bb7898 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -30,7 +30,12 @@ import IconizedContextMenu, { import {_t} from "../../../languageHandler"; import {ContextMenuTooltipButton} from "../../../accessibility/context_menu/ContextMenuTooltipButton"; import {toRightOf} from "../../structures/ContextMenu"; -import {shouldShowSpaceSettings, showCreateNewRoom, showSpaceSettings} from "../../../utils/space"; +import { + shouldShowSpaceSettings, + showAddExistingRooms, + showCreateNewRoom, + showSpaceSettings, +} from "../../../utils/space"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {ButtonEvent} from "../elements/AccessibleButton"; import defaultDispatcher from "../../../dispatcher/dispatcher"; @@ -127,7 +132,7 @@ export class SpaceItem extends React.PureComponent { if (this.props.space.getJoinRule() === "public") { const modal = Modal.createTrackedDialog("Space Invite", "User Menu", InfoDialog, { - title: _t("Invite members"), + title: _t("Invite to %(spaceName)s", { spaceName: this.props.space.name }), description: { _t("Share your public space") } modal.close()} /> @@ -170,6 +175,14 @@ export class SpaceItem extends React.PureComponent { this.setState({contextMenuPosition: null}); // also close the menu }; + private onAddExistingRoomClick = (ev: ButtonEvent) => { + ev.preventDefault(); + ev.stopPropagation(); + + showAddExistingRooms(this.context, this.props.space); + this.setState({contextMenuPosition: null}); // also close the menu + }; + private onMembersClick = (ev: ButtonEvent) => { ev.preventDefault(); ev.stopPropagation(); @@ -236,15 +249,20 @@ export class SpaceItem extends React.PureComponent { ; } - let newRoomOption; + let newRoomSection; if (this.props.space.currentState.maySendStateEvent(EventType.SpaceChild, userId)) { - newRoomOption = ( + newRoomSection = - ); + + ; } contextMenu = { label={_t("Explore rooms")} onClick={this.onExploreRoomsClick} /> - { newRoomOption } + { newRoomSection } { leaveSection } ; } From 31dd224cc98c4fc7d44ac1296abe338593ca0751 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 15:36:20 +0000 Subject: [PATCH 13/24] Wire up passing through initialText for room invite dialog helper method --- src/RoomInvite.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/RoomInvite.js b/src/RoomInvite.js index 9ae41b851a..aa758ecbdc 100644 --- a/src/RoomInvite.js +++ b/src/RoomInvite.js @@ -49,11 +49,12 @@ export function showStartChatInviteDialog(initialText) { ); } -export function showRoomInviteDialog(roomId) { +export function showRoomInviteDialog(roomId, initialText = "") { // This dialog handles the room creation internally - we don't need to worry about it. Modal.createTrackedDialog( "Invite Users", "", InviteDialog, { kind: KIND_INVITE, + initialText, roomId, }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true, From f340b8f7edfb339cf4c168bdeaf5e73c27d273b4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 16:42:21 +0000 Subject: [PATCH 14/24] Set invite PL requirement for public spaces to 0 explicitly --- src/components/views/spaces/SpaceCreateMenu.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx index 6269de1c50..9ee6edc489 100644 --- a/src/components/views/spaces/SpaceCreateMenu.tsx +++ b/src/components/views/spaces/SpaceCreateMenu.tsx @@ -88,6 +88,7 @@ const SpaceCreateMenu = ({ onFinished }) => { power_level_content_override: { // Only allow Admins to write to the timeline to prevent hidden sync spam events_default: 100, + ...Visibility.Public ? { invite: 0 } : {}, }, }, spinner: false, From 56dbd5f628713816cfdc7773716b41dc5bcb6eb5 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 16:45:53 +0000 Subject: [PATCH 15/24] Remove unused autoJoin prop and move viaServers logic into RVS this fixes the issue where autoJoining ignored viaServers --- src/components/structures/LoggedInView.tsx | 6 ------ src/components/structures/MatrixChat.tsx | 2 -- src/components/structures/RoomView.tsx | 10 ++-------- src/stores/RoomViewStore.tsx | 5 ++++- 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index 60a2bf4ada..20a3b811c5 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -74,7 +74,6 @@ function canElementReceiveInput(el) { interface IProps { matrixClient: MatrixClient; onRegistered: (credentials: IMatrixClientCreds) => Promise; - viaServers?: string[]; hideToSRUsers: boolean; resizeNotifier: ResizeNotifier; // eslint-disable-next-line camelcase @@ -143,9 +142,6 @@ class LoggedInView extends React.Component { // transitioned to PWLU) onRegistered: PropTypes.func, - // Used by the RoomView to handle joining rooms - viaServers: PropTypes.arrayOf(PropTypes.string), - // and lots and lots of other stuff. }; @@ -625,11 +621,9 @@ class LoggedInView extends React.Component { case PageTypes.RoomView: pageElement = { page_type: PageTypes.RoomView, threepidInvite: roomInfo.threepid_invite, roomOobData: roomInfo.oob_data, - viaServers: roomInfo.via_servers, ready: true, roomJustCreatedOpts: roomInfo.justCreatedOpts, }, () => { diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 706cd5ded8..8a9c7cabd9 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -112,10 +112,6 @@ interface IProps { inviterName?: string; }; - // Servers the RoomView can use to try and assist joins - viaServers?: string[]; - - autoJoin?: boolean; resizeNotifier: ResizeNotifier; justCreatedOpts?: IOpts; @@ -450,9 +446,7 @@ export default class RoomView extends React.Component { // now not joined because the js-sdk peeking API will clobber our historical room, // making it impossible to indicate a newly joined room. if (!joining && roomId) { - if (this.props.autoJoin) { - this.onJoinButtonClicked(); - } else if (!room && shouldPeek) { + if (!room && shouldPeek) { console.info("Attempting to peek into room %s", roomId); this.setState({ peekLoading: true, @@ -1123,7 +1117,7 @@ export default class RoomView extends React.Component { const signUrl = this.props.threepidInvite?.signUrl; dis.dispatch({ action: 'join_room', - opts: { inviteSignUrl: signUrl, viaServers: this.props.viaServers }, + opts: { inviteSignUrl: signUrl }, _type: "unknown", // TODO: instrumentation }); return Promise.resolve(); diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index f4c0c1b15c..601c77cdf3 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -273,7 +273,10 @@ class RoomViewStore extends Store { const cli = MatrixClientPeg.get(); const address = this.state.roomAlias || this.state.roomId; try { - await retry(() => cli.joinRoom(address, payload.opts), NUM_JOIN_RETRY, (err) => { + await retry(() => cli.joinRoom(address, { + viaServers: payload.via_servers, + ...payload.opts, + }), NUM_JOIN_RETRY, (err) => { // if we received a Gateway timeout then retry return err.httpStatus === 504; }); From d9f3e70b0bf165ff809d05e4294557cf6ea7ded5 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 16:46:30 +0000 Subject: [PATCH 16/24] Fix joining over federation from Space Home (via servers) --- src/components/structures/SpaceRoomView.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 16028f0975..06b4fe5983 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -258,20 +258,26 @@ const SpaceLanding = ({ space }) => { ; } - const [loading, roomsMap, relations, numRooms] = useAsyncMemo(async () => { + const [loading, roomsMap, relations, viaMap, numRooms] = useAsyncMemo(async () => { try { const data = await cli.getSpaceSummary(space.roomId, undefined, myMembership !== "join"); const parentChildRelations = new EnhancedMap>(); + const viaMap = new EnhancedMap>(); data.events.map((ev: ISpaceSummaryEvent) => { if (ev.type === EventType.SpaceChild) { parentChildRelations.getOrCreate(ev.room_id, new Map()).set(ev.state_key, ev); } + + if (Array.isArray(ev.content["via"])) { + const set = viaMap.getOrCreate(ev.state_key, new Set()); + ev.content["via"].forEach(via => set.add(via)); + } }); const roomsMap = new Map(data.rooms.map(r => [r.room_id, r])); const numRooms = data.rooms.filter(r => r.room_type !== RoomType.Space).length; - return [false, roomsMap, parentChildRelations, numRooms]; + return [false, roomsMap, parentChildRelations, viaMap, numRooms]; } catch (e) { console.error(e); // TODO } @@ -292,7 +298,7 @@ const SpaceLanding = ({ space }) => { relations={relations} parents={new Set()} onViewRoomClick={(roomId, autoJoin) => { - showRoom(roomsMap.get(roomId), [], autoJoin); + showRoom(roomsMap.get(roomId), Array.from(viaMap.get(roomId) || []), autoJoin); }} />
; From 6d9496cc224fbfe23c29800b9fe24aadc7e14906 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 17:02:12 +0000 Subject: [PATCH 17/24] Consolidate space summary api logic between space room view and directory --- .../structures/SpaceRoomDirectory.tsx | 51 +++++++++++-------- src/components/structures/SpaceRoomView.tsx | 43 +++++----------- 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/src/components/structures/SpaceRoomDirectory.tsx b/src/components/structures/SpaceRoomDirectory.tsx index 877a4283f1..0dfb33379d 100644 --- a/src/components/structures/SpaceRoomDirectory.tsx +++ b/src/components/structures/SpaceRoomDirectory.tsx @@ -15,7 +15,8 @@ limitations under the License. */ import React, {useMemo, useState} from "react"; -import Room from "matrix-js-sdk/src/models/room"; +import {Room} from "matrix-js-sdk/src/models/room"; +import {MatrixClient} from "matrix-js-sdk/src/client"; import {EventType, RoomType} from "matrix-js-sdk/src/@types/event"; import classNames from "classnames"; import {sortBy} from "lodash"; @@ -232,7 +233,7 @@ export const showRoom = (room: ISpaceSummaryRoom, viaServers?: string[], autoJoi interface IHierarchyLevelProps { spaceId: string; rooms: Map; - relations: EnhancedMap>; + relations: Map>; parents: Set; selectedMap?: Map>; onViewRoomClick(roomId: string, autoJoin: boolean): void; @@ -308,23 +309,15 @@ export const HierarchyLevel = ({ }; -const SpaceRoomDirectory: React.FC = ({ space, initialText = "", onFinished }) => { +// mutate argument refreshToken to force a reload +export const useSpaceSummary = (cli: MatrixClient, space: Room, refreshToken?: any): [ + ISpaceSummaryRoom[], + Map>, + Map>, + Map>, +] | [] => { // TODO pagination - const cli = MatrixClientPeg.get(); - const userId = cli.getUserId(); - const [query, setQuery] = useState(initialText); - - const onCreateRoomClick = () => { - dis.dispatch({ - action: 'view_create_room', - public: true, - }); - onFinished(); - }; - - const [selected, setSelected] = useState(new Map>()); // Map> - - const [rooms, parentChildMap, childParentMap, viaMap] = useAsyncMemo(async () => { + return useAsyncMemo(async () => { try { const data = await cli.getSpaceSummary(space.roomId); @@ -342,13 +335,31 @@ const SpaceRoomDirectory: React.FC = ({ space, initialText = "", onFinis } }); - return [data.rooms as ISpaceSummaryRoom[], parentChildRelations, childParentRelations, viaMap]; + return [data.rooms as ISpaceSummaryRoom[], parentChildRelations, viaMap, childParentRelations]; } catch (e) { console.error(e); // TODO } return []; - }, [space], []); + }, [space, refreshToken], []); +}; + +const SpaceRoomDirectory: React.FC = ({ space, initialText = "", onFinished }) => { + const cli = MatrixClientPeg.get(); + const userId = cli.getUserId(); + const [query, setQuery] = useState(initialText); + + const onCreateRoomClick = () => { + dis.dispatch({ + action: 'view_create_room', + public: true, + }); + onFinished(); + }; + + const [selected, setSelected] = useState(new Map>()); // Map> + + const [rooms, parentChildMap, viaMap, childParentMap] = useSpaceSummary(cli, space); const roomsMap = useMemo(() => { if (!rooms) return null; diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 06b4fe5983..3ef10363b9 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {RefObject, useContext, useRef, useState} from "react"; +import React, {RefObject, useContext, useMemo, useRef, useState} from "react"; import {EventType, RoomType} from "matrix-js-sdk/src/@types/event"; import {Room} from "matrix-js-sdk/src/models/room"; import {EventSubscription} from "fbemitter"; @@ -46,7 +46,7 @@ import {SetRightPanelPhasePayload} from "../../dispatcher/payloads/SetRightPanel import {useStateArray} from "../../hooks/useStateArray"; import SpacePublicShare from "../views/spaces/SpacePublicShare"; import {showAddExistingRooms, showCreateNewRoom, shouldShowSpaceSettings, showSpaceSettings} from "../../utils/space"; -import {HierarchyLevel, ISpaceSummaryEvent, ISpaceSummaryRoom, showRoom} from "./SpaceRoomDirectory"; +import {HierarchyLevel, ISpaceSummaryEvent, ISpaceSummaryRoom, showRoom, useSpaceSummary} from "./SpaceRoomDirectory"; import {useAsyncMemo} from "../../hooks/useAsyncMemo"; import {EnhancedMap} from "../../utils/maps"; import AutoHideScrollbar from "./AutoHideScrollbar"; @@ -228,7 +228,7 @@ const SpaceLanding = ({ space }) => { const canAddRooms = myMembership === "join" && space.currentState.maySendStateEvent(EventType.SpaceChild, userId); - const [_, forceUpdate] = useStateToggle(false); // TODO + const [refreshToken, forceUpdate] = useStateToggle(false); let addRoomButtons; if (canAddRooms) { @@ -258,32 +258,13 @@ const SpaceLanding = ({ space }) => { ; } - const [loading, roomsMap, relations, viaMap, numRooms] = useAsyncMemo(async () => { - try { - const data = await cli.getSpaceSummary(space.roomId, undefined, myMembership !== "join"); - - const parentChildRelations = new EnhancedMap>(); - const viaMap = new EnhancedMap>(); - data.events.map((ev: ISpaceSummaryEvent) => { - if (ev.type === EventType.SpaceChild) { - parentChildRelations.getOrCreate(ev.room_id, new Map()).set(ev.state_key, ev); - } - - if (Array.isArray(ev.content["via"])) { - const set = viaMap.getOrCreate(ev.state_key, new Set()); - ev.content["via"].forEach(via => set.add(via)); - } - }); - - const roomsMap = new Map(data.rooms.map(r => [r.room_id, r])); - const numRooms = data.rooms.filter(r => r.room_type !== RoomType.Space).length; - return [false, roomsMap, parentChildRelations, viaMap, numRooms]; - } catch (e) { - console.error(e); // TODO - } - - return [false]; - }, [space, _], [true]); + const [rooms, relations, viaMap] = useSpaceSummary(cli, space, refreshToken); + const [roomsMap, numRooms] = useMemo(() => { + if (!rooms) return []; + const roomsMap = new Map(rooms.map(r => [r.room_id, r])); + const numRooms = rooms.filter(r => r.room_type !== RoomType.Space).length; + return [roomsMap, numRooms]; + }, [rooms]); let previewRooms; if (roomsMap) { @@ -302,7 +283,7 @@ const SpaceLanding = ({ space }) => { }} /> ; - } else if (loading) { + } else if (!rooms) { previewRooms = ; } else { previewRooms =

{_t("Your server does not support showing space hierarchies.")}

; @@ -647,6 +628,8 @@ export default class SpaceRoomView extends React.PureComponent { }; private goToFirstRoom = async () => { + // TODO actually go to the first room + const childRooms = SpaceStore.instance.getChildRooms(this.props.space.roomId); if (childRooms.length) { const room = childRooms[0]; From ee5d0d68421f0510d8a084f77954a9869e9e67a4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 24 Mar 2021 17:05:21 +0000 Subject: [PATCH 18/24] Fix alignment bug with space panel on spaces with subspaces in Chrome --- res/css/structures/_SpacePanel.scss | 3 --- src/components/views/spaces/SpaceTreeLevel.tsx | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/res/css/structures/_SpacePanel.scss b/res/css/structures/_SpacePanel.scss index ffe67ce6ab..33f4dc0588 100644 --- a/res/css/structures/_SpacePanel.scss +++ b/res/css/structures/_SpacePanel.scss @@ -146,9 +146,6 @@ $activeBorderColor: $secondary-fg-color; .mx_SpaceButton_toggleCollapse { width: $gutterSize; - // negative margin to place it correctly even with the complex - // 4px selection border each space button has when active - margin-right: -4px; height: 20px; mask-position: center; mask-size: 20px; diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index 1b86bb7898..1da6720eea 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -37,7 +37,7 @@ import { showSpaceSettings, } from "../../../utils/space"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {ButtonEvent} from "../elements/AccessibleButton"; +import AccessibleButton, {ButtonEvent} from "../elements/AccessibleButton"; import defaultDispatcher from "../../../dispatcher/dispatcher"; import Modal from "../../../Modal"; import SpacePublicShare from "./SpacePublicShare"; @@ -353,7 +353,7 @@ export class SpaceItem extends React.PureComponent { const avatarSize = isNested ? 24 : 32; const toggleCollapseButton = childSpaces && childSpaces.length ? -