Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Allow requesting to join knock rooms via spotlight (#11482)
Browse files Browse the repository at this point in the history
Signed-off-by: Charly Nguyen <charly.nguyen@nordeck.net>
  • Loading branch information
charlynguyen authored Aug 30, 2023
1 parent 200631f commit 50160b9
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 4 deletions.
36 changes: 32 additions & 4 deletions src/components/views/dialogs/spotlight/SpotlightDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 => {
Expand All @@ -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();
};

Expand Down Expand Up @@ -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();
Expand All @@ -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}`}
Expand All @@ -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`}
Expand Down
1 change: 1 addition & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"resend": "Resend",
"next": "Next",
"view": "View",
"ask_to_join": "Ask to join",
"forward": "Forward",
"copy_link": "Copy link",
"logout": "Logout",
Expand Down
73 changes: 73 additions & 0 deletions test/components/views/dialogs/SpotlightDialog-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
ConnectionError,
IProtocol,
IPublicRoomsChunkRoom,
JoinRule,
MatrixClient,
Room,
RoomMember,
Expand All @@ -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();

Expand Down Expand Up @@ -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 });
});
});
});
});

0 comments on commit 50160b9

Please sign in to comment.