mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-15 20:54:59 +08:00
Allow reactions for broadcasts (#9856)
This commit is contained in:
parent
720bf0573a
commit
488a08a25e
@ -59,6 +59,7 @@ import { Action } from "../../../dispatcher/actions";
|
|||||||
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
|
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
|
||||||
import useFavouriteMessages from "../../../hooks/useFavouriteMessages";
|
import useFavouriteMessages from "../../../hooks/useFavouriteMessages";
|
||||||
import { GetRelationsForEvent } from "../rooms/EventTile";
|
import { GetRelationsForEvent } from "../rooms/EventTile";
|
||||||
|
import { VoiceBroadcastInfoEventType } from "../../../voice-broadcast/types";
|
||||||
|
|
||||||
interface IOptionsButtonProps {
|
interface IOptionsButtonProps {
|
||||||
mxEvent: MatrixEvent;
|
mxEvent: MatrixEvent;
|
||||||
@ -394,7 +395,8 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
|
|||||||
* until cross-platform support
|
* until cross-platform support
|
||||||
* (PSF-1041)
|
* (PSF-1041)
|
||||||
*/
|
*/
|
||||||
!M_BEACON_INFO.matches(this.props.mxEvent.getType());
|
!M_BEACON_INFO.matches(this.props.mxEvent.getType()) &&
|
||||||
|
!(this.props.mxEvent.getType() === VoiceBroadcastInfoEventType);
|
||||||
|
|
||||||
return inNotThreadTimeline && isAllowedMessageType;
|
return inNotThreadTimeline && isAllowedMessageType;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
|
|||||||
import { MatrixEvent, MatrixClient } from "matrix-js-sdk/src/matrix";
|
import { MatrixEvent, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { getShareableLocationEventForBeacon } from "../../utils/beacon/getShareableLocation";
|
import { getShareableLocationEventForBeacon } from "../../utils/beacon/getShareableLocation";
|
||||||
|
import { VoiceBroadcastInfoEventType } from "../../voice-broadcast/types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get forwardable event for a given event
|
* Get forwardable event for a given event
|
||||||
@ -29,6 +30,8 @@ export const getForwardableEvent = (event: MatrixEvent, cli: MatrixClient): Matr
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.getType() === VoiceBroadcastInfoEventType) return null;
|
||||||
|
|
||||||
// Live location beacons should forward their latest location as a static pin location
|
// Live location beacons should forward their latest location as a static pin location
|
||||||
// If the beacon is not live, or doesn't have a location forwarding is not allowed
|
// If the beacon is not live, or doesn't have a location forwarding is not allowed
|
||||||
if (M_BEACON_INFO.matches(event.getType())) {
|
if (M_BEACON_INFO.matches(event.getType())) {
|
||||||
|
@ -32,6 +32,7 @@ import { TimelineRenderingType } from "../contexts/RoomContext";
|
|||||||
import { launchPollEditor } from "../components/views/messages/MPollBody";
|
import { launchPollEditor } from "../components/views/messages/MPollBody";
|
||||||
import { Action } from "../dispatcher/actions";
|
import { Action } from "../dispatcher/actions";
|
||||||
import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload";
|
import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload";
|
||||||
|
import { VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "../voice-broadcast/types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether an event should allow actions like reply, reactions, edit, etc.
|
* Returns whether an event should allow actions like reply, reactions, edit, etc.
|
||||||
@ -56,7 +57,9 @@ export function isContentActionable(mxEvent: MatrixEvent): boolean {
|
|||||||
} else if (
|
} else if (
|
||||||
mxEvent.getType() === "m.sticker" ||
|
mxEvent.getType() === "m.sticker" ||
|
||||||
M_POLL_START.matches(mxEvent.getType()) ||
|
M_POLL_START.matches(mxEvent.getType()) ||
|
||||||
M_BEACON_INFO.matches(mxEvent.getType())
|
M_BEACON_INFO.matches(mxEvent.getType()) ||
|
||||||
|
(mxEvent.getType() === VoiceBroadcastInfoEventType &&
|
||||||
|
mxEvent.getContent()?.state === VoiceBroadcastInfoState.Started)
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -42,14 +42,15 @@ import dispatcher from "../../../../src/dispatcher/dispatcher";
|
|||||||
import SettingsStore from "../../../../src/settings/SettingsStore";
|
import SettingsStore from "../../../../src/settings/SettingsStore";
|
||||||
import { ReadPinsEventId } from "../../../../src/components/views/right_panel/types";
|
import { ReadPinsEventId } from "../../../../src/components/views/right_panel/types";
|
||||||
import { Action } from "../../../../src/dispatcher/actions";
|
import { Action } from "../../../../src/dispatcher/actions";
|
||||||
|
import { mkVoiceBroadcastInfoStateEvent } from "../../../voice-broadcast/utils/test-utils";
|
||||||
|
import { VoiceBroadcastInfoState } from "../../../../src/voice-broadcast";
|
||||||
|
|
||||||
jest.mock("../../../../src/utils/strings", () => ({
|
jest.mock("../../../../src/utils/strings", () => ({
|
||||||
copyPlaintext: jest.fn(),
|
copyPlaintext: jest.fn(),
|
||||||
getSelectedText: jest.fn(),
|
getSelectedText: jest.fn(),
|
||||||
}));
|
}));
|
||||||
jest.mock("../../../../src/utils/EventUtils", () => ({
|
jest.mock("../../../../src/utils/EventUtils", () => ({
|
||||||
// @ts-ignore don't mock everything
|
...(jest.requireActual("../../../../src/utils/EventUtils") as object),
|
||||||
...jest.requireActual("../../../../src/utils/EventUtils"),
|
|
||||||
canEditContent: jest.fn(),
|
canEditContent: jest.fn(),
|
||||||
}));
|
}));
|
||||||
jest.mock("../../../../src/dispatcher/dispatcher");
|
jest.mock("../../../../src/dispatcher/dispatcher");
|
||||||
@ -241,6 +242,17 @@ describe("MessageContextMenu", () => {
|
|||||||
expect(menu.find('div[aria-label="Forward"]')).toHaveLength(0);
|
expect(menu.find('div[aria-label="Forward"]')).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should not allow forwarding a voice broadcast", () => {
|
||||||
|
const broadcastStartEvent = mkVoiceBroadcastInfoStateEvent(
|
||||||
|
roomId,
|
||||||
|
VoiceBroadcastInfoState.Started,
|
||||||
|
"@user:example.com",
|
||||||
|
"ABC123",
|
||||||
|
);
|
||||||
|
const menu = createMenu(broadcastStartEvent);
|
||||||
|
expect(menu.find('div[aria-label="Forward"]')).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
describe("forwarding beacons", () => {
|
describe("forwarding beacons", () => {
|
||||||
const aliceId = "@alice:server.org";
|
const aliceId = "@alice:server.org";
|
||||||
|
|
||||||
|
@ -15,8 +15,7 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { render, fireEvent } from "@testing-library/react";
|
import { act, render, fireEvent } from "@testing-library/react";
|
||||||
import { act } from "react-test-renderer";
|
|
||||||
import { EventType, EventStatus, MatrixEvent, MatrixEventEvent, MsgType, Room } from "matrix-js-sdk/src/matrix";
|
import { EventType, EventStatus, MatrixEvent, MatrixEventEvent, MsgType, Room } from "matrix-js-sdk/src/matrix";
|
||||||
import { FeatureSupport, Thread } from "matrix-js-sdk/src/models/thread";
|
import { FeatureSupport, Thread } from "matrix-js-sdk/src/models/thread";
|
||||||
|
|
||||||
@ -34,6 +33,8 @@ import dispatcher from "../../../../src/dispatcher/dispatcher";
|
|||||||
import SettingsStore from "../../../../src/settings/SettingsStore";
|
import SettingsStore from "../../../../src/settings/SettingsStore";
|
||||||
import { Action } from "../../../../src/dispatcher/actions";
|
import { Action } from "../../../../src/dispatcher/actions";
|
||||||
import { UserTab } from "../../../../src/components/views/dialogs/UserTab";
|
import { UserTab } from "../../../../src/components/views/dialogs/UserTab";
|
||||||
|
import { mkVoiceBroadcastInfoStateEvent } from "../../../voice-broadcast/utils/test-utils";
|
||||||
|
import { VoiceBroadcastInfoState } from "../../../../src/voice-broadcast";
|
||||||
|
|
||||||
jest.mock("../../../../src/dispatcher/dispatcher");
|
jest.mock("../../../../src/dispatcher/dispatcher");
|
||||||
|
|
||||||
@ -405,6 +406,17 @@ describe("<MessageActionBar />", () => {
|
|||||||
expect(queryByLabelText("Reply in thread")).toBeTruthy();
|
expect(queryByLabelText("Reply in thread")).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not render thread button for a voice broadcast", () => {
|
||||||
|
const broadcastEvent = mkVoiceBroadcastInfoStateEvent(
|
||||||
|
roomId,
|
||||||
|
VoiceBroadcastInfoState.Started,
|
||||||
|
userId,
|
||||||
|
"ABC123",
|
||||||
|
);
|
||||||
|
const { queryByLabelText } = getComponent({ mxEvent: broadcastEvent });
|
||||||
|
expect(queryByLabelText("Reply in thread")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it("opens user settings on click", () => {
|
it("opens user settings on click", () => {
|
||||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
||||||
const { getByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
const { getByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||||
|
@ -43,6 +43,8 @@ import {
|
|||||||
import { getMockClientWithEventEmitter, makeBeaconInfoEvent, makePollStartEvent, stubClient } from "../test-utils";
|
import { getMockClientWithEventEmitter, makeBeaconInfoEvent, makePollStartEvent, stubClient } from "../test-utils";
|
||||||
import dis from "../../src/dispatcher/dispatcher";
|
import dis from "../../src/dispatcher/dispatcher";
|
||||||
import { Action } from "../../src/dispatcher/actions";
|
import { Action } from "../../src/dispatcher/actions";
|
||||||
|
import { mkVoiceBroadcastInfoStateEvent } from "../voice-broadcast/utils/test-utils";
|
||||||
|
import { VoiceBroadcastInfoState } from "../../src/voice-broadcast/types";
|
||||||
|
|
||||||
jest.mock("../../src/dispatcher/dispatcher");
|
jest.mock("../../src/dispatcher/dispatcher");
|
||||||
|
|
||||||
@ -151,6 +153,20 @@ describe("EventUtils", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const voiceBroadcastStart = mkVoiceBroadcastInfoStateEvent(
|
||||||
|
"!room:example.com",
|
||||||
|
VoiceBroadcastInfoState.Started,
|
||||||
|
"@user:example.com",
|
||||||
|
"ABC123",
|
||||||
|
);
|
||||||
|
|
||||||
|
const voiceBroadcastStop = mkVoiceBroadcastInfoStateEvent(
|
||||||
|
"!room:example.com",
|
||||||
|
VoiceBroadcastInfoState.Stopped,
|
||||||
|
"@user:example.com",
|
||||||
|
"ABC123",
|
||||||
|
);
|
||||||
|
|
||||||
describe("isContentActionable()", () => {
|
describe("isContentActionable()", () => {
|
||||||
type TestCase = [string, MatrixEvent];
|
type TestCase = [string, MatrixEvent];
|
||||||
it.each<TestCase>([
|
it.each<TestCase>([
|
||||||
@ -161,6 +177,7 @@ describe("EventUtils", () => {
|
|||||||
["room member event", roomMemberEvent],
|
["room member event", roomMemberEvent],
|
||||||
["event without msgtype", noMsgType],
|
["event without msgtype", noMsgType],
|
||||||
["event without content body property", noContentBody],
|
["event without content body property", noContentBody],
|
||||||
|
["broadcast stop event", voiceBroadcastStop],
|
||||||
])("returns false for %s", (_description, event) => {
|
])("returns false for %s", (_description, event) => {
|
||||||
expect(isContentActionable(event)).toBe(false);
|
expect(isContentActionable(event)).toBe(false);
|
||||||
});
|
});
|
||||||
@ -171,6 +188,7 @@ describe("EventUtils", () => {
|
|||||||
["event with empty content body", emptyContentBody],
|
["event with empty content body", emptyContentBody],
|
||||||
["event with a content body", niceTextMessage],
|
["event with a content body", niceTextMessage],
|
||||||
["beacon_info event", beaconInfoEvent],
|
["beacon_info event", beaconInfoEvent],
|
||||||
|
["broadcast start event", voiceBroadcastStart],
|
||||||
])("returns true for %s", (_description, event) => {
|
])("returns true for %s", (_description, event) => {
|
||||||
expect(isContentActionable(event)).toBe(true);
|
expect(isContentActionable(event)).toBe(true);
|
||||||
});
|
});
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
VoiceBroadcastChunkEventType,
|
VoiceBroadcastChunkEventType,
|
||||||
VoiceBroadcastInfoEventType,
|
VoiceBroadcastInfoEventType,
|
||||||
VoiceBroadcastInfoState,
|
VoiceBroadcastInfoState,
|
||||||
} from "../../../src/voice-broadcast";
|
} from "../../../src/voice-broadcast/types";
|
||||||
import { mkEvent } from "../../test-utils";
|
import { mkEvent } from "../../test-utils";
|
||||||
|
|
||||||
// timestamp incremented on each call to prevent duplicate timestamp
|
// timestamp incremented on each call to prevent duplicate timestamp
|
||||||
|
Loading…
Reference in New Issue
Block a user