Disable redacting reactions if we don't have sufficient permissions (#8767)
This commit is contained in:
parent
3f99f594de
commit
9b8b1d193e
11 changed files with 37 additions and 9 deletions
|
@ -18,7 +18,7 @@ limitations under the License.
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&.mx_AccessibleButton_disabled {
|
&.mx_AccessibleButton_disabled {
|
||||||
cursor: default;
|
cursor: not-allowed;
|
||||||
|
|
||||||
&.mx_AccessibleButton_kind_primary,
|
&.mx_AccessibleButton_kind_primary,
|
||||||
&.mx_AccessibleButton_kind_primary_outline,
|
&.mx_AccessibleButton_kind_primary_outline,
|
||||||
|
|
|
@ -169,6 +169,7 @@ export interface IRoomState {
|
||||||
searchInProgress?: boolean;
|
searchInProgress?: boolean;
|
||||||
callState?: CallState;
|
callState?: CallState;
|
||||||
canPeek: boolean;
|
canPeek: boolean;
|
||||||
|
canSelfRedact: boolean;
|
||||||
showApps: boolean;
|
showApps: boolean;
|
||||||
isPeeking: boolean;
|
isPeeking: boolean;
|
||||||
showRightPanel: boolean;
|
showRightPanel: boolean;
|
||||||
|
@ -252,6 +253,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
searchResults: null,
|
searchResults: null,
|
||||||
callState: null,
|
callState: null,
|
||||||
canPeek: false,
|
canPeek: false,
|
||||||
|
canSelfRedact: false,
|
||||||
showApps: false,
|
showApps: false,
|
||||||
isPeeking: false,
|
isPeeking: false,
|
||||||
showRightPanel: false,
|
showRightPanel: false,
|
||||||
|
@ -1173,10 +1175,14 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
private updatePermissions(room: Room) {
|
private updatePermissions(room: Room) {
|
||||||
if (room) {
|
if (room) {
|
||||||
const me = this.context.getUserId();
|
const me = this.context.getUserId();
|
||||||
const canReact = room.getMyMembership() === "join" && room.currentState.maySendEvent("m.reaction", me);
|
const canReact = (
|
||||||
|
room.getMyMembership() === "join" &&
|
||||||
|
room.currentState.maySendEvent(EventType.Reaction, me)
|
||||||
|
);
|
||||||
const canSendMessages = room.maySendMessage();
|
const canSendMessages = room.maySendMessage();
|
||||||
|
const canSelfRedact = room.currentState.maySendEvent(EventType.RoomRedaction, me);
|
||||||
|
|
||||||
this.setState({ canReact, canSendMessages });
|
this.setState({ canReact, canSendMessages, canSelfRedact });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ interface IProps {
|
||||||
onClick(emoji: IEmoji): void;
|
onClick(emoji: IEmoji): void;
|
||||||
onMouseEnter(emoji: IEmoji): void;
|
onMouseEnter(emoji: IEmoji): void;
|
||||||
onMouseLeave(emoji: IEmoji): void;
|
onMouseLeave(emoji: IEmoji): void;
|
||||||
|
isEmojiDisabled?: (unicode: string) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Category extends React.PureComponent<IProps> {
|
class Category extends React.PureComponent<IProps> {
|
||||||
|
@ -60,6 +61,7 @@ class Category extends React.PureComponent<IProps> {
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onMouseLeave={onMouseLeave}
|
onMouseLeave={onMouseLeave}
|
||||||
|
disabled={this.props.isEmojiDisabled?.(emoji.unicode)}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
}</div>);
|
}</div>);
|
||||||
|
|
|
@ -26,6 +26,7 @@ interface IProps {
|
||||||
onClick(emoji: IEmoji): void;
|
onClick(emoji: IEmoji): void;
|
||||||
onMouseEnter(emoji: IEmoji): void;
|
onMouseEnter(emoji: IEmoji): void;
|
||||||
onMouseLeave(emoji: IEmoji): void;
|
onMouseLeave(emoji: IEmoji): void;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Emoji extends React.PureComponent<IProps> {
|
class Emoji extends React.PureComponent<IProps> {
|
||||||
|
@ -40,6 +41,7 @@ class Emoji extends React.PureComponent<IProps> {
|
||||||
onMouseLeave={() => onMouseLeave(emoji)}
|
onMouseLeave={() => onMouseLeave(emoji)}
|
||||||
className="mx_EmojiPicker_item_wrapper"
|
className="mx_EmojiPicker_item_wrapper"
|
||||||
label={emoji.unicode}
|
label={emoji.unicode}
|
||||||
|
disabled={this.props.disabled}
|
||||||
>
|
>
|
||||||
<div className={`mx_EmojiPicker_item ${isSelected ? 'mx_EmojiPicker_item_selected' : ''}`}>
|
<div className={`mx_EmojiPicker_item ${isSelected ? 'mx_EmojiPicker_item_selected' : ''}`}>
|
||||||
{ emoji.unicode }
|
{ emoji.unicode }
|
||||||
|
|
|
@ -37,6 +37,7 @@ interface IProps {
|
||||||
selectedEmojis?: Set<string>;
|
selectedEmojis?: Set<string>;
|
||||||
showQuickReactions?: boolean;
|
showQuickReactions?: boolean;
|
||||||
onChoose(unicode: string): boolean;
|
onChoose(unicode: string): boolean;
|
||||||
|
isEmojiDisabled?: (unicode: string) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
|
@ -261,6 +262,7 @@ class EmojiPicker extends React.Component<IProps, IState> {
|
||||||
onClick={this.onClickEmoji}
|
onClick={this.onClickEmoji}
|
||||||
onMouseEnter={this.onHoverEmoji}
|
onMouseEnter={this.onHoverEmoji}
|
||||||
onMouseLeave={this.onHoverEmojiEnd}
|
onMouseLeave={this.onHoverEmojiEnd}
|
||||||
|
isEmojiDisabled={this.props.isEmojiDisabled}
|
||||||
selectedEmojis={this.props.selectedEmojis}
|
selectedEmojis={this.props.selectedEmojis}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -73,7 +73,7 @@ class ReactionPicker extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getReactions() {
|
private getReactions(): Record<string, string> {
|
||||||
if (!this.props.reactions) {
|
if (!this.props.reactions) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,8 @@ class ReactionPicker extends React.Component<IProps, IState> {
|
||||||
this.props.onFinished();
|
this.props.onFinished();
|
||||||
const myReactions = this.getReactions();
|
const myReactions = this.getReactions();
|
||||||
if (myReactions.hasOwnProperty(reaction)) {
|
if (myReactions.hasOwnProperty(reaction)) {
|
||||||
|
if (this.props.mxEvent.isRedacted() || !this.context.canSelfRedact) return;
|
||||||
|
|
||||||
MatrixClientPeg.get().redactEvent(this.props.mxEvent.getRoomId(), myReactions[reaction]);
|
MatrixClientPeg.get().redactEvent(this.props.mxEvent.getRoomId(), myReactions[reaction]);
|
||||||
dis.dispatch<FocusComposerPayload>({
|
dis.dispatch<FocusComposerPayload>({
|
||||||
action: Action.FocusAComposer,
|
action: Action.FocusAComposer,
|
||||||
|
@ -119,9 +121,17 @@ class ReactionPicker extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private isEmojiDisabled = (unicode: string): boolean => {
|
||||||
|
if (!this.getReactions()[unicode]) return false;
|
||||||
|
if (this.context.canSelfRedact) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <EmojiPicker
|
return <EmojiPicker
|
||||||
onChoose={this.onChoose}
|
onChoose={this.onChoose}
|
||||||
|
isEmojiDisabled={this.isEmojiDisabled}
|
||||||
selectedEmojis={this.state.selectedEmojis}
|
selectedEmojis={this.state.selectedEmojis}
|
||||||
showQuickReactions={true}
|
showQuickReactions={true}
|
||||||
data-testid='mx_ReactionPicker'
|
data-testid='mx_ReactionPicker'
|
||||||
|
|
|
@ -183,7 +183,10 @@ export default class ReactionsRow extends React.PureComponent<IProps, IState> {
|
||||||
mxEvent={mxEvent}
|
mxEvent={mxEvent}
|
||||||
reactionEvents={events}
|
reactionEvents={events}
|
||||||
myReactionEvent={myReactionEvent}
|
myReactionEvent={myReactionEvent}
|
||||||
disabled={!this.context.canReact}
|
disabled={
|
||||||
|
!this.context.canReact ||
|
||||||
|
(myReactionEvent && !myReactionEvent.isRedacted() && !this.context.canSelfRedact)
|
||||||
|
}
|
||||||
/>;
|
/>;
|
||||||
}).filter(item => !!item);
|
}).filter(item => !!item);
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ interface IState {
|
||||||
|
|
||||||
export default class ReactionsRowButton extends React.PureComponent<IProps, IState> {
|
export default class ReactionsRowButton extends React.PureComponent<IProps, IState> {
|
||||||
static contextType = MatrixClientContext;
|
static contextType = MatrixClientContext;
|
||||||
|
public context!: React.ContextType<typeof MatrixClientContext>;
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
tooltipRendered: false,
|
tooltipRendered: false,
|
||||||
|
|
|
@ -43,6 +43,7 @@ const RoomContext = createContext<IRoomState>({
|
||||||
showTopUnreadMessagesBar: false,
|
showTopUnreadMessagesBar: false,
|
||||||
statusBarVisible: false,
|
statusBarVisible: false,
|
||||||
canReact: false,
|
canReact: false,
|
||||||
|
canSelfRedact: false,
|
||||||
canSendMessages: false,
|
canSendMessages: false,
|
||||||
resizing: false,
|
resizing: false,
|
||||||
layout: Layout.Group,
|
layout: Layout.Group,
|
||||||
|
|
|
@ -209,6 +209,7 @@ function createRoomState(room: Room, narrow: boolean): IRoomState {
|
||||||
shouldPeek: true,
|
shouldPeek: true,
|
||||||
membersLoaded: false,
|
membersLoaded: false,
|
||||||
numUnreadMessages: 0,
|
numUnreadMessages: 0,
|
||||||
|
canSelfRedact: false,
|
||||||
canPeek: false,
|
canPeek: false,
|
||||||
showApps: false,
|
showApps: false,
|
||||||
isPeeking: false,
|
isPeeking: false,
|
||||||
|
|
|
@ -48,21 +48,18 @@ const WrapWithProviders: React.FC<{
|
||||||
</MatrixClientContext.Provider>;
|
</MatrixClientContext.Provider>;
|
||||||
|
|
||||||
describe('<SendMessageComposer/>', () => {
|
describe('<SendMessageComposer/>', () => {
|
||||||
const defaultRoomContext = {
|
const defaultRoomContext: IRoomState = {
|
||||||
roomLoading: true,
|
roomLoading: true,
|
||||||
peekLoading: false,
|
peekLoading: false,
|
||||||
shouldPeek: true,
|
shouldPeek: true,
|
||||||
membersLoaded: false,
|
membersLoaded: false,
|
||||||
numUnreadMessages: 0,
|
numUnreadMessages: 0,
|
||||||
searching: false,
|
|
||||||
guestsCanJoin: false,
|
|
||||||
canPeek: false,
|
canPeek: false,
|
||||||
showApps: false,
|
showApps: false,
|
||||||
isPeeking: false,
|
isPeeking: false,
|
||||||
showRightPanel: true,
|
showRightPanel: true,
|
||||||
joining: false,
|
joining: false,
|
||||||
atEndOfLiveTimeline: true,
|
atEndOfLiveTimeline: true,
|
||||||
atEndOfLiveTimelineInit: false,
|
|
||||||
showTopUnreadMessagesBar: false,
|
showTopUnreadMessagesBar: false,
|
||||||
statusBarVisible: false,
|
statusBarVisible: false,
|
||||||
canReact: false,
|
canReact: false,
|
||||||
|
@ -82,6 +79,9 @@ describe('<SendMessageComposer/>', () => {
|
||||||
matrixClientIsReady: false,
|
matrixClientIsReady: false,
|
||||||
timelineRenderingType: TimelineRenderingType.Room,
|
timelineRenderingType: TimelineRenderingType.Room,
|
||||||
liveTimeline: undefined,
|
liveTimeline: undefined,
|
||||||
|
canSelfRedact: false,
|
||||||
|
resizing: false,
|
||||||
|
narrow: false,
|
||||||
};
|
};
|
||||||
describe("createMessageContent", () => {
|
describe("createMessageContent", () => {
|
||||||
const permalinkCreator = jest.fn() as any;
|
const permalinkCreator = jest.fn() as any;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue