You've already forked matrix-react-sdk
mirror of
https://github.com/matrix-org/matrix-react-sdk.git
synced 2025-11-07 10:46:24 +03:00
post-merge tidy up
This commit is contained in:
@@ -116,6 +116,12 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_SpaceHierarchy_list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_SpaceHierarchy_roomCount {
|
.mx_SpaceHierarchy_roomCount {
|
||||||
> h3 {
|
> h3 {
|
||||||
display: inline;
|
display: inline;
|
||||||
@@ -264,7 +270,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
li.mx_SpaceRoomDirectory_roomTileWrapper {
|
li.mx_SpaceHierarchy_roomTileWrapper {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,15 +23,18 @@ import React, {
|
|||||||
useState,
|
useState,
|
||||||
KeyboardEvent,
|
KeyboardEvent,
|
||||||
KeyboardEventHandler,
|
KeyboardEventHandler,
|
||||||
|
useContext,
|
||||||
|
SetStateAction,
|
||||||
|
Dispatch,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { RoomHierarchy } from "matrix-js-sdk/src/room-hierarchy";
|
import { RoomHierarchy } from "matrix-js-sdk/src/room-hierarchy";
|
||||||
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
|
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
|
||||||
import { IHierarchyRelation, IHierarchyRoom } from "matrix-js-sdk/src/@types/spaces";
|
import { IHierarchyRelation, IHierarchyRoom } from "matrix-js-sdk/src/@types/spaces";
|
||||||
|
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { sortBy } from "lodash";
|
import { sortBy } from "lodash";
|
||||||
|
|
||||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
|
||||||
import dis from "../../dispatcher/dispatcher";
|
import dis from "../../dispatcher/dispatcher";
|
||||||
import defaultDispatcher from "../../dispatcher/dispatcher";
|
import defaultDispatcher from "../../dispatcher/dispatcher";
|
||||||
import { _t } from "../../languageHandler";
|
import { _t } from "../../languageHandler";
|
||||||
@@ -53,12 +56,13 @@ import { Action } from "../../dispatcher/actions";
|
|||||||
import { Key } from "../../Keyboard";
|
import { Key } from "../../Keyboard";
|
||||||
import { IState, RovingTabIndexProvider, useRovingTabIndex } from "../../accessibility/RovingTabIndex";
|
import { IState, RovingTabIndexProvider, useRovingTabIndex } from "../../accessibility/RovingTabIndex";
|
||||||
import { getDisplayAliasForRoom } from "./RoomDirectory";
|
import { getDisplayAliasForRoom } from "./RoomDirectory";
|
||||||
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
space: Room;
|
space: Room;
|
||||||
initialText?: string;
|
initialText?: string;
|
||||||
additionalButtons?: ReactNode;
|
additionalButtons?: ReactNode;
|
||||||
showRoom(hierarchy: RoomHierarchy, roomId: string, autoJoin?: boolean): void;
|
showRoom(cli: MatrixClient, hierarchy: RoomHierarchy, roomId: string, autoJoin?: boolean): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ITileProps {
|
interface ITileProps {
|
||||||
@@ -81,7 +85,7 @@ const Tile: React.FC<ITileProps> = ({
|
|||||||
numChildRooms,
|
numChildRooms,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = useContext(MatrixClientContext);
|
||||||
const joinedRoom = cli.getRoom(room.room_id)?.getMyMembership() === "join" ? cli.getRoom(room.room_id) : null;
|
const joinedRoom = cli.getRoom(room.room_id)?.getMyMembership() === "join" ? cli.getRoom(room.room_id) : null;
|
||||||
const name = joinedRoom?.name || room.name || room.canonical_alias || room.aliases?.[0]
|
const name = joinedRoom?.name || room.name || room.canonical_alias || room.aliases?.[0]
|
||||||
|| (room.room_type === RoomType.Space ? _t("Unnamed Space") : _t("Unnamed Room"));
|
|| (room.room_type === RoomType.Space ? _t("Unnamed Space") : _t("Unnamed Room"));
|
||||||
@@ -238,7 +242,7 @@ const Tile: React.FC<ITileProps> = ({
|
|||||||
handled = true;
|
handled = true;
|
||||||
if (showChildren) {
|
if (showChildren) {
|
||||||
const childSection = ref.current?.nextElementSibling;
|
const childSection = ref.current?.nextElementSibling;
|
||||||
childSection?.querySelector<HTMLDivElement>(".mx_SpaceRoomDirectory_roomTile")?.focus();
|
childSection?.querySelector<HTMLDivElement>(".mx_SpaceHierarchy_roomTile")?.focus();
|
||||||
} else {
|
} else {
|
||||||
toggleShowChildren();
|
toggleShowChildren();
|
||||||
}
|
}
|
||||||
@@ -253,7 +257,7 @@ const Tile: React.FC<ITileProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <li
|
return <li
|
||||||
className="mx_SpaceRoomDirectory_roomTileWrapper"
|
className="mx_SpaceHierarchy_roomTileWrapper"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
aria-expanded={children ? showChildren : undefined}
|
aria-expanded={children ? showChildren : undefined}
|
||||||
>
|
>
|
||||||
@@ -274,12 +278,12 @@ const Tile: React.FC<ITileProps> = ({
|
|||||||
</li>;
|
</li>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const showRoom = (hierarchy: RoomHierarchy, roomId: string, autoJoin = false) => {
|
export const showRoom = (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: string, autoJoin = false) => {
|
||||||
const room = hierarchy.roomMap.get(roomId);
|
const room = hierarchy.roomMap.get(roomId);
|
||||||
|
|
||||||
// Don't let the user view a room they won't be able to either peek or join:
|
// Don't let the user view a room they won't be able to either peek or join:
|
||||||
// fail earlier so they don't have to click back to the directory.
|
// fail earlier so they don't have to click back to the directory.
|
||||||
if (MatrixClientPeg.get().isGuest()) {
|
if (cli.isGuest()) {
|
||||||
if (!room.world_readable && !room.guest_can_join) {
|
if (!room.world_readable && !room.guest_can_join) {
|
||||||
dis.dispatch({ action: "require_registration" });
|
dis.dispatch({ action: "require_registration" });
|
||||||
return;
|
return;
|
||||||
@@ -322,7 +326,7 @@ export const HierarchyLevel = ({
|
|||||||
onViewRoomClick,
|
onViewRoomClick,
|
||||||
onToggleClick,
|
onToggleClick,
|
||||||
}: IHierarchyLevelProps) => {
|
}: IHierarchyLevelProps) => {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = useContext(MatrixClientContext);
|
||||||
const space = cli.getRoom(root.room_id);
|
const space = cli.getRoom(root.room_id);
|
||||||
const hasPermissions = space?.currentState.maySendStateEvent(EventType.SpaceChild, cli.getUserId());
|
const hasPermissions = space?.currentState.maySendStateEvent(EventType.SpaceChild, cli.getUserId());
|
||||||
|
|
||||||
@@ -462,72 +466,19 @@ const useIntersectionObserver = (callback: () => void) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const SpaceHierarchy = ({
|
interface IManageButtonsProps {
|
||||||
space,
|
hierarchy: RoomHierarchy;
|
||||||
initialText = "",
|
selected: Map<string, Set<string>>;
|
||||||
showRoom,
|
setSelected: Dispatch<SetStateAction<Map<string, Set<string>>>>;
|
||||||
additionalButtons,
|
setError: Dispatch<SetStateAction<string>>;
|
||||||
}: IProps) => {
|
|
||||||
const cli = MatrixClientPeg.get();
|
|
||||||
const userId = cli.getUserId();
|
|
||||||
const [query, setQuery] = useState(initialText);
|
|
||||||
|
|
||||||
const [selected, setSelected] = useState(new Map<string, Set<string>>()); // Map<parentId, Set<childId>>
|
|
||||||
|
|
||||||
const { loading, rooms, hierarchy, loadMore } = useSpaceSummary(space);
|
|
||||||
|
|
||||||
const filteredRoomSet = useMemo<Set<IHierarchyRoom>>(() => {
|
|
||||||
if (!rooms.length) return new Set();
|
|
||||||
const lcQuery = query.toLowerCase().trim();
|
|
||||||
if (!lcQuery) return new Set(rooms);
|
|
||||||
|
|
||||||
const directMatches = rooms.filter(r => {
|
|
||||||
return r.name?.toLowerCase().includes(lcQuery) || r.topic?.toLowerCase().includes(lcQuery);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Walk back up the tree to find all parents of the direct matches to show their place in the hierarchy
|
|
||||||
const visited = new Set<string>();
|
|
||||||
const queue = [...directMatches.map(r => r.room_id)];
|
|
||||||
while (queue.length) {
|
|
||||||
const roomId = queue.pop();
|
|
||||||
visited.add(roomId);
|
|
||||||
hierarchy.backRefs.get(roomId)?.forEach(parentId => {
|
|
||||||
if (!visited.has(parentId)) {
|
|
||||||
queue.push(parentId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Set(rooms.filter(r => visited.has(r.room_id)));
|
const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageButtonsProps) => {
|
||||||
}, [rooms, hierarchy, query]);
|
const cli = useContext(MatrixClientContext);
|
||||||
|
|
||||||
const [error, setError] = useState("");
|
|
||||||
const [removing, setRemoving] = useState(false);
|
const [removing, setRemoving] = useState(false);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
|
|
||||||
const loaderRef = useIntersectionObserver(loadMore);
|
|
||||||
|
|
||||||
if (!loading && hierarchy.noSupport) {
|
|
||||||
return <p>{ _t("Your server does not support showing space hierarchies.") }</p>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onKeyDown = (ev: KeyboardEvent, state: IState) => {
|
|
||||||
if (ev.key === Key.ARROW_DOWN && ev.currentTarget.classList.contains("mx_SpaceRoomDirectory_search")) {
|
|
||||||
state.refs[0]?.current?.focus();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO loading state/error state
|
|
||||||
return <RovingTabIndexProvider onKeyDown={onKeyDown} handleHomeEnd handleUpDown>
|
|
||||||
{ ({ onKeyDownHandler }) => {
|
|
||||||
let content: JSX.Element;
|
|
||||||
let loader: JSX.Element;
|
|
||||||
|
|
||||||
if (loading && !rooms.length) {
|
|
||||||
content = <Spinner />;
|
|
||||||
} else {
|
|
||||||
let manageButtons;
|
|
||||||
if (space.getMyMembership() === "join" && space.currentState.maySendStateEvent(EventType.SpaceChild, userId)) {
|
|
||||||
const selectedRelations = Array.from(selected.keys()).flatMap(parentId => {
|
const selectedRelations = Array.from(selected.keys()).flatMap(parentId => {
|
||||||
return [
|
return [
|
||||||
...selected.get(parentId).values(),
|
...selected.get(parentId).values(),
|
||||||
@@ -550,7 +501,7 @@ const SpaceHierarchy = ({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
manageButtons = <>
|
return <>
|
||||||
<Button
|
<Button
|
||||||
{...props}
|
{...props}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
@@ -607,20 +558,61 @@ const SpaceHierarchy = ({
|
|||||||
}
|
}
|
||||||
</Button>
|
</Button>
|
||||||
</>;
|
</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SpaceHierarchy = ({
|
||||||
|
space,
|
||||||
|
initialText = "",
|
||||||
|
showRoom,
|
||||||
|
additionalButtons,
|
||||||
|
}: IProps) => {
|
||||||
|
const cli = useContext(MatrixClientContext);
|
||||||
|
const [query, setQuery] = useState(initialText);
|
||||||
|
|
||||||
|
const [selected, setSelected] = useState(new Map<string, Set<string>>()); // Map<parentId, Set<childId>>
|
||||||
|
|
||||||
|
const { loading, rooms, hierarchy, loadMore } = useSpaceSummary(space);
|
||||||
|
|
||||||
|
const filteredRoomSet = useMemo<Set<IHierarchyRoom>>(() => {
|
||||||
|
if (!rooms.length) return new Set();
|
||||||
|
const lcQuery = query.toLowerCase().trim();
|
||||||
|
if (!lcQuery) return new Set(rooms);
|
||||||
|
|
||||||
|
const directMatches = rooms.filter(r => {
|
||||||
|
return r.name?.toLowerCase().includes(lcQuery) || r.topic?.toLowerCase().includes(lcQuery);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Walk back up the tree to find all parents of the direct matches to show their place in the hierarchy
|
||||||
|
const visited = new Set<string>();
|
||||||
|
const queue = [...directMatches.map(r => r.room_id)];
|
||||||
|
while (queue.length) {
|
||||||
|
const roomId = queue.pop();
|
||||||
|
visited.add(roomId);
|
||||||
|
hierarchy.backRefs.get(roomId)?.forEach(parentId => {
|
||||||
|
if (!visited.has(parentId)) {
|
||||||
|
queue.push(parentId);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let results: JSX.Element;
|
return new Set(rooms.filter(r => visited.has(r.room_id)));
|
||||||
if (filteredRoomSet.size) {
|
}, [rooms, hierarchy, query]);
|
||||||
const hasPermissions = space?.currentState.maySendStateEvent(EventType.SpaceChild, cli.getUserId());
|
|
||||||
|
|
||||||
results = <>
|
const [error, setError] = useState("");
|
||||||
<HierarchyLevel
|
|
||||||
root={hierarchy.roomMap.get(space.roomId)}
|
const loaderRef = useIntersectionObserver(loadMore);
|
||||||
roomSet={filteredRoomSet}
|
|
||||||
hierarchy={hierarchy}
|
if (!loading && hierarchy.noSupport) {
|
||||||
parents={new Set()}
|
return <p>{ _t("Your server does not support showing space hierarchies.") }</p>;
|
||||||
selectedMap={selected}
|
}
|
||||||
onToggleClick={hasPermissions ? (parentId, childId) => {
|
|
||||||
|
const onKeyDown = (ev: KeyboardEvent, state: IState): void => {
|
||||||
|
if (ev.key === Key.ARROW_DOWN && ev.currentTarget.classList.contains("mx_SpaceHierarchy_search")) {
|
||||||
|
state.refs[0]?.current?.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onToggleClick = (parentId: string, childId: string): void => {
|
||||||
setError("");
|
setError("");
|
||||||
if (!selected.has(parentId)) {
|
if (!selected.has(parentId)) {
|
||||||
setSelected(new Map(selected.set(parentId, new Set([childId]))));
|
setSelected(new Map(selected.set(parentId, new Set([childId]))));
|
||||||
@@ -635,9 +627,31 @@ const SpaceHierarchy = ({
|
|||||||
|
|
||||||
parentSet.delete(childId);
|
parentSet.delete(childId);
|
||||||
setSelected(new Map(selected.set(parentId, new Set(parentSet))));
|
setSelected(new Map(selected.set(parentId, new Set(parentSet))));
|
||||||
} : undefined}
|
};
|
||||||
|
|
||||||
|
return <RovingTabIndexProvider onKeyDown={onKeyDown} handleHomeEnd handleUpDown>
|
||||||
|
{ ({ onKeyDownHandler }) => {
|
||||||
|
let content: JSX.Element;
|
||||||
|
let loader: JSX.Element;
|
||||||
|
|
||||||
|
if (loading && !rooms.length) {
|
||||||
|
content = <Spinner />;
|
||||||
|
} else {
|
||||||
|
const hasPermissions = space?.getMyMembership() === "join" &&
|
||||||
|
space.currentState.maySendStateEvent(EventType.SpaceChild, cli.getUserId());
|
||||||
|
|
||||||
|
let results: JSX.Element;
|
||||||
|
if (filteredRoomSet.size) {
|
||||||
|
results = <>
|
||||||
|
<HierarchyLevel
|
||||||
|
root={hierarchy.roomMap.get(space.roomId)}
|
||||||
|
roomSet={filteredRoomSet}
|
||||||
|
hierarchy={hierarchy}
|
||||||
|
parents={new Set()}
|
||||||
|
selectedMap={selected}
|
||||||
|
onToggleClick={hasPermissions ? onToggleClick : undefined}
|
||||||
onViewRoomClick={(roomId, autoJoin) => {
|
onViewRoomClick={(roomId, autoJoin) => {
|
||||||
showRoom(hierarchy, roomId, autoJoin);
|
showRoom(cli, hierarchy, roomId, autoJoin);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>;
|
</>;
|
||||||
@@ -659,13 +673,25 @@ const SpaceHierarchy = ({
|
|||||||
<h4>{ query.trim() ? _t("Results") : _t("Rooms and spaces") }</h4>
|
<h4>{ query.trim() ? _t("Results") : _t("Rooms and spaces") }</h4>
|
||||||
<span>
|
<span>
|
||||||
{ additionalButtons }
|
{ additionalButtons }
|
||||||
{ manageButtons }
|
{ hasPermissions && (
|
||||||
|
<ManageButtons
|
||||||
|
hierarchy={hierarchy}
|
||||||
|
selected={selected}
|
||||||
|
setSelected={setSelected}
|
||||||
|
setError={setError}
|
||||||
|
/>
|
||||||
|
) }
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{ error && <div className="mx_SpaceHierarchy_error">
|
{ error && <div className="mx_SpaceHierarchy_error">
|
||||||
{ error }
|
{ error }
|
||||||
</div> }
|
</div> }
|
||||||
<ul onKeyDown={onKeyDownHandler} role="tree" aria-label={_t("Space")}>
|
<ul
|
||||||
|
className="mx_SpaceHierarchy_list"
|
||||||
|
onKeyDown={onKeyDownHandler}
|
||||||
|
role="tree"
|
||||||
|
aria-label={_t("Space")}
|
||||||
|
>
|
||||||
{ results }
|
{ results }
|
||||||
</ul>
|
</ul>
|
||||||
{ loader }
|
{ loader }
|
||||||
@@ -674,7 +700,7 @@ const SpaceHierarchy = ({
|
|||||||
|
|
||||||
return <>
|
return <>
|
||||||
<SearchBox
|
<SearchBox
|
||||||
className="mx_SpaceRoomDirectory_search mx_textinput_icon mx_textinput_search"
|
className="mx_SpaceHierarchy_search mx_textinput_icon mx_textinput_search"
|
||||||
placeholder={_t("Search names and descriptions")}
|
placeholder={_t("Search names and descriptions")}
|
||||||
onSearch={setQuery}
|
onSearch={setQuery}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
|
|||||||
@@ -2844,10 +2844,6 @@
|
|||||||
"This room is suggested as a good one to join": "This room is suggested as a good one to join",
|
"This room is suggested as a good one to join": "This room is suggested as a good one to join",
|
||||||
"Suggested": "Suggested",
|
"Suggested": "Suggested",
|
||||||
"Your server does not support showing space hierarchies.": "Your server does not support showing space hierarchies.",
|
"Your server does not support showing space hierarchies.": "Your server does not support showing space hierarchies.",
|
||||||
"%(count)s rooms and %(numSpaces)s spaces|other": "%(count)s rooms and %(numSpaces)s spaces",
|
|
||||||
"%(count)s rooms and %(numSpaces)s spaces|one": "%(count)s room and %(numSpaces)s spaces",
|
|
||||||
"%(count)s rooms and 1 space|other": "%(count)s rooms and 1 space",
|
|
||||||
"%(count)s rooms and 1 space|one": "%(count)s room and 1 space",
|
|
||||||
"Select a room below first": "Select a room below first",
|
"Select a room below first": "Select a room below first",
|
||||||
"Failed to remove some rooms. Try again later": "Failed to remove some rooms. Try again later",
|
"Failed to remove some rooms. Try again later": "Failed to remove some rooms. Try again later",
|
||||||
"Removing...": "Removing...",
|
"Removing...": "Removing...",
|
||||||
@@ -2855,10 +2851,10 @@
|
|||||||
"Mark as suggested": "Mark as suggested",
|
"Mark as suggested": "Mark as suggested",
|
||||||
"No results found": "No results found",
|
"No results found": "No results found",
|
||||||
"You may want to try a different search or check for typos.": "You may want to try a different search or check for typos.",
|
"You may want to try a different search or check for typos.": "You may want to try a different search or check for typos.",
|
||||||
|
"Results": "Results",
|
||||||
|
"Rooms and spaces": "Rooms and spaces",
|
||||||
"Space": "Space",
|
"Space": "Space",
|
||||||
"Search names and descriptions": "Search names and descriptions",
|
"Search names and descriptions": "Search names and descriptions",
|
||||||
"If you can't find the room you're looking for, ask for an invite or <a>create a new room</a>.": "If you can't find the room you're looking for, ask for an invite or <a>create a new room</a>.",
|
|
||||||
"Create room": "Create room",
|
|
||||||
"Private space": "Private space",
|
"Private space": "Private space",
|
||||||
"<inviter/> invites you": "<inviter/> invites you",
|
"<inviter/> invites you": "<inviter/> invites you",
|
||||||
"To view %(spaceName)s, turn on the <a>Spaces beta</a>": "To view %(spaceName)s, turn on the <a>Spaces beta</a>",
|
"To view %(spaceName)s, turn on the <a>Spaces beta</a>": "To view %(spaceName)s, turn on the <a>Spaces beta</a>",
|
||||||
|
|||||||
Reference in New Issue
Block a user