mirror of https://github.com/vector-im/riot-web
Add voice broadcast permissions (#9284)
* Add Voice Broadcast labs setting and composer button * Implement strict typing * Extend MessageComposer-test * Extend tests * Revert some strict type fixex * Implement voice broadcast permissions * Update variable casingpull/28788/head^2
parent
cb735c9439
commit
0cc4f4e1bc
|
@ -119,6 +119,7 @@ import { isLocalRoom } from '../../utils/localRoom/isLocalRoom';
|
|||
import { ShowThreadPayload } from "../../dispatcher/payloads/ShowThreadPayload";
|
||||
import { RoomStatusBarUnsentMessages } from './RoomStatusBarUnsentMessages';
|
||||
import { LargeLoader } from './LargeLoader';
|
||||
import { VoiceBroadcastInfoEventType } from '../../voice-broadcast';
|
||||
import { isVideoRoom } from '../../utils/video-rooms';
|
||||
|
||||
const DEBUG = false;
|
||||
|
@ -200,6 +201,7 @@ export interface IRoomState {
|
|||
upgradeRecommendation?: IRecommendedVersion;
|
||||
canReact: boolean;
|
||||
canSendMessages: boolean;
|
||||
canSendVoiceBroadcasts: boolean;
|
||||
tombstone?: MatrixEvent;
|
||||
resizing: boolean;
|
||||
layout: Layout;
|
||||
|
@ -402,6 +404,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
statusBarVisible: false,
|
||||
canReact: false,
|
||||
canSendMessages: false,
|
||||
canSendVoiceBroadcasts: false,
|
||||
resizing: false,
|
||||
layout: SettingsStore.getValue("layout"),
|
||||
lowBandwidth: SettingsStore.getValue("lowBandwidth"),
|
||||
|
@ -1346,8 +1349,14 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
);
|
||||
const canSendMessages = room.maySendMessage();
|
||||
const canSelfRedact = room.currentState.maySendEvent(EventType.RoomRedaction, me);
|
||||
const canSendVoiceBroadcasts = room.currentState.maySendEvent(VoiceBroadcastInfoEventType, me);
|
||||
|
||||
this.setState({ canReact, canSendMessages, canSelfRedact });
|
||||
this.setState({
|
||||
canReact,
|
||||
canSendMessages,
|
||||
canSendVoiceBroadcasts,
|
||||
canSelfRedact,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2220,6 +2229,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
resizeNotifier={this.props.resizeNotifier}
|
||||
replyToEvent={this.state.replyToEvent}
|
||||
permalinkCreator={this.permalinkCreator}
|
||||
showVoiceBroadcastButton={this.state.canSendVoiceBroadcasts}
|
||||
/>;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ interface IProps {
|
|||
relation?: IEventRelation;
|
||||
e2eStatus?: E2EStatus;
|
||||
compact?: boolean;
|
||||
showVoiceBroadcastButton?: boolean;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
@ -107,6 +108,7 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
|||
|
||||
public static defaultProps = {
|
||||
compact: false,
|
||||
showVoiceBroadcastButton: false,
|
||||
};
|
||||
|
||||
public constructor(props: IProps) {
|
||||
|
@ -368,6 +370,10 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
|||
return this.state.showStickersButton && !isLocalRoom(this.props.room);
|
||||
}
|
||||
|
||||
private get showVoiceBroadcastButton(): boolean {
|
||||
return this.props.showVoiceBroadcastButton && this.state.showVoiceBroadcastButton;
|
||||
}
|
||||
|
||||
public render() {
|
||||
const controls = [
|
||||
this.props.e2eStatus ?
|
||||
|
@ -495,7 +501,7 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
|||
showPollsButton={this.state.showPollsButton}
|
||||
showStickersButton={this.showStickersButton}
|
||||
toggleButtonMenu={this.toggleButtonMenu}
|
||||
showVoiceBroadcastButton={this.state.showVoiceBroadcastButton}
|
||||
showVoiceBroadcastButton={this.showVoiceBroadcastButton}
|
||||
onStartVoiceBroadcastClick={() => {
|
||||
// Sends a voice message. To be replaced by voice broadcast during development.
|
||||
this.voiceRecordingButton.current?.onRecordStartEndClick();
|
||||
|
|
|
@ -30,6 +30,7 @@ import ErrorDialog from '../../../dialogs/ErrorDialog';
|
|||
import PowerSelector from "../../../elements/PowerSelector";
|
||||
import SettingsFieldset from '../../SettingsFieldset';
|
||||
import SettingsStore from "../../../../../settings/SettingsStore";
|
||||
import { VoiceBroadcastInfoEventType } from '../../../../../voice-broadcast';
|
||||
|
||||
interface IEventShowOpts {
|
||||
isState?: boolean;
|
||||
|
@ -61,6 +62,7 @@ const plEventsToShow: Record<string, IEventShowOpts> = {
|
|||
|
||||
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
|
||||
"im.vector.modular.widgets": { isState: true, hideForSpace: true },
|
||||
[VoiceBroadcastInfoEventType]: { isState: true, hideForSpace: true },
|
||||
};
|
||||
|
||||
// parse a string as an integer; if the input is undefined, or cannot be parsed
|
||||
|
@ -244,6 +246,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
|
|||
|
||||
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
|
||||
"im.vector.modular.widgets": isSpaceRoom ? null : _td("Modify widgets"),
|
||||
[VoiceBroadcastInfoEventType]: _td("Voice broadcasts"),
|
||||
};
|
||||
|
||||
if (SettingsStore.getValue("feature_pinning")) {
|
||||
|
|
|
@ -45,6 +45,7 @@ const RoomContext = createContext<IRoomState>({
|
|||
canReact: false,
|
||||
canSelfRedact: false,
|
||||
canSendMessages: false,
|
||||
canSendVoiceBroadcasts: false,
|
||||
resizing: false,
|
||||
layout: Layout.Group,
|
||||
lowBandwidth: false,
|
||||
|
|
|
@ -1642,6 +1642,7 @@
|
|||
"Send reactions": "Send reactions",
|
||||
"Remove messages sent by me": "Remove messages sent by me",
|
||||
"Modify widgets": "Modify widgets",
|
||||
"Voice broadcasts": "Voice broadcasts",
|
||||
"Manage pinned events": "Manage pinned events",
|
||||
"Default role": "Default role",
|
||||
"Send messages": "Send messages",
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
export const VoiceBroadcastInfoEventType = "io.element.voice_broadcast_info";
|
|
@ -137,7 +137,7 @@ describe("MessageComposer", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
SettingsStore.setValue(setting, null, SettingLevel.DEVICE, value);
|
||||
wrapper = wrapAndRender({ room });
|
||||
wrapper = wrapAndRender({ room, showVoiceBroadcastButton: true });
|
||||
});
|
||||
|
||||
it(`should pass the prop ${prop} = ${value}`, () => {
|
||||
|
@ -164,6 +164,17 @@ describe("MessageComposer", () => {
|
|||
});
|
||||
});
|
||||
|
||||
[false, undefined].forEach((value) => {
|
||||
it(`should pass showVoiceBroadcastButton = false if the MessageComposer prop is ${value}`, () => {
|
||||
SettingsStore.setValue(Features.VoiceBroadcast, null, SettingLevel.DEVICE, true);
|
||||
const wrapper = wrapAndRender({
|
||||
room,
|
||||
showVoiceBroadcastButton: value,
|
||||
});
|
||||
expect(wrapper.find(MessageComposerButtons).props().showVoiceBroadcastButton).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it("should not render the send button", () => {
|
||||
const wrapper = wrapAndRender({ room });
|
||||
expect(wrapper.find("SendButton")).toHaveLength(0);
|
||||
|
|
|
@ -250,6 +250,7 @@ function createRoomState(room: Room, narrow: boolean): IRoomState {
|
|||
statusBarVisible: false,
|
||||
canReact: false,
|
||||
canSendMessages: false,
|
||||
canSendVoiceBroadcasts: false,
|
||||
layout: Layout.Group,
|
||||
lowBandwidth: false,
|
||||
alwaysShowTimestamps: false,
|
||||
|
|
|
@ -72,6 +72,7 @@ describe('<SendMessageComposer/>', () => {
|
|||
statusBarVisible: false,
|
||||
canReact: false,
|
||||
canSendMessages: false,
|
||||
canSendVoiceBroadcasts: false,
|
||||
layout: Layout.Group,
|
||||
lowBandwidth: false,
|
||||
alwaysShowTimestamps: false,
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { fireEvent, render, RenderResult } from "@testing-library/react";
|
||||
import { EventType, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import RolesRoomSettingsTab from "../../../../../../src/components/views/settings/tabs/room/RolesRoomSettingsTab";
|
||||
import { mkStubRoom, stubClient } from "../../../../../test-utils";
|
||||
import { MatrixClientPeg } from "../../../../../../src/MatrixClientPeg";
|
||||
import { VoiceBroadcastInfoEventType } from "../../../../../../src/voice-broadcast";
|
||||
|
||||
describe("RolesRoomSettingsTab", () => {
|
||||
const roomId = "!room:example.com";
|
||||
let rolesRoomSettingsTab: RenderResult;
|
||||
let cli: MatrixClient;
|
||||
|
||||
const getVoiceBroadcastsSelect = () => {
|
||||
return rolesRoomSettingsTab.container.querySelector("select[label='Voice broadcasts']");
|
||||
};
|
||||
|
||||
const getVoiceBroadcastsSelectedOption = () => {
|
||||
return rolesRoomSettingsTab.container.querySelector("select[label='Voice broadcasts'] option:checked");
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
cli = MatrixClientPeg.get();
|
||||
rolesRoomSettingsTab = render(<RolesRoomSettingsTab roomId={roomId} />);
|
||||
mkStubRoom(roomId, "test room", cli);
|
||||
});
|
||||
|
||||
it("should initially show »Moderator« permission for »Voice broadcasts«", () => {
|
||||
expect(getVoiceBroadcastsSelectedOption().textContent).toBe("Moderator");
|
||||
});
|
||||
|
||||
describe("when setting »Default« permission for »Voice broadcasts«", () => {
|
||||
beforeEach(() => {
|
||||
fireEvent.change(getVoiceBroadcastsSelect(), {
|
||||
target: { value: 0 },
|
||||
});
|
||||
});
|
||||
|
||||
it("should update the power levels", () => {
|
||||
expect(cli.sendStateEvent).toHaveBeenCalledWith(
|
||||
roomId,
|
||||
EventType.RoomPowerLevels,
|
||||
{
|
||||
events: {
|
||||
[VoiceBroadcastInfoEventType]: 0,
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue