mirror of
https://github.com/element-hq/element-web
synced 2024-11-29 12:58:53 +03:00
Allow requesting to join knock rooms via spotlight (#11482)
Signed-off-by: Charly Nguyen <charly.nguyen@nordeck.net>
This commit is contained in:
parent
200631f3a5
commit
50160b9969
3 changed files with 106 additions and 4 deletions
|
@ -24,6 +24,7 @@ import {
|
|||
RoomType,
|
||||
Room,
|
||||
HierarchyRoom,
|
||||
JoinRule,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { normalize } from "matrix-js-sdk/src/utils";
|
||||
import React, { ChangeEvent, RefObject, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||
|
@ -276,6 +277,10 @@ const roomAriaUnreadLabel = (room: Room, notification: RoomNotificationState): s
|
|||
}
|
||||
};
|
||||
|
||||
const canAskToJoin = (joinRule?: JoinRule): boolean => {
|
||||
return SettingsStore.getValue("feature_ask_to_join") && JoinRule.Knock === joinRule;
|
||||
};
|
||||
|
||||
interface IDirectoryOpts {
|
||||
limit: number;
|
||||
query: string;
|
||||
|
@ -514,7 +519,14 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
|||
}, [results, filter]);
|
||||
|
||||
const viewRoom = (
|
||||
room: { roomId: string; roomAlias?: string; autoJoin?: boolean; shouldPeek?: boolean; viaServers?: string[] },
|
||||
room: {
|
||||
roomId: string;
|
||||
roomAlias?: string;
|
||||
autoJoin?: boolean;
|
||||
shouldPeek?: boolean;
|
||||
viaServers?: string[];
|
||||
joinRule?: IPublicRoomsChunkRoom["join_rule"];
|
||||
},
|
||||
persist = false,
|
||||
viaKeyboard = false,
|
||||
): void => {
|
||||
|
@ -538,10 +550,15 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
|||
metricsViaKeyboard: viaKeyboard,
|
||||
room_id: room.roomId,
|
||||
room_alias: room.roomAlias,
|
||||
auto_join: room.autoJoin,
|
||||
auto_join: room.autoJoin && !canAskToJoin(room.joinRule),
|
||||
should_peek: room.shouldPeek,
|
||||
via_servers: room.viaServers,
|
||||
});
|
||||
|
||||
if (canAskToJoin(room.joinRule)) {
|
||||
defaultDispatcher.dispatch({ action: Action.PromptAskToJoin });
|
||||
}
|
||||
|
||||
onFinished();
|
||||
};
|
||||
|
||||
|
@ -647,12 +664,15 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
|||
}
|
||||
if (isPublicRoomResult(result)) {
|
||||
const clientRoom = cli.getRoom(result.publicRoom.room_id);
|
||||
const joinRule = result.publicRoom.join_rule;
|
||||
// Element Web currently does not allow guests to join rooms, so we
|
||||
// instead show them view buttons for all rooms. If the room is not
|
||||
// world readable, a modal will appear asking you to register first. If
|
||||
// it is readable, the preview appears as normal.
|
||||
const showViewButton =
|
||||
clientRoom?.getMyMembership() === "join" || result.publicRoom.world_readable || cli.isGuest();
|
||||
clientRoom?.getMyMembership() === "join" ||
|
||||
(result.publicRoom.world_readable && !canAskToJoin(joinRule)) ||
|
||||
cli.isGuest();
|
||||
|
||||
const listener = (ev: ButtonEvent): void => {
|
||||
ev.stopPropagation();
|
||||
|
@ -665,12 +685,20 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
|||
autoJoin: !result.publicRoom.world_readable && !cli.isGuest(),
|
||||
shouldPeek: result.publicRoom.world_readable || cli.isGuest(),
|
||||
viaServers: config ? [config.roomServer] : undefined,
|
||||
joinRule,
|
||||
},
|
||||
true,
|
||||
ev.type !== "click",
|
||||
);
|
||||
};
|
||||
|
||||
let buttonLabel;
|
||||
if (showViewButton) {
|
||||
buttonLabel = _t("action|view");
|
||||
} else {
|
||||
buttonLabel = canAskToJoin(joinRule) ? _t("action|ask_to_join") : _t("action|join");
|
||||
}
|
||||
|
||||
return (
|
||||
<Option
|
||||
id={`mx_SpotlightDialog_button_result_${result.publicRoom.room_id}`}
|
||||
|
@ -683,7 +711,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
|||
onClick={listener}
|
||||
tabIndex={-1}
|
||||
>
|
||||
{showViewButton ? _t("action|view") : _t("action|join")}
|
||||
{buttonLabel}
|
||||
</AccessibleButton>
|
||||
}
|
||||
aria-labelledby={`mx_SpotlightDialog_button_result_${result.publicRoom.room_id}_name`}
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
"resend": "Resend",
|
||||
"next": "Next",
|
||||
"view": "View",
|
||||
"ask_to_join": "Ask to join",
|
||||
"forward": "Forward",
|
||||
"copy_link": "Copy link",
|
||||
"logout": "Logout",
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
ConnectionError,
|
||||
IProtocol,
|
||||
IPublicRoomsChunkRoom,
|
||||
JoinRule,
|
||||
MatrixClient,
|
||||
Room,
|
||||
RoomMember,
|
||||
|
@ -38,6 +39,7 @@ import SettingsStore from "../../../../src/settings/SettingsStore";
|
|||
import { SettingLevel } from "../../../../src/settings/SettingLevel";
|
||||
import defaultDispatcher from "../../../../src/dispatcher/dispatcher";
|
||||
import SdkConfig from "../../../../src/SdkConfig";
|
||||
import { Action } from "../../../../src/dispatcher/actions";
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
|
@ -574,4 +576,75 @@ describe("Spotlight Dialog", () => {
|
|||
|
||||
expect(screen.getByText("Failed to query public rooms")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("knock rooms", () => {
|
||||
const knockRoom: IPublicRoomsChunkRoom = {
|
||||
guest_can_join: false,
|
||||
join_rule: JoinRule.Knock,
|
||||
num_joined_members: 0,
|
||||
room_id: "some-room-id",
|
||||
world_readable: false,
|
||||
};
|
||||
|
||||
const viewRoomParams = {
|
||||
action: Action.ViewRoom,
|
||||
metricsTrigger: "WebUnifiedSearch",
|
||||
metricsViaKeyboard: false,
|
||||
room_alias: undefined,
|
||||
room_id: knockRoom.room_id,
|
||||
should_peek: false,
|
||||
via_servers: ["example.tld"],
|
||||
};
|
||||
|
||||
beforeEach(() => (mockedClient = mockClient({ rooms: [knockRoom] })));
|
||||
|
||||
describe("when disabling feature", () => {
|
||||
beforeEach(async () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) =>
|
||||
setting === "feature_ask_to_join" ? false : [],
|
||||
);
|
||||
|
||||
render(<SpotlightDialog initialFilter={Filter.PublicRooms} onFinished={() => {}} />);
|
||||
|
||||
// search is debounced
|
||||
jest.advanceTimersByTime(200);
|
||||
await flushPromisesWithFakeTimers();
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "View" }));
|
||||
});
|
||||
|
||||
it("should not skip to auto join", async () => {
|
||||
expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({ ...viewRoomParams, auto_join: true });
|
||||
});
|
||||
|
||||
it("should not prompt ask to join", async () => {
|
||||
expect(defaultDispatcher.dispatch).not.toHaveBeenCalledWith({ action: Action.PromptAskToJoin });
|
||||
});
|
||||
});
|
||||
|
||||
describe("when enabling feature", () => {
|
||||
beforeEach(async () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) =>
|
||||
setting === "feature_ask_to_join" ? true : [],
|
||||
);
|
||||
jest.spyOn(mockedClient, "getRoom").mockReturnValue(null);
|
||||
|
||||
render(<SpotlightDialog initialFilter={Filter.PublicRooms} onFinished={() => {}} />);
|
||||
|
||||
// search is debounced
|
||||
jest.advanceTimersByTime(200);
|
||||
await flushPromisesWithFakeTimers();
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Ask to join" }));
|
||||
});
|
||||
|
||||
it("should skip to auto join", async () => {
|
||||
expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({ ...viewRoomParams, auto_join: false });
|
||||
});
|
||||
|
||||
it("should prompt ask to join", async () => {
|
||||
expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({ action: Action.PromptAskToJoin });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue