mirror of https://github.com/vector-im/riot-web
Implement MSC3827: Filtering of `/publicRooms` by room type (#8866)
parent
18c21d77cd
commit
663bca559f
|
@ -168,6 +168,11 @@ limitations under the License.
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: $spacing-8;
|
||||
|
||||
.mx_SpotlightDialog_options {
|
||||
display: flex;
|
||||
gap: $spacing-4;
|
||||
}
|
||||
}
|
||||
|
||||
& + .mx_SpotlightDialog_section {
|
||||
|
|
|
@ -18,7 +18,7 @@ import classNames from "classnames";
|
|||
import { capitalize, sum } from "lodash";
|
||||
import { WebSearch as WebSearchEvent } from "@matrix-org/analytics-events/types/typescript/WebSearch";
|
||||
import { IHierarchyRoom } from "matrix-js-sdk/src/@types/spaces";
|
||||
import { IPublicRoomsChunkRoom, MatrixClient, RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
import { IPublicRoomsChunkRoom, MatrixClient, RoomMember, RoomType } from "matrix-js-sdk/src/matrix";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { normalize } from "matrix-js-sdk/src/utils";
|
||||
import React, {
|
||||
|
@ -89,6 +89,8 @@ import { Option } from "./Option";
|
|||
import { PublicRoomResultDetails } from "./PublicRoomResultDetails";
|
||||
import { RoomResultDetails } from "./RoomResultDetails";
|
||||
import { TooltipOption } from "./TooltipOption";
|
||||
import LabelledCheckbox from "../../elements/LabelledCheckbox";
|
||||
import { useFeatureEnabled } from "../../../../hooks/useSettings";
|
||||
|
||||
const MAX_RECENT_SEARCHES = 10;
|
||||
const SECTION_LIMIT = 50; // only show 50 results per section for performance reasons
|
||||
|
@ -103,6 +105,18 @@ function refIsForRecentlyViewed(ref: RefObject<HTMLElement>): boolean {
|
|||
return ref.current?.id?.startsWith("mx_SpotlightDialog_button_recentlyViewed_") === true;
|
||||
}
|
||||
|
||||
function getRoomTypes(showRooms: boolean, showSpaces: boolean): Set<RoomType | null> | null {
|
||||
const roomTypes = new Set<RoomType | null>();
|
||||
|
||||
// This is what servers not implementing MSC3827 are expecting
|
||||
if (showRooms && !showSpaces) return null;
|
||||
|
||||
if (showRooms) roomTypes.add(null);
|
||||
if (showSpaces) roomTypes.add(RoomType.Space);
|
||||
|
||||
return roomTypes;
|
||||
}
|
||||
|
||||
enum Section {
|
||||
People,
|
||||
Rooms,
|
||||
|
@ -277,14 +291,19 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
|||
const [inviteLinkCopied, setInviteLinkCopied] = useState<boolean>(false);
|
||||
const trimmedQuery = useMemo(() => query.trim(), [query]);
|
||||
|
||||
const exploringPublicSpacesEnabled = useFeatureEnabled("feature_exploring_public_spaces");
|
||||
|
||||
const { loading: publicRoomsLoading, publicRooms, protocols, config, setConfig, search: searchPublicRooms } =
|
||||
usePublicRoomDirectory();
|
||||
const [showRooms, setShowRooms] = useState(true);
|
||||
const [showSpaces, setShowSpaces] = useState(false);
|
||||
const { loading: peopleLoading, users, search: searchPeople } = useUserDirectory();
|
||||
const { loading: profileLoading, profile, search: searchProfileInfo } = useProfileInfo();
|
||||
const searchParams: [IDirectoryOpts] = useMemo(() => ([{
|
||||
query: trimmedQuery,
|
||||
roomTypes: getRoomTypes(showRooms, showSpaces),
|
||||
limit: SECTION_LIMIT,
|
||||
}]), [trimmedQuery]);
|
||||
}]), [trimmedQuery, showRooms, showSpaces]);
|
||||
useDebouncedCallback(
|
||||
filter === Filter.PublicRooms,
|
||||
searchPublicRooms,
|
||||
|
@ -624,15 +643,32 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
|||
<div className="mx_SpotlightDialog_section mx_SpotlightDialog_results" role="group">
|
||||
<div className="mx_SpotlightDialog_sectionHeader">
|
||||
<h4>{ _t("Suggestions") }</h4>
|
||||
<NetworkDropdown
|
||||
protocols={protocols}
|
||||
config={config ?? null}
|
||||
setConfig={setConfig}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
{ results[Section.PublicRooms].slice(0, SECTION_LIMIT).map(resultMapper) }
|
||||
<div className="mx_SpotlightDialog_options">
|
||||
{ exploringPublicSpacesEnabled && <>
|
||||
<LabelledCheckbox
|
||||
label={_t("Show rooms")}
|
||||
value={showRooms}
|
||||
onChange={setShowRooms}
|
||||
/>
|
||||
<LabelledCheckbox
|
||||
label={_t("Show spaces")}
|
||||
value={showSpaces}
|
||||
onChange={setShowSpaces}
|
||||
/>
|
||||
</> }
|
||||
<NetworkDropdown
|
||||
protocols={protocols}
|
||||
config={config ?? null}
|
||||
setConfig={setConfig}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div> { (showRooms || showSpaces)
|
||||
? results[Section.PublicRooms].slice(0, SECTION_LIMIT).map(resultMapper)
|
||||
: <div className="mx_SpotlightDialog_otherSearches_messageSearchText">
|
||||
{ _t("You cannot search for rooms that are neither a room nor a space") }
|
||||
</div>
|
||||
} </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -49,23 +49,31 @@ export class LabsSettingToggle extends React.Component<ILabsSettingToggleProps>
|
|||
interface IState {
|
||||
showHiddenReadReceipts: boolean;
|
||||
showJumpToDate: boolean;
|
||||
showExploringPublicSpaces: boolean;
|
||||
}
|
||||
|
||||
export default class LabsUserSettingsTab extends React.Component<{}, IState> {
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
|
||||
MatrixClientPeg.get().doesServerSupportUnstableFeature("org.matrix.msc2285").then((showHiddenReadReceipts) => {
|
||||
const cli = MatrixClientPeg.get();
|
||||
|
||||
cli.doesServerSupportUnstableFeature("org.matrix.msc2285").then((showHiddenReadReceipts) => {
|
||||
this.setState({ showHiddenReadReceipts });
|
||||
});
|
||||
|
||||
MatrixClientPeg.get().doesServerSupportUnstableFeature("org.matrix.msc3030").then((showJumpToDate) => {
|
||||
cli.doesServerSupportUnstableFeature("org.matrix.msc3030").then((showJumpToDate) => {
|
||||
this.setState({ showJumpToDate });
|
||||
});
|
||||
|
||||
cli.doesServerSupportUnstableFeature("org.matrix.msc3827").then((showExploringPublicSpaces) => {
|
||||
this.setState({ showExploringPublicSpaces });
|
||||
});
|
||||
|
||||
this.state = {
|
||||
showHiddenReadReceipts: false,
|
||||
showJumpToDate: false,
|
||||
showExploringPublicSpaces: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -133,6 +141,16 @@ export default class LabsUserSettingsTab extends React.Component<{}, IState> {
|
|||
);
|
||||
}
|
||||
|
||||
if (this.state.showExploringPublicSpaces) {
|
||||
groups.getOrCreate(LabGroup.Spaces, []).push(
|
||||
<SettingsFlag
|
||||
key="feature_exploring_public_spaces"
|
||||
name="feature_exploring_public_spaces"
|
||||
level={SettingLevel.DEVICE}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
|
||||
labsSections = <>
|
||||
{ sortBy(Array.from(groups.entries()), "0").map(([group, flags]) => (
|
||||
<div className="mx_SettingsTab_section" key={group}>
|
||||
|
|
|
@ -18,7 +18,7 @@ import React, { ComponentProps, RefObject, SyntheticEvent, KeyboardEvent, useCon
|
|||
import classNames from "classnames";
|
||||
import { RoomType } from "matrix-js-sdk/src/@types/event";
|
||||
import { ICreateRoomOpts } from "matrix-js-sdk/src/@types/requests";
|
||||
import { HistoryVisibility, Preset } from "matrix-js-sdk/src/@types/partials";
|
||||
import { HistoryVisibility, Preset, Visibility } from "matrix-js-sdk/src/@types/partials";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
@ -37,6 +37,7 @@ import GenericFeatureFeedbackDialog from "../dialogs/GenericFeatureFeedbackDialo
|
|||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
|
||||
export const createSpace = async (
|
||||
name: string,
|
||||
|
@ -51,6 +52,9 @@ export const createSpace = async (
|
|||
createOpts: {
|
||||
name,
|
||||
preset: isPublic ? Preset.PublicChat : Preset.PrivateChat,
|
||||
visibility: (isPublic && await MatrixClientPeg.get().doesServerSupportUnstableFeature("org.matrix.msc3827"))
|
||||
? Visibility.Public
|
||||
: Visibility.Private,
|
||||
power_level_content_override: {
|
||||
// Only allow Admins to write to the timeline to prevent hidden sync spam
|
||||
events_default: 100,
|
||||
|
@ -80,11 +84,6 @@ const SpaceCreateMenuType = ({ title, description, className, onClick }) => {
|
|||
);
|
||||
};
|
||||
|
||||
enum Visibility {
|
||||
Public,
|
||||
Private,
|
||||
}
|
||||
|
||||
const spaceNameValidator = withValidation({
|
||||
rules: [
|
||||
{
|
||||
|
|
|
@ -29,6 +29,7 @@ import { useLocalEcho } from "../../../hooks/useLocalEcho";
|
|||
import JoinRuleSettings from "../settings/JoinRuleSettings";
|
||||
import { useRoomState } from "../../../hooks/useRoomState";
|
||||
import SettingsFieldset from "../settings/SettingsFieldset";
|
||||
import { useAsyncMemo } from "../../../hooks/useAsyncMemo";
|
||||
|
||||
interface IProps {
|
||||
matrixClient: MatrixClient;
|
||||
|
@ -38,6 +39,9 @@ interface IProps {
|
|||
|
||||
const SpaceSettingsVisibilityTab = ({ matrixClient: cli, space, closeSettingsFn }: IProps) => {
|
||||
const [error, setError] = useState("");
|
||||
const serverSupportsExploringSpaces = useAsyncMemo<boolean>(async () => {
|
||||
return cli.doesServerSupportUnstableFeature("org.matrix.msc3827");
|
||||
}, [cli], false);
|
||||
|
||||
const userId = cli.getUserId();
|
||||
|
||||
|
@ -103,7 +107,7 @@ const SpaceSettingsVisibilityTab = ({ matrixClient: cli, space, closeSettingsFn
|
|||
canSetCanonicalAlias={canSetCanonical}
|
||||
canSetAliases={true}
|
||||
canonicalAliasEvent={canonicalAliasEv}
|
||||
hidePublishSetting={true}
|
||||
hidePublishSetting={!serverSupportsExploringSpaces}
|
||||
/>
|
||||
</>;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { RoomType } from "matrix-js-sdk/src/@types/event";
|
||||
import { IRoomDirectoryOptions } from "matrix-js-sdk/src/@types/requests";
|
||||
import { IProtocol, IPublicRoomsChunkRoom } from "matrix-js-sdk/src/client";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
@ -32,6 +33,7 @@ const LAST_INSTANCE_KEY = "mx_last_room_directory_instance";
|
|||
export interface IPublicRoomsOpts {
|
||||
limit: number;
|
||||
query?: string;
|
||||
roomTypes?: Set<RoomType | null>;
|
||||
}
|
||||
|
||||
let thirdParty: Protocols;
|
||||
|
@ -72,6 +74,7 @@ export const usePublicRoomDirectory = () => {
|
|||
const search = useCallback(async ({
|
||||
limit = 20,
|
||||
query,
|
||||
roomTypes,
|
||||
}: IPublicRoomsOpts): Promise<boolean> => {
|
||||
const opts: IRoomDirectoryOptions = { limit };
|
||||
|
||||
|
@ -85,9 +88,10 @@ export const usePublicRoomDirectory = () => {
|
|||
opts.third_party_instance_id = config.instanceId;
|
||||
}
|
||||
|
||||
if (query) {
|
||||
if (query || roomTypes) {
|
||||
opts.filter = {
|
||||
generic_search_term: query,
|
||||
"generic_search_term": query,
|
||||
"org.matrix.msc3827.room_types": roomTypes ? Array.from<RoomType | null>(roomTypes) : null,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -856,6 +856,7 @@
|
|||
"Can I use text chat alongside the video call?": "Can I use text chat alongside the video call?",
|
||||
"Yes, the chat timeline is displayed alongside the video.": "Yes, the chat timeline is displayed alongside the video.",
|
||||
"Thank you for trying the beta, please go into as much detail as you can so we can improve it.": "Thank you for trying the beta, please go into as much detail as you can so we can improve it.",
|
||||
"Explore public spaces in the new search dialog": "Explore public spaces in the new search dialog",
|
||||
"Let moderators hide messages pending moderation.": "Let moderators hide messages pending moderation.",
|
||||
"Report to moderators prototype. In rooms that support moderation, the `report` button will let you report abuse to room moderators": "Report to moderators prototype. In rooms that support moderation, the `report` button will let you report abuse to room moderators",
|
||||
"Render LaTeX maths in messages": "Render LaTeX maths in messages",
|
||||
|
@ -2803,6 +2804,9 @@
|
|||
"Use \"%(query)s\" to search": "Use \"%(query)s\" to search",
|
||||
"Search for": "Search for",
|
||||
"Spaces you're in": "Spaces you're in",
|
||||
"Show rooms": "Show rooms",
|
||||
"Show spaces": "Show spaces",
|
||||
"You cannot search for rooms that are neither a room nor a space": "You cannot search for rooms that are neither a room nor a space",
|
||||
"Other rooms in %(spaceName)s": "Other rooms in %(spaceName)s",
|
||||
"Join %(roomAddress)s": "Join %(roomAddress)s",
|
||||
"Some results may be hidden for privacy": "Some results may be hidden for privacy",
|
||||
|
|
|
@ -220,6 +220,11 @@ export const SETTINGS: {[setting: string]: ISetting} = {
|
|||
requiresRefresh: true,
|
||||
},
|
||||
},
|
||||
"feature_exploring_public_spaces": {
|
||||
displayName: _td("Explore public spaces in the new search dialog"),
|
||||
supportedLevels: LEVELS_FEATURE,
|
||||
default: false,
|
||||
},
|
||||
"feature_msc3531_hide_messages_pending_moderation": {
|
||||
isFeature: true,
|
||||
labsGroup: LabGroup.Moderation,
|
||||
|
|
Loading…
Reference in New Issue