Apply prettier formatting

This commit is contained in:
Michael Weimann 2022-12-12 12:24:14 +01:00
parent 1cac306093
commit 526645c791
No known key found for this signature in database
GPG key ID: 53F535A266BB9584
1576 changed files with 65385 additions and 62478 deletions

View file

@ -34,12 +34,14 @@ interface IDeviceContextMenuDeviceProps {
}
const DeviceContextMenuDevice: React.FC<IDeviceContextMenuDeviceProps> = ({ label, selected, onClick }) => {
return <IconizedContextMenuRadio
iconClassName="mx_DeviceContextMenu_device_icon"
label={label}
active={selected}
onClick={onClick}
/>;
return (
<IconizedContextMenuRadio
iconClassName="mx_DeviceContextMenu_device_icon"
label={label}
active={selected}
onClick={onClick}
/>
);
};
interface IDeviceContextMenuSectionProps {
@ -62,16 +64,20 @@ const DeviceContextMenuSection: React.FC<IDeviceContextMenuSectionProps> = ({ de
setSelectedDevice(deviceId);
};
return <IconizedContextMenuOptionList label={_t(SECTION_NAMES[deviceKind])}>
{ devices.map(({ label, deviceId }) => {
return <DeviceContextMenuDevice
key={deviceId}
label={label}
selected={selectedDevice === deviceId}
onClick={() => onDeviceClick(deviceId)}
/>;
}) }
</IconizedContextMenuOptionList>;
return (
<IconizedContextMenuOptionList label={_t(SECTION_NAMES[deviceKind])}>
{devices.map(({ label, deviceId }) => {
return (
<DeviceContextMenuDevice
key={deviceId}
label={label}
selected={selectedDevice === deviceId}
onClick={() => onDeviceClick(deviceId)}
/>
);
})}
</IconizedContextMenuOptionList>
);
};
interface IProps extends IContextMenuProps {
@ -79,11 +85,13 @@ interface IProps extends IContextMenuProps {
}
const DeviceContextMenu: React.FC<IProps> = ({ deviceKinds, ...props }) => {
return <IconizedContextMenu compact className="mx_DeviceContextMenu" {...props}>
{ deviceKinds.map((kind) => {
return <DeviceContextMenuSection key={kind} deviceKind={kind as MediaDeviceKindEnum} />;
}) }
</IconizedContextMenu>;
return (
<IconizedContextMenu compact className="mx_DeviceContextMenu" {...props}>
{deviceKinds.map((kind) => {
return <DeviceContextMenuSection key={kind} deviceKind={kind as MediaDeviceKindEnum} />;
})}
</IconizedContextMenu>
);
};
export default DeviceContextMenu;

View file

@ -16,12 +16,12 @@ limitations under the License.
import * as React from "react";
import { createRef } from "react";
import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
import { MatrixCall } from "matrix-js-sdk/src/webrtc/call";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import ContextMenu, { IProps as IContextMenuProps } from '../../structures/ContextMenu';
import ContextMenu, { IProps as IContextMenuProps } from "../../structures/ContextMenu";
import Field from "../elements/Field";
import DialPad from '../voip/DialPad';
import DialPad from "../voip/DialPad";
interface IProps extends IContextMenuProps {
call: MatrixCall;
@ -38,7 +38,7 @@ export default class DialpadContextMenu extends React.Component<IProps, IState>
super(props);
this.state = {
value: '',
value: "",
};
}
@ -70,25 +70,27 @@ export default class DialpadContextMenu extends React.Component<IProps, IState>
};
render() {
return <ContextMenu {...this.props}>
<div className="mx_DialPadContextMenuWrapper">
<div>
<AccessibleButton className="mx_DialPadContextMenu_cancel" onClick={this.onCancelClick} />
return (
<ContextMenu {...this.props}>
<div className="mx_DialPadContextMenuWrapper">
<div>
<AccessibleButton className="mx_DialPadContextMenu_cancel" onClick={this.onCancelClick} />
</div>
<div className="mx_DialPadContextMenu_header">
<Field
ref={this.numberEntryFieldRef}
className="mx_DialPadContextMenu_dialled"
value={this.state.value}
autoFocus={true}
onKeyDown={this.onKeyDown}
onChange={this.onChange}
/>
</div>
<div className="mx_DialPadContextMenu_dialPad">
<DialPad onDigitPress={this.onDigitPress} hasDial={false} />
</div>
</div>
<div className="mx_DialPadContextMenu_header">
<Field
ref={this.numberEntryFieldRef}
className="mx_DialPadContextMenu_dialled"
value={this.state.value}
autoFocus={true}
onKeyDown={this.onKeyDown}
onChange={this.onChange}
/>
</div>
<div className="mx_DialPadContextMenu_dialPad">
<DialPad onDigitPress={this.onDigitPress} hasDial={false} />
</div>
</div>
</ContextMenu>;
</ContextMenu>
);
}
}

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import React from "react";
interface IProps {
element: React.ReactNode;
@ -48,6 +48,6 @@ export default class GenericElementContextMenu extends React.Component<IProps> {
};
public render(): JSX.Element {
return <div>{ this.props.element }</div>;
return <div>{this.props.element}</div>;
}
}

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import React from "react";
interface IProps {
message: string;
@ -22,8 +22,10 @@ interface IProps {
export default class GenericTextContextMenu extends React.Component<IProps> {
public render(): JSX.Element {
return <div className="mx_Tooltip mx_Tooltip_visible" style={{ display: "block" }}>
{ this.props.message }
</div>;
return (
<div className="mx_Tooltip mx_Tooltip_visible" style={{ display: "block" }}>
{this.props.message}
</div>
);
}
}

View file

@ -21,7 +21,8 @@ import ContextMenu, {
ChevronFace,
IProps as IContextMenuProps,
MenuItem,
MenuItemCheckbox, MenuItemRadio,
MenuItemCheckbox,
MenuItemRadio,
} from "../../structures/ContextMenu";
import { _t } from "../../../languageHandler";
@ -58,19 +59,21 @@ export const IconizedContextMenuRadio: React.FC<IRadioProps> = ({
className,
...props
}) => {
return <MenuItemRadio
{...props}
className={classNames(className, {
mx_IconizedContextMenu_item: true,
mx_IconizedContextMenu_active: active,
})}
active={active}
label={label}
>
{ iconClassName && <span className={classNames("mx_IconizedContextMenu_icon", iconClassName)} /> }
<span className="mx_IconizedContextMenu_label">{ label }</span>
{ active && <span className="mx_IconizedContextMenu_icon mx_IconizedContextMenu_checked" /> }
</MenuItemRadio>;
return (
<MenuItemRadio
{...props}
className={classNames(className, {
mx_IconizedContextMenu_item: true,
mx_IconizedContextMenu_active: active,
})}
active={active}
label={label}
>
{iconClassName && <span className={classNames("mx_IconizedContextMenu_icon", iconClassName)} />}
<span className="mx_IconizedContextMenu_label">{label}</span>
{active && <span className="mx_IconizedContextMenu_icon mx_IconizedContextMenu_checked" />}
</MenuItemRadio>
);
};
export const IconizedContextMenuCheckbox: React.FC<ICheckboxProps> = ({
@ -83,29 +86,33 @@ export const IconizedContextMenuCheckbox: React.FC<ICheckboxProps> = ({
}) => {
let marker: JSX.Element;
if (words) {
marker = <span className="mx_IconizedContextMenu_activeText">
{ active ? _t("On") : _t("Off") }
</span>;
marker = <span className="mx_IconizedContextMenu_activeText">{active ? _t("On") : _t("Off")}</span>;
} else {
marker = <span className={classNames("mx_IconizedContextMenu_icon", {
mx_IconizedContextMenu_checked: active,
mx_IconizedContextMenu_unchecked: !active,
})} />;
marker = (
<span
className={classNames("mx_IconizedContextMenu_icon", {
mx_IconizedContextMenu_checked: active,
mx_IconizedContextMenu_unchecked: !active,
})}
/>
);
}
return <MenuItemCheckbox
{...props}
className={classNames(className, {
mx_IconizedContextMenu_item: true,
mx_IconizedContextMenu_active: active,
})}
active={active}
label={label}
>
<span className={classNames("mx_IconizedContextMenu_icon", iconClassName)} />
<span className="mx_IconizedContextMenu_label">{ label }</span>
{ marker }
</MenuItemCheckbox>;
return (
<MenuItemCheckbox
{...props}
className={classNames(className, {
mx_IconizedContextMenu_item: true,
mx_IconizedContextMenu_active: active,
})}
active={active}
label={label}
>
<span className={classNames("mx_IconizedContextMenu_icon", iconClassName)} />
<span className="mx_IconizedContextMenu_label">{label}</span>
{marker}
</MenuItemCheckbox>
);
};
export const IconizedContextMenuOption: React.FC<IOptionProps> = ({
@ -116,18 +123,20 @@ export const IconizedContextMenuOption: React.FC<IOptionProps> = ({
isDestructive,
...props
}) => {
return <MenuItem
{...props}
className={classNames(className, {
mx_IconizedContextMenu_item: true,
mx_IconizedContextMenu_itemDestructive: isDestructive,
})}
label={label}
>
{ iconClassName && <span className={classNames("mx_IconizedContextMenu_icon", iconClassName)} /> }
<span className="mx_IconizedContextMenu_label">{ label }</span>
{ children }
</MenuItem>;
return (
<MenuItem
{...props}
className={classNames(className, {
mx_IconizedContextMenu_item: true,
mx_IconizedContextMenu_itemDestructive: isDestructive,
})}
label={label}
>
{iconClassName && <span className={classNames("mx_IconizedContextMenu_icon", iconClassName)} />}
<span className="mx_IconizedContextMenu_label">{label}</span>
{children}
</MenuItem>
);
};
export const IconizedContextMenuOptionList: React.FC<IOptionListProps> = ({
@ -142,10 +151,16 @@ export const IconizedContextMenuOptionList: React.FC<IOptionListProps> = ({
mx_IconizedContextMenu_optionList_red: red,
});
return <div className={classes}>
{ label && <div><span className="mx_IconizedContextMenu_optionList_label">{ label }</span></div> }
{ children }
</div>;
return (
<div className={classes}>
{label && (
<div>
<span className="mx_IconizedContextMenu_optionList_label">{label}</span>
</div>
)}
{children}
</div>
);
};
const IconizedContextMenu: React.FC<IProps> = ({ className, children, compact, ...props }) => {
@ -153,12 +168,11 @@ const IconizedContextMenu: React.FC<IProps> = ({ className, children, compact, .
mx_IconizedContextMenu_compact: compact,
});
return <ContextMenu chevronFace={ChevronFace.None} {...props}>
<div className={classes}>
{ children }
</div>
</ContextMenu>;
return (
<ContextMenu chevronFace={ChevronFace.None} {...props}>
<div className={classes}>{children}</div>
</ContextMenu>
);
};
export default IconizedContextMenu;

View file

@ -14,12 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import React from "react";
import { Icon as ContextMenuIcon } from '../../../../res/img/element-icons/context-menu.svg';
import { ChevronFace, ContextMenuButton, useContextMenu } from '../../structures/ContextMenu';
import AccessibleButton from '../elements/AccessibleButton';
import IconizedContextMenu, { IconizedContextMenuOptionList } from './IconizedContextMenu';
import { Icon as ContextMenuIcon } from "../../../../res/img/element-icons/context-menu.svg";
import { ChevronFace, ContextMenuButton, useContextMenu } from "../../structures/ContextMenu";
import AccessibleButton from "../elements/AccessibleButton";
import IconizedContextMenu, { IconizedContextMenuOptionList } from "./IconizedContextMenu";
const contextMenuBelow = (elementRect: DOMRect) => {
// align the context menu's icons with the icon which opened the context menu
@ -34,33 +34,25 @@ interface KebabContextMenuProps extends Partial<React.ComponentProps<typeof Acce
title: string;
}
export const KebabContextMenu: React.FC<KebabContextMenuProps> = ({
options,
title,
...props
}) => {
export const KebabContextMenu: React.FC<KebabContextMenuProps> = ({ options, title, ...props }) => {
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
return <>
<ContextMenuButton
{...props}
onClick={openMenu}
title={title}
isExpanded={menuDisplayed}
inputRef={button}
>
<ContextMenuIcon className='mx_KebabContextMenu_icon' />
</ContextMenuButton>
{ menuDisplayed && (<IconizedContextMenu
onFinished={closeMenu}
compact
rightAligned
closeOnInteraction
{...contextMenuBelow(button.current.getBoundingClientRect())}
>
<IconizedContextMenuOptionList>
{ options }
</IconizedContextMenuOptionList>
</IconizedContextMenu>) }
</>;
return (
<>
<ContextMenuButton {...props} onClick={openMenu} title={title} isExpanded={menuDisplayed} inputRef={button}>
<ContextMenuIcon className="mx_KebabContextMenu_icon" />
</ContextMenuButton>
{menuDisplayed && (
<IconizedContextMenu
onFinished={closeMenu}
compact
rightAligned
closeOnInteraction
{...contextMenuBelow(button.current.getBoundingClientRect())}
>
<IconizedContextMenuOptionList>{options}</IconizedContextMenuOptionList>
</IconizedContextMenu>
)}
</>
);
};

View file

@ -14,12 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
import React from "react";
import { MatrixCall } from "matrix-js-sdk/src/webrtc/call";
import { _t } from '../../../languageHandler';
import ContextMenu, { IProps as IContextMenuProps, MenuItem } from '../../structures/ContextMenu';
import LegacyCallHandler from '../../../LegacyCallHandler';
import { _t } from "../../../languageHandler";
import ContextMenu, { IProps as IContextMenuProps, MenuItem } from "../../structures/ContextMenu";
import LegacyCallHandler from "../../../LegacyCallHandler";
interface IProps extends IContextMenuProps {
call: MatrixCall;
@ -52,16 +52,20 @@ export default class LegacyCallContextMenu extends React.Component<IProps> {
let transferItem;
if (this.props.call.opponentCanBeTransferred()) {
transferItem = <MenuItem className="mx_LegacyCallContextMenu_item" onClick={this.onTransferClick}>
{ _t("Transfer") }
</MenuItem>;
transferItem = (
<MenuItem className="mx_LegacyCallContextMenu_item" onClick={this.onTransferClick}>
{_t("Transfer")}
</MenuItem>
);
}
return <ContextMenu {...this.props}>
<MenuItem className="mx_LegacyCallContextMenu_item" onClick={handler}>
{ holdUnholdCaption }
</MenuItem>
{ transferItem }
</ContextMenu>;
return (
<ContextMenu {...this.props}>
<MenuItem className="mx_LegacyCallContextMenu_item" onClick={handler}>
{holdUnholdCaption}
</MenuItem>
{transferItem}
</ContextMenu>
);
}
}

View file

@ -16,49 +16,44 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { createRef, useContext } from 'react';
import { EventStatus, MatrixEvent } from 'matrix-js-sdk/src/models/event';
import React, { createRef, useContext } from "react";
import { EventStatus, MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, RelationType } from "matrix-js-sdk/src/@types/event";
import { Relations } from 'matrix-js-sdk/src/models/relations';
import { Relations } from "matrix-js-sdk/src/models/relations";
import { RoomMemberEvent } from "matrix-js-sdk/src/models/room-member";
import { M_POLL_START } from "matrix-events-sdk";
import { Thread } from "matrix-js-sdk/src/models/thread";
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import dis from '../../../dispatcher/dispatcher';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';
import Resend from '../../../Resend';
import SettingsStore from '../../../settings/SettingsStore';
import { isUrlPermitted } from '../../../HtmlUtils';
import {
canEditContent,
canPinEvent,
editEvent,
isContentActionable,
} from '../../../utils/EventUtils';
import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from './IconizedContextMenu';
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import dis from "../../../dispatcher/dispatcher";
import { _t } from "../../../languageHandler";
import Modal from "../../../Modal";
import Resend from "../../../Resend";
import SettingsStore from "../../../settings/SettingsStore";
import { isUrlPermitted } from "../../../HtmlUtils";
import { canEditContent, canPinEvent, editEvent, isContentActionable } from "../../../utils/EventUtils";
import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from "./IconizedContextMenu";
import { ReadPinsEventId } from "../right_panel/types";
import { Action } from "../../../dispatcher/actions";
import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks';
import { ButtonEvent } from '../elements/AccessibleButton';
import { copyPlaintext, getSelectedText } from '../../../utils/strings';
import ContextMenu, { toRightOf, IPosition, ChevronFace } from '../../structures/ContextMenu';
import ReactionPicker from '../emojipicker/ReactionPicker';
import ViewSource from '../../structures/ViewSource';
import { createRedactEventDialog } from '../dialogs/ConfirmRedactDialog';
import ShareDialog from '../dialogs/ShareDialog';
import RoomContext, { TimelineRenderingType } from '../../../contexts/RoomContext';
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
import { ButtonEvent } from "../elements/AccessibleButton";
import { copyPlaintext, getSelectedText } from "../../../utils/strings";
import ContextMenu, { toRightOf, IPosition, ChevronFace } from "../../structures/ContextMenu";
import ReactionPicker from "../emojipicker/ReactionPicker";
import ViewSource from "../../structures/ViewSource";
import { createRedactEventDialog } from "../dialogs/ConfirmRedactDialog";
import ShareDialog from "../dialogs/ShareDialog";
import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
import { ComposerInsertPayload } from "../../../dispatcher/payloads/ComposerInsertPayload";
import EndPollDialog from '../dialogs/EndPollDialog';
import { isPollEnded } from '../messages/MPollBody';
import EndPollDialog from "../dialogs/EndPollDialog";
import { isPollEnded } from "../messages/MPollBody";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { GetRelationsForEvent, IEventTileOps } from "../rooms/EventTile";
import { OpenForwardDialogPayload } from "../../../dispatcher/payloads/OpenForwardDialogPayload";
import { OpenReportEventDialogPayload } from "../../../dispatcher/payloads/OpenReportEventDialogPayload";
import { createMapSiteLinkFromEvent } from '../../../utils/location';
import { getForwardableEvent } from '../../../events/forward/getForwardableEvent';
import { getShareableLocationEvent } from '../../../events/location/getShareableLocationEvent';
import { createMapSiteLinkFromEvent } from "../../../utils/location";
import { getForwardableEvent } from "../../../events/forward/getForwardableEvent";
import { getShareableLocationEvent } from "../../../events/location/getShareableLocationEvent";
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
import { CardContext } from "../right_panel/context";
import { UserTab } from "../dialogs/UserTab";
@ -178,11 +173,13 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
// We explicitly decline to show the redact option on ACL events as it has a potential
// to obliterate the room - https://github.com/matrix-org/synapse/issues/4042
// Similarly for encryption events, since redacting them "breaks everything"
const canRedact = room.currentState.maySendRedactionForEvent(this.props.mxEvent, cli.credentials.userId)
&& this.props.mxEvent.getType() !== EventType.RoomServerAcl
&& this.props.mxEvent.getType() !== EventType.RoomEncryption;
const canRedact =
room.currentState.maySendRedactionForEvent(this.props.mxEvent, cli.credentials.userId) &&
this.props.mxEvent.getType() !== EventType.RoomServerAcl &&
this.props.mxEvent.getType() !== EventType.RoomEncryption;
let canPin = room.currentState.mayClientSendStateEvent(EventType.RoomPinnedEvents, cli) &&
let canPin =
room.currentState.mayClientSendStateEvent(EventType.RoomPinnedEvents, cli) &&
canPinEvent(this.props.mxEvent);
// HACK: Intentionally say we can't pin if the user doesn't want to use the functionality
@ -193,7 +190,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
private isPinned(): boolean {
const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
const pinnedEvent = room.currentState.getStateEvents(EventType.RoomPinnedEvents, '');
const pinnedEvent = room.currentState.getStateEvents(EventType.RoomPinnedEvents, "");
if (!pinnedEvent) return false;
const content = pinnedEvent.getContent();
return content.pinned && Array.isArray(content.pinned) && content.pinned.includes(this.props.mxEvent.getId());
@ -232,9 +229,13 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
};
private onViewSourceClick = (): void => {
Modal.createDialog(ViewSource, {
mxEvent: this.props.mxEvent,
}, 'mx_Dialog_viewsource');
Modal.createDialog(
ViewSource,
{
mxEvent: this.props.mxEvent,
},
"mx_Dialog_viewsource",
);
this.closeMenu();
};
@ -268,10 +269,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
} else {
pinnedIds.push(eventId);
cli.setRoomAccountData(room.roomId, ReadPinsEventId, {
event_ids: [
...(room.getAccountData(ReadPinsEventId)?.getContent()?.event_ids || []),
eventId,
],
event_ids: [...(room.getAccountData(ReadPinsEventId)?.getContent()?.event_ids || []), eventId],
});
}
cli.sendStateEvent(this.props.mxEvent.getRoomId(), EventType.RoomPinnedEvents, { pinned: pinnedIds }, "");
@ -328,7 +326,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
private onReplyClick = (): void => {
dis.dispatch({
action: 'reply_to_event',
action: "reply_to_event",
event: this.props.mxEvent,
context: this.context.timelineRenderingType,
});
@ -346,11 +344,15 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
private onEndPollClick = (): void => {
const matrixClient = MatrixClientPeg.get();
Modal.createDialog(EndPollDialog, {
matrixClient,
event: this.props.mxEvent,
getRelationsForEvent: this.props.getRelationsForEvent,
}, 'mx_Dialog_endPoll');
Modal.createDialog(
EndPollDialog,
{
matrixClient,
event: this.props.mxEvent,
getRelationsForEvent: this.props.getRelationsForEvent,
},
"mx_Dialog_endPoll",
);
this.closeMenu();
};
@ -358,14 +360,14 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
const cli = MatrixClientPeg.get();
const room = cli.getRoom(this.props.mxEvent.getRoomId());
const eventId = this.props.mxEvent.getId();
return room.getPendingEvents().filter(e => {
return room.getPendingEvents().filter((e) => {
const relation = e.getRelation();
return relation?.rel_type === RelationType.Annotation && relation.event_id === eventId && filter(e);
});
}
private getUnsentReactions(): MatrixEvent[] {
return this.getReactions(e => e.status === EventStatus.NOT_SENT);
return this.getReactions((e) => e.status === EventStatus.NOT_SENT);
}
private viewInRoom = (): void => {
@ -382,10 +384,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
public render(): JSX.Element {
const cli = MatrixClientPeg.get();
const me = cli.getUserId();
const {
mxEvent, rightClick, link, eventTileOps, reactions, collapseReplyChain,
...other
} = this.props;
const { mxEvent, rightClick, link, eventTileOps, reactions, collapseReplyChain, ...other } = this.props;
delete other.getRelationsForEvent;
delete other.permalinkCreator;
@ -396,10 +395,9 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
// status is SENT before remote-echo, null after
const isSent = !eventStatus || eventStatus === EventStatus.SENT;
const { timelineRenderingType, canReact, canSendMessages } = this.context;
const isThread = (
const isThread =
timelineRenderingType === TimelineRenderingType.Thread ||
timelineRenderingType === TimelineRenderingType.ThreadsList
);
timelineRenderingType === TimelineRenderingType.ThreadsList;
const isThreadRootEvent = isThread && mxEvent?.getThread()?.rootEvent === mxEvent;
let resendReactionsButton: JSX.Element;
@ -407,7 +405,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
resendReactionsButton = (
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconResend"
label={_t('Resend %(unsentCount)s reaction(s)', { unsentCount: unsentReactionsCount })}
label={_t("Resend %(unsentCount)s reaction(s)", { unsentCount: unsentReactionsCount })}
onClick={this.onResendReactionsClick}
/>
);
@ -432,15 +430,13 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconOpenInMapSite"
onClick={null}
label={_t('Open in OpenStreetMap')}
label={_t("Open in OpenStreetMap")}
element="a"
{
...{
href: mapSiteLink,
target: "_blank",
rel: "noreferrer noopener",
}
}
{...{
href: mapSiteLink,
target: "_blank",
rel: "noreferrer noopener",
}}
/>
);
}
@ -462,7 +458,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
pinButton = (
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconPin"
label={this.isPinned() ? _t('Unpin') : _t('Pin')}
label={this.isPinned() ? _t("Unpin") : _t("Pin")}
onClick={this.onPinClick}
/>
);
@ -494,7 +490,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconPermalink"
onClick={this.onShareClick}
label={_t('Share')}
label={_t("Share")}
element="a"
{
// XXX: Typescript signature for AccessibleButton doesn't work properly for non-inputs like `a`
@ -520,7 +516,8 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
}
let quoteButton: JSX.Element;
if (eventTileOps && canSendMessages) { // this event is rendered using TextualBody
if (eventTileOps && canSendMessages) {
// this event is rendered using TextualBody
quoteButton = (
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconQuote"
@ -533,14 +530,14 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
// Bridges can provide a 'external_url' to link back to the source.
let externalURLButton: JSX.Element;
if (
typeof (mxEvent.getContent().external_url) === "string" &&
typeof mxEvent.getContent().external_url === "string" &&
isUrlPermitted(mxEvent.getContent().external_url)
) {
externalURLButton = (
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconLink"
onClick={this.closeMenu}
label={_t('Source URL')}
label={_t("Source URL")}
element="a"
{
// XXX: Typescript signature for AccessibleButton doesn't work properly for non-inputs like `a`
@ -594,10 +591,10 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconCopy"
onClick={this.onCopyLinkClick}
label={_t('Copy link')}
label={_t("Copy link")}
element="a"
{
// XXX: Typescript signature for AccessibleButton doesn't work properly for non-inputs like `a`
// XXX: Typescript signature for AccessibleButton doesn't work properly for non-inputs like `a`
...{
href: link,
target: "_blank",
@ -651,12 +648,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
Thread.hasServerSideSupport &&
timelineRenderingType !== TimelineRenderingType.Thread
) {
replyInThreadButton = (
<ReplyInThreadButton
mxEvent={mxEvent}
closeMenu={this.closeMenu}
/>
);
replyInThreadButton = <ReplyInThreadButton mxEvent={mxEvent} closeMenu={this.closeMenu} />;
}
let reactButton;
@ -686,8 +678,8 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
if (copyButton || copyLinkButton) {
nativeItemsList = (
<IconizedContextMenuOptionList>
{ copyButton }
{ copyLinkButton }
{copyButton}
{copyLinkButton}
</IconizedContextMenuOptionList>
);
}
@ -696,56 +688,44 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
if (editButton || replyButton || reactButton) {
quickItemsList = (
<IconizedContextMenuOptionList>
{ reactButton }
{ replyButton }
{ replyInThreadButton }
{ editButton }
{reactButton}
{replyButton}
{replyInThreadButton}
{editButton}
</IconizedContextMenuOptionList>
);
}
const commonItemsList = (
<IconizedContextMenuOptionList>
{ viewInRoomButton }
{ openInMapSiteButton }
{ endPollButton }
{ quoteButton }
{ forwardButton }
{ pinButton }
{ permalinkButton }
{ reportEventButton }
{ externalURLButton }
{ jumpToRelatedEventButton }
{ unhidePreviewButton }
{ viewSourceButton }
{ resendReactionsButton }
{ collapseReplyChainButton }
{viewInRoomButton}
{openInMapSiteButton}
{endPollButton}
{quoteButton}
{forwardButton}
{pinButton}
{permalinkButton}
{reportEventButton}
{externalURLButton}
{jumpToRelatedEventButton}
{unhidePreviewButton}
{viewSourceButton}
{resendReactionsButton}
{collapseReplyChainButton}
</IconizedContextMenuOptionList>
);
let redactItemList: JSX.Element;
if (redactButton) {
redactItemList = (
<IconizedContextMenuOptionList red>
{ redactButton }
</IconizedContextMenuOptionList>
);
redactItemList = <IconizedContextMenuOptionList red>{redactButton}</IconizedContextMenuOptionList>;
}
let reactionPicker: JSX.Element;
if (this.state.reactionPickerDisplayed) {
const buttonRect = (this.reactButtonRef.current as HTMLElement)?.getBoundingClientRect();
reactionPicker = (
<ContextMenu
{...toRightOf(buttonRect)}
onFinished={this.closeMenu}
managed={false}
>
<ReactionPicker
mxEvent={mxEvent}
onFinished={this.onCloseReactionPicker}
reactions={reactions}
/>
<ContextMenu {...toRightOf(buttonRect)} onFinished={this.closeMenu} managed={false}>
<ReactionPicker mxEvent={mxEvent} onFinished={this.onCloseReactionPicker} reactions={reactions} />
</ContextMenu>
);
}
@ -758,14 +738,13 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
compact={true}
data-testid="mx_MessageContextMenu"
>
{ nativeItemsList }
{ quickItemsList }
{ commonItemsList }
{ redactItemList }
{nativeItemsList}
{quickItemsList}
{commonItemsList}
{redactItemList}
</IconizedContextMenu>
{ reactionPicker }
{reactionPicker}
</React.Fragment>
);
}
}

View file

@ -37,7 +37,7 @@ import Modal from "../../../Modal";
import ExportDialog from "../dialogs/ExportDialog";
import { useFeatureEnabled } from "../../../hooks/useSettings";
import { usePinnedEvents } from "../right_panel/PinnedMessagesCard";
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases";
import { ROOM_NOTIFICATIONS_TAB } from "../dialogs/RoomSettingsDialog";
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
@ -57,10 +57,8 @@ interface IProps extends IContextMenuProps {
const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
const cli = useContext(MatrixClientContext);
const roomTags = useEventEmitterState(
RoomListStore.instance,
LISTS_UPDATE_EVENT,
() => RoomListStore.instance.getTagsForRoom(room),
const roomTags = useEventEmitterState(RoomListStore.instance, LISTS_UPDATE_EVENT, () =>
RoomListStore.instance.getTagsForRoom(room),
);
let leaveOption: JSX.Element;
@ -76,12 +74,14 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
onFinished();
};
leaveOption = <IconizedContextMenuOption
iconClassName="mx_RoomTile_iconSignOut"
label={_t("Forget")}
className="mx_IconizedContextMenu_option_red"
onClick={onForgetRoomClick}
/>;
leaveOption = (
<IconizedContextMenuOption
iconClassName="mx_RoomTile_iconSignOut"
label={_t("Forget")}
className="mx_IconizedContextMenu_option_red"
onClick={onForgetRoomClick}
/>
);
} else {
const onLeaveRoomClick = (ev: ButtonEvent) => {
ev.preventDefault();
@ -96,20 +96,21 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuLeaveItem", ev);
};
leaveOption = <IconizedContextMenuOption
onClick={onLeaveRoomClick}
label={_t("Leave")}
className="mx_IconizedContextMenu_option_red"
iconClassName="mx_RoomTile_iconSignOut"
/>;
leaveOption = (
<IconizedContextMenuOption
onClick={onLeaveRoomClick}
label={_t("Leave")}
className="mx_IconizedContextMenu_option_red"
iconClassName="mx_RoomTile_iconSignOut"
/>
);
}
const isDm = DMRoomMap.shared().getUserIdForRoomId(room.roomId);
const videoRoomsEnabled = useFeatureEnabled("feature_video_rooms");
const elementCallVideoRoomsEnabled = useFeatureEnabled("feature_element_call_video_rooms");
const isVideoRoom = videoRoomsEnabled && (
room.isElementVideoRoom() || (elementCallVideoRoomsEnabled && room.isCallRoom())
);
const isVideoRoom =
videoRoomsEnabled && (room.isElementVideoRoom() || (elementCallVideoRoomsEnabled && room.isCallRoom()));
let inviteOption: JSX.Element;
if (room.canInvite(cli.getUserId()!) && !isDm) {
@ -126,11 +127,13 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuInviteItem", ev);
};
inviteOption = <IconizedContextMenuOption
onClick={onInviteClick}
label={_t("Invite")}
iconClassName="mx_RoomTile_iconInvite"
/>;
inviteOption = (
<IconizedContextMenuOption
onClick={onInviteClick}
label={_t("Invite")}
iconClassName="mx_RoomTile_iconInvite"
/>
);
}
let favouriteOption: JSX.Element;
@ -138,23 +141,27 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
let notificationOption: JSX.Element;
if (room.getMyMembership() === "join") {
const isFavorite = roomTags.includes(DefaultTagID.Favourite);
favouriteOption = <IconizedContextMenuCheckbox
onClick={(e) => {
onTagRoom(e, DefaultTagID.Favourite);
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuFavouriteToggle", e);
}}
active={isFavorite}
label={isFavorite ? _t("Favourited") : _t("Favourite")}
iconClassName="mx_RoomTile_iconStar"
/>;
favouriteOption = (
<IconizedContextMenuCheckbox
onClick={(e) => {
onTagRoom(e, DefaultTagID.Favourite);
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuFavouriteToggle", e);
}}
active={isFavorite}
label={isFavorite ? _t("Favourited") : _t("Favourite")}
iconClassName="mx_RoomTile_iconStar"
/>
);
const isLowPriority = roomTags.includes(DefaultTagID.LowPriority);
lowPriorityOption = <IconizedContextMenuCheckbox
onClick={(e) => onTagRoom(e, DefaultTagID.LowPriority)}
active={isLowPriority}
label={_t("Low priority")}
iconClassName="mx_RoomTile_iconArrowDown"
/>;
lowPriorityOption = (
<IconizedContextMenuCheckbox
onClick={(e) => onTagRoom(e, DefaultTagID.LowPriority)}
active={isLowPriority}
label={_t("Low priority")}
iconClassName="mx_RoomTile_iconArrowDown"
/>
);
const echoChamber = EchoChamber.forRoom(room);
let notificationLabel: string;
@ -178,80 +185,84 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
break;
}
notificationOption = <IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
notificationOption = (
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
dis.dispatch({
action: "open_room_settings",
room_id: room.roomId,
initial_tab_id: ROOM_NOTIFICATIONS_TAB,
});
onFinished();
dis.dispatch({
action: "open_room_settings",
room_id: room.roomId,
initial_tab_id: ROOM_NOTIFICATIONS_TAB,
});
onFinished();
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuNotificationsItem", ev);
}}
label={_t("Notifications")}
iconClassName={iconClassName}
>
<span className="mx_IconizedContextMenu_sublabel">
{ notificationLabel }
</span>
</IconizedContextMenuOption>;
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuNotificationsItem", ev);
}}
label={_t("Notifications")}
iconClassName={iconClassName}
>
<span className="mx_IconizedContextMenu_sublabel">{notificationLabel}</span>
</IconizedContextMenuOption>
);
}
let peopleOption: JSX.Element;
let copyLinkOption: JSX.Element;
if (!isDm) {
peopleOption = <IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
peopleOption = (
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
ensureViewingRoom(ev);
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.RoomMemberList }, false);
onFinished();
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuPeopleItem", ev);
}}
label={_t("People")}
iconClassName="mx_RoomTile_iconPeople"
>
<span className="mx_IconizedContextMenu_sublabel">
{ room.getJoinedMemberCount() }
</span>
</IconizedContextMenuOption>;
ensureViewingRoom(ev);
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.RoomMemberList }, false);
onFinished();
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuPeopleItem", ev);
}}
label={_t("People")}
iconClassName="mx_RoomTile_iconPeople"
>
<span className="mx_IconizedContextMenu_sublabel">{room.getJoinedMemberCount()}</span>
</IconizedContextMenuOption>
);
copyLinkOption = <IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
copyLinkOption = (
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
dis.dispatch({
action: "copy_room",
room_id: room.roomId,
});
onFinished();
}}
label={_t("Copy room link")}
iconClassName="mx_RoomTile_iconCopyLink"
/>;
dis.dispatch({
action: "copy_room",
room_id: room.roomId,
});
onFinished();
}}
label={_t("Copy room link")}
iconClassName="mx_RoomTile_iconCopyLink"
/>
);
}
let filesOption: JSX.Element;
if (!isVideoRoom) {
filesOption = <IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
filesOption = (
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
ensureViewingRoom(ev);
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.FilePanel }, false);
onFinished();
}}
label={_t("Files")}
iconClassName="mx_RoomTile_iconFiles"
/>;
ensureViewingRoom(ev);
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.FilePanel }, false);
onFinished();
}}
label={_t("Files")}
iconClassName="mx_RoomTile_iconFiles"
/>
);
}
const pinningEnabled = useFeatureEnabled("feature_pinning");
@ -259,53 +270,57 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
let pinsOption: JSX.Element;
if (pinningEnabled && !isVideoRoom) {
pinsOption = <IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
pinsOption = (
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
ensureViewingRoom(ev);
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.PinnedMessages }, false);
onFinished();
}}
label={_t("Pinned")}
iconClassName="mx_RoomTile_iconPins"
>
{ pinCount > 0 && <span className="mx_IconizedContextMenu_sublabel">
{ pinCount }
</span> }
</IconizedContextMenuOption>;
ensureViewingRoom(ev);
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.PinnedMessages }, false);
onFinished();
}}
label={_t("Pinned")}
iconClassName="mx_RoomTile_iconPins"
>
{pinCount > 0 && <span className="mx_IconizedContextMenu_sublabel">{pinCount}</span>}
</IconizedContextMenuOption>
);
}
let widgetsOption: JSX.Element;
if (!isVideoRoom) {
widgetsOption = <IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
widgetsOption = (
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
ensureViewingRoom(ev);
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomSummary }, false);
onFinished();
}}
label={_t("Widgets")}
iconClassName="mx_RoomTile_iconWidgets"
/>;
ensureViewingRoom(ev);
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomSummary }, false);
onFinished();
}}
label={_t("Widgets")}
iconClassName="mx_RoomTile_iconWidgets"
/>
);
}
let exportChatOption: JSX.Element;
if (!isVideoRoom) {
exportChatOption = <IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
exportChatOption = (
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
Modal.createDialog(ExportDialog, { room });
onFinished();
}}
label={_t("Export chat")}
iconClassName="mx_RoomTile_iconExport"
/>;
Modal.createDialog(ExportDialog, { room });
onFinished();
}}
label={_t("Export chat")}
iconClassName="mx_RoomTile_iconExport"
/>
);
}
const onTagRoom = (ev: ButtonEvent, tagId: TagID) => {
@ -333,62 +348,72 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
const ensureViewingRoom = (ev: ButtonEvent) => {
if (SdkContextClass.instance.roomViewStore.getRoomId() === room.roomId) return;
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: room.roomId,
metricsTrigger: "RoomList",
metricsViaKeyboard: ev.type !== "click",
}, true);
dis.dispatch<ViewRoomPayload>(
{
action: Action.ViewRoom,
room_id: room.roomId,
metricsTrigger: "RoomList",
metricsViaKeyboard: ev.type !== "click",
},
true,
);
};
return <IconizedContextMenu {...props} onFinished={onFinished} className="mx_RoomTile_contextMenu" compact>
<IconizedContextMenuOptionList>
{ inviteOption }
{ notificationOption }
{ favouriteOption }
{ peopleOption }
{ filesOption }
{ pinsOption }
{ widgetsOption }
{ lowPriorityOption }
{ copyLinkOption }
return (
<IconizedContextMenu {...props} onFinished={onFinished} className="mx_RoomTile_contextMenu" compact>
<IconizedContextMenuOptionList>
{inviteOption}
{notificationOption}
{favouriteOption}
{peopleOption}
{filesOption}
{pinsOption}
{widgetsOption}
{lowPriorityOption}
{copyLinkOption}
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
dis.dispatch({
action: "open_room_settings",
room_id: room.roomId,
});
onFinished();
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuSettingsItem", ev);
}}
label={_t("Settings")}
iconClassName="mx_RoomTile_iconSettings"
/>
dis.dispatch({
action: "open_room_settings",
room_id: room.roomId,
});
onFinished();
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuSettingsItem", ev);
}}
label={_t("Settings")}
iconClassName="mx_RoomTile_iconSettings"
/>
{ exportChatOption }
{exportChatOption}
{ SettingsStore.getValue("developerMode") && <IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
{SettingsStore.getValue("developerMode") && (
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
Modal.createDialog(DevtoolsDialog, {
roomId: SdkContextClass.instance.roomViewStore.getRoomId(),
}, "mx_DevtoolsDialog_wrapper");
onFinished();
}}
label={_t("Developer tools")}
iconClassName="mx_RoomTile_iconDeveloperTools"
/> }
Modal.createDialog(
DevtoolsDialog,
{
roomId: SdkContextClass.instance.roomViewStore.getRoomId(),
},
"mx_DevtoolsDialog_wrapper",
);
onFinished();
}}
label={_t("Developer tools")}
iconClassName="mx_RoomTile_iconDeveloperTools"
/>
)}
{ leaveOption }
</IconizedContextMenuOptionList>
</IconizedContextMenu>;
{leaveOption}
</IconizedContextMenuOptionList>
</IconizedContextMenu>
);
};
export default RoomContextMenu;

View file

@ -48,22 +48,27 @@ interface IProps extends IContextMenuProps {
}
export const RoomGeneralContextMenu = ({
room, onFinished,
onPostFavoriteClick, onPostLowPriorityClick, onPostInviteClick, onPostCopyLinkClick, onPostSettingsClick,
onPostLeaveClick, onPostForgetClick, ...props
room,
onFinished,
onPostFavoriteClick,
onPostLowPriorityClick,
onPostInviteClick,
onPostCopyLinkClick,
onPostSettingsClick,
onPostLeaveClick,
onPostForgetClick,
...props
}: IProps) => {
const cli = useContext(MatrixClientContext);
const roomTags = useEventEmitterState(
RoomListStore.instance,
LISTS_UPDATE_EVENT,
() => RoomListStore.instance.getTagsForRoom(room),
const roomTags = useEventEmitterState(RoomListStore.instance, LISTS_UPDATE_EVENT, () =>
RoomListStore.instance.getTagsForRoom(room),
);
const isDm = DMRoomMap.shared().getUserIdForRoomId(room.roomId);
const wrapHandler = (
handler: (ev: ButtonEvent) => void,
postHandler?: (ev: ButtonEvent) => void,
persistent = false,
): (ev: ButtonEvent) => void => {
): ((ev: ButtonEvent) => void) => {
return (ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
@ -91,96 +96,123 @@ export const RoomGeneralContextMenu = ({
};
const isFavorite = roomTags.includes(DefaultTagID.Favourite);
const favoriteOption: JSX.Element = <IconizedContextMenuCheckbox
onClick={wrapHandler((ev) =>
onTagRoom(ev, DefaultTagID.Favourite), onPostFavoriteClick, true)}
active={isFavorite}
label={isFavorite ? _t("Favourited") : _t("Favourite")}
iconClassName="mx_RoomGeneralContextMenu_iconStar"
/>;
const favoriteOption: JSX.Element = (
<IconizedContextMenuCheckbox
onClick={wrapHandler((ev) => onTagRoom(ev, DefaultTagID.Favourite), onPostFavoriteClick, true)}
active={isFavorite}
label={isFavorite ? _t("Favourited") : _t("Favourite")}
iconClassName="mx_RoomGeneralContextMenu_iconStar"
/>
);
const isLowPriority = roomTags.includes(DefaultTagID.LowPriority);
const lowPriorityOption: JSX.Element = <IconizedContextMenuCheckbox
onClick={wrapHandler((ev) =>
onTagRoom(ev, DefaultTagID.LowPriority), onPostLowPriorityClick, true)}
active={isLowPriority}
label={_t("Low Priority")}
iconClassName="mx_RoomGeneralContextMenu_iconArrowDown"
/>;
const lowPriorityOption: JSX.Element = (
<IconizedContextMenuCheckbox
onClick={wrapHandler((ev) => onTagRoom(ev, DefaultTagID.LowPriority), onPostLowPriorityClick, true)}
active={isLowPriority}
label={_t("Low Priority")}
iconClassName="mx_RoomGeneralContextMenu_iconArrowDown"
/>
);
let inviteOption: JSX.Element;
if (room.canInvite(cli.getUserId()) && !isDm) {
inviteOption = <IconizedContextMenuOption
onClick={wrapHandler(() => dis.dispatch({
action: "view_invite",
roomId: room.roomId,
}), onPostInviteClick)}
label={_t("Invite")}
iconClassName="mx_RoomGeneralContextMenu_iconInvite"
/>;
inviteOption = (
<IconizedContextMenuOption
onClick={wrapHandler(
() =>
dis.dispatch({
action: "view_invite",
roomId: room.roomId,
}),
onPostInviteClick,
)}
label={_t("Invite")}
iconClassName="mx_RoomGeneralContextMenu_iconInvite"
/>
);
}
let copyLinkOption: JSX.Element;
if (!isDm) {
copyLinkOption = <IconizedContextMenuOption
onClick={wrapHandler(() => dis.dispatch({
action: "copy_room",
room_id: room.roomId,
}), onPostCopyLinkClick)}
label={_t("Copy room link")}
iconClassName="mx_RoomGeneralContextMenu_iconCopyLink"
/>;
copyLinkOption = (
<IconizedContextMenuOption
onClick={wrapHandler(
() =>
dis.dispatch({
action: "copy_room",
room_id: room.roomId,
}),
onPostCopyLinkClick,
)}
label={_t("Copy room link")}
iconClassName="mx_RoomGeneralContextMenu_iconCopyLink"
/>
);
}
const settingsOption: JSX.Element = <IconizedContextMenuOption
onClick={wrapHandler(() => dis.dispatch({
action: "open_room_settings",
room_id: room.roomId,
}), onPostSettingsClick)}
label={_t("Settings")}
iconClassName="mx_RoomGeneralContextMenu_iconSettings"
/>;
const settingsOption: JSX.Element = (
<IconizedContextMenuOption
onClick={wrapHandler(
() =>
dis.dispatch({
action: "open_room_settings",
room_id: room.roomId,
}),
onPostSettingsClick,
)}
label={_t("Settings")}
iconClassName="mx_RoomGeneralContextMenu_iconSettings"
/>
);
let leaveOption: JSX.Element;
if (roomTags.includes(DefaultTagID.Archived)) {
leaveOption = <IconizedContextMenuOption
iconClassName="mx_RoomGeneralContextMenu_iconSignOut"
label={_t("Forget Room")}
className="mx_IconizedContextMenu_option_red"
onClick={wrapHandler(() => dis.dispatch({
action: "forget_room",
room_id: room.roomId,
}), onPostForgetClick)}
/>;
leaveOption = (
<IconizedContextMenuOption
iconClassName="mx_RoomGeneralContextMenu_iconSignOut"
label={_t("Forget Room")}
className="mx_IconizedContextMenu_option_red"
onClick={wrapHandler(
() =>
dis.dispatch({
action: "forget_room",
room_id: room.roomId,
}),
onPostForgetClick,
)}
/>
);
} else {
leaveOption = <IconizedContextMenuOption
onClick={wrapHandler(() => dis.dispatch({
action: "leave_room",
room_id: room.roomId,
}), onPostLeaveClick)}
label={_t("Leave")}
className="mx_IconizedContextMenu_option_red"
iconClassName="mx_RoomGeneralContextMenu_iconSignOut"
/>;
leaveOption = (
<IconizedContextMenuOption
onClick={wrapHandler(
() =>
dis.dispatch({
action: "leave_room",
room_id: room.roomId,
}),
onPostLeaveClick,
)}
label={_t("Leave")}
className="mx_IconizedContextMenu_option_red"
iconClassName="mx_RoomGeneralContextMenu_iconSignOut"
/>
);
}
return <IconizedContextMenu
{...props}
onFinished={onFinished}
className="mx_RoomGeneralContextMenu"
compact
>
{ !roomTags.includes(DefaultTagID.Archived) && (
<IconizedContextMenuOptionList>
{ favoriteOption }
{ lowPriorityOption }
{ inviteOption }
{ copyLinkOption }
{ settingsOption }
</IconizedContextMenuOptionList>
) }
<IconizedContextMenuOptionList red>
{ leaveOption }
</IconizedContextMenuOptionList>
</IconizedContextMenu>;
return (
<IconizedContextMenu {...props} onFinished={onFinished} className="mx_RoomGeneralContextMenu" compact>
{!roomTags.includes(DefaultTagID.Archived) && (
<IconizedContextMenuOptionList>
{favoriteOption}
{lowPriorityOption}
{inviteOption}
{copyLinkOption}
{settingsOption}
</IconizedContextMenuOptionList>
)}
<IconizedContextMenuOptionList red>{leaveOption}</IconizedContextMenuOptionList>
</IconizedContextMenu>
);
};

View file

@ -36,10 +36,7 @@ interface IProps extends IContextMenuProps {
export const RoomNotificationContextMenu = ({ room, onFinished, ...props }: IProps) => {
const [notificationState, setNotificationState] = useNotificationState(room);
const wrapHandler = (
handler: (ev: ButtonEvent) => void,
persistent = false,
): (ev: ButtonEvent) => void => {
const wrapHandler = (handler: (ev: ButtonEvent) => void, persistent = false): ((ev: ButtonEvent) => void) => {
return (ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
@ -53,45 +50,50 @@ export const RoomNotificationContextMenu = ({ room, onFinished, ...props }: IPro
};
};
const defaultOption: JSX.Element = <IconizedContextMenuRadio
label={_t("Use default")}
active={notificationState === RoomNotifState.AllMessages}
iconClassName="mx_RoomNotificationContextMenu_iconBell"
onClick={wrapHandler(() => setNotificationState(RoomNotifState.AllMessages))}
/>;
const defaultOption: JSX.Element = (
<IconizedContextMenuRadio
label={_t("Use default")}
active={notificationState === RoomNotifState.AllMessages}
iconClassName="mx_RoomNotificationContextMenu_iconBell"
onClick={wrapHandler(() => setNotificationState(RoomNotifState.AllMessages))}
/>
);
const allMessagesOption: JSX.Element = <IconizedContextMenuRadio
label={_t("All messages")}
active={notificationState === RoomNotifState.AllMessagesLoud}
iconClassName="mx_RoomNotificationContextMenu_iconBellDot"
onClick={wrapHandler(() => setNotificationState(RoomNotifState.AllMessagesLoud))}
/>;
const allMessagesOption: JSX.Element = (
<IconizedContextMenuRadio
label={_t("All messages")}
active={notificationState === RoomNotifState.AllMessagesLoud}
iconClassName="mx_RoomNotificationContextMenu_iconBellDot"
onClick={wrapHandler(() => setNotificationState(RoomNotifState.AllMessagesLoud))}
/>
);
const mentionsOption: JSX.Element = <IconizedContextMenuRadio
label={_t("Mentions & Keywords")}
active={notificationState === RoomNotifState.MentionsOnly}
iconClassName="mx_RoomNotificationContextMenu_iconBellMentions"
onClick={wrapHandler(() => setNotificationState(RoomNotifState.MentionsOnly))}
/>;
const mentionsOption: JSX.Element = (
<IconizedContextMenuRadio
label={_t("Mentions & Keywords")}
active={notificationState === RoomNotifState.MentionsOnly}
iconClassName="mx_RoomNotificationContextMenu_iconBellMentions"
onClick={wrapHandler(() => setNotificationState(RoomNotifState.MentionsOnly))}
/>
);
const muteOption: JSX.Element = <IconizedContextMenuRadio
label={_t("Off")}
active={notificationState === RoomNotifState.Mute}
iconClassName="mx_RoomNotificationContextMenu_iconBellCrossed"
onClick={wrapHandler(() => setNotificationState(RoomNotifState.Mute))}
/>;
const muteOption: JSX.Element = (
<IconizedContextMenuRadio
label={_t("Off")}
active={notificationState === RoomNotifState.Mute}
iconClassName="mx_RoomNotificationContextMenu_iconBellCrossed"
onClick={wrapHandler(() => setNotificationState(RoomNotifState.Mute))}
/>
);
return <IconizedContextMenu
{...props}
onFinished={onFinished}
className="mx_RoomNotificationContextMenu"
compact
>
<IconizedContextMenuOptionList first>
{ defaultOption }
{ allMessagesOption }
{ mentionsOption }
{ muteOption }
</IconizedContextMenuOptionList>
</IconizedContextMenu>;
return (
<IconizedContextMenu {...props} onFinished={onFinished} className="mx_RoomNotificationContextMenu" compact>
<IconizedContextMenuOptionList first>
{defaultOption}
{allMessagesOption}
{mentionsOption}
{muteOption}
</IconizedContextMenuOptionList>
</IconizedContextMenu>
);
};

View file

@ -63,7 +63,7 @@ const SpaceContextMenu = ({ space, hideHeader, onFinished, ...props }: IProps) =
inviteOption = (
<IconizedContextMenuOption
data-test-id='invite-option'
data-test-id="invite-option"
className="mx_SpacePanel_contextMenu_inviteButton"
iconClassName="mx_SpacePanel_iconInvite"
label={_t("Invite")}
@ -85,7 +85,7 @@ const SpaceContextMenu = ({ space, hideHeader, onFinished, ...props }: IProps) =
settingsOption = (
<IconizedContextMenuOption
data-test-id='settings-option'
data-test-id="settings-option"
iconClassName="mx_SpacePanel_iconSettings"
label={_t("Settings")}
onClick={onSettingsClick}
@ -102,7 +102,7 @@ const SpaceContextMenu = ({ space, hideHeader, onFinished, ...props }: IProps) =
leaveOption = (
<IconizedContextMenuOption
data-test-id='leave-option'
data-test-id="leave-option"
iconClassName="mx_SpacePanel_iconLeave"
className="mx_IconizedContextMenu_option_red"
label={_t("Leave space")}
@ -170,39 +170,41 @@ const SpaceContextMenu = ({ space, hideHeader, onFinished, ...props }: IProps) =
onFinished();
};
newRoomSection = <>
<div data-test-id='add-to-space-header' className="mx_SpacePanel_contextMenu_separatorLabel">
{ _t("Add") }
</div>
{ canAddRooms &&
<IconizedContextMenuOption
data-test-id='new-room-option'
iconClassName="mx_SpacePanel_iconPlus"
label={_t("Room")}
onClick={onNewRoomClick}
/>
}
{ canAddVideoRooms &&
<IconizedContextMenuOption
data-test-id='new-video-room-option'
iconClassName="mx_SpacePanel_iconPlus"
label={_t("Video room")}
onClick={onNewVideoRoomClick}
>
<BetaPill />
</IconizedContextMenuOption>
}
{ canAddSubSpaces &&
<IconizedContextMenuOption
data-test-id='new-subspace-option'
iconClassName="mx_SpacePanel_iconPlus"
label={_t("Space")}
onClick={onNewSubspaceClick}
>
<BetaPill />
</IconizedContextMenuOption>
}
</>;
newRoomSection = (
<>
<div data-test-id="add-to-space-header" className="mx_SpacePanel_contextMenu_separatorLabel">
{_t("Add")}
</div>
{canAddRooms && (
<IconizedContextMenuOption
data-test-id="new-room-option"
iconClassName="mx_SpacePanel_iconPlus"
label={_t("Room")}
onClick={onNewRoomClick}
/>
)}
{canAddVideoRooms && (
<IconizedContextMenuOption
data-test-id="new-video-room-option"
iconClassName="mx_SpacePanel_iconPlus"
label={_t("Video room")}
onClick={onNewVideoRoomClick}
>
<BetaPill />
</IconizedContextMenuOption>
)}
{canAddSubSpaces && (
<IconizedContextMenuOption
data-test-id="new-subspace-option"
iconClassName="mx_SpacePanel_iconPlus"
label={_t("Space")}
onClick={onNewSubspaceClick}
>
<BetaPill />
</IconizedContextMenuOption>
)}
</>
);
}
const onPreferencesClick = (ev: ButtonEvent) => {
@ -235,38 +237,33 @@ const SpaceContextMenu = ({ space, hideHeader, onFinished, ...props }: IProps) =
openSpace(ev);
};
return <IconizedContextMenu
{...props}
onFinished={onFinished}
className="mx_SpacePanel_contextMenu"
compact
>
{ !hideHeader && <div className="mx_SpacePanel_contextMenu_header">
{ space.name }
</div> }
<IconizedContextMenuOptionList first>
<IconizedContextMenuOption
iconClassName="mx_SpacePanel_iconHome"
label={_t("Space home")}
onClick={onHomeClick}
/>
{ inviteOption }
<IconizedContextMenuOption
iconClassName="mx_SpacePanel_iconExplore"
label={canAddRooms ? _t("Manage & explore rooms") : _t("Explore rooms")}
onClick={onExploreRoomsClick}
/>
<IconizedContextMenuOption
iconClassName="mx_SpacePanel_iconPreferences"
label={_t("Preferences")}
onClick={onPreferencesClick}
/>
{ devtoolsOption }
{ settingsOption }
{ leaveOption }
{ newRoomSection }
</IconizedContextMenuOptionList>
</IconizedContextMenu>;
return (
<IconizedContextMenu {...props} onFinished={onFinished} className="mx_SpacePanel_contextMenu" compact>
{!hideHeader && <div className="mx_SpacePanel_contextMenu_header">{space.name}</div>}
<IconizedContextMenuOptionList first>
<IconizedContextMenuOption
iconClassName="mx_SpacePanel_iconHome"
label={_t("Space home")}
onClick={onHomeClick}
/>
{inviteOption}
<IconizedContextMenuOption
iconClassName="mx_SpacePanel_iconExplore"
label={canAddRooms ? _t("Manage & explore rooms") : _t("Explore rooms")}
onClick={onExploreRoomsClick}
/>
<IconizedContextMenuOption
iconClassName="mx_SpacePanel_iconPreferences"
label={_t("Preferences")}
onClick={onPreferencesClick}
/>
{devtoolsOption}
{settingsOption}
{leaveOption}
{newRoomSection}
</IconizedContextMenuOptionList>
</IconizedContextMenu>
);
};
export default SpaceContextMenu;

View file

@ -18,7 +18,7 @@ import React, { useCallback, useEffect } from "react";
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
import { ButtonEvent } from "../elements/AccessibleButton";
import dis from '../../../dispatcher/dispatcher';
import dis from "../../../dispatcher/dispatcher";
import { Action } from "../../../dispatcher/actions";
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
import { copyPlaintext } from "../../../utils/strings";
@ -51,28 +51,34 @@ const ThreadListContextMenu: React.FC<ThreadListContextMenuProps> = ({
}) => {
const [menuDisplayed, button, openMenu, closeThreadOptions] = useContextMenu();
const viewInRoom = useCallback((evt: ButtonEvent): void => {
evt.preventDefault();
evt.stopPropagation();
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
event_id: mxEvent.getId(),
highlighted: true,
room_id: mxEvent.getRoomId(),
metricsTrigger: undefined, // room doesn't change
});
closeThreadOptions();
}, [mxEvent, closeThreadOptions]);
const copyLinkToThread = useCallback(async (evt: ButtonEvent | undefined) => {
if (permalinkCreator) {
evt?.preventDefault();
evt?.stopPropagation();
const matrixToUrl = permalinkCreator.forEvent(mxEvent.getId());
await copyPlaintext(matrixToUrl);
const viewInRoom = useCallback(
(evt: ButtonEvent): void => {
evt.preventDefault();
evt.stopPropagation();
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
event_id: mxEvent.getId(),
highlighted: true,
room_id: mxEvent.getRoomId(),
metricsTrigger: undefined, // room doesn't change
});
closeThreadOptions();
}
}, [mxEvent, closeThreadOptions, permalinkCreator]);
},
[mxEvent, closeThreadOptions],
);
const copyLinkToThread = useCallback(
async (evt: ButtonEvent | undefined) => {
if (permalinkCreator) {
evt?.preventDefault();
evt?.stopPropagation();
const matrixToUrl = permalinkCreator.forEvent(mxEvent.getId());
await copyPlaintext(matrixToUrl);
closeThreadOptions();
}
},
[mxEvent, closeThreadOptions, permalinkCreator],
);
useEffect(() => {
onMenuToggle?.(menuDisplayed);
@ -81,41 +87,46 @@ const ThreadListContextMenu: React.FC<ThreadListContextMenuProps> = ({
const isMainSplitTimelineShown = !WidgetLayoutStore.instance.hasMaximisedWidget(
MatrixClientPeg.get().getRoom(mxEvent.getRoomId()),
);
return <React.Fragment>
<ContextMenuTooltipButton
{...props}
className="mx_BaseCard_header_title_button--option"
onClick={openMenu}
title={_t("Thread options")}
isExpanded={menuDisplayed}
inputRef={button}
data-testid="threadlist-dropdown-button"
/>
{ menuDisplayed && (<IconizedContextMenu
onFinished={closeThreadOptions}
className="mx_RoomTile_contextMenu"
compact
rightAligned
{...contextMenuBelow(button.current.getBoundingClientRect())}
>
<IconizedContextMenuOptionList>
{ isMainSplitTimelineShown &&
<IconizedContextMenuOption
onClick={(e) => viewInRoom(e)}
label={_t("View in room")}
iconClassName="mx_ThreadPanel_viewInRoom"
/> }
{ permalinkCreator &&
<IconizedContextMenuOption
data-testid="copy-thread-link"
onClick={(e) => copyLinkToThread(e)}
label={_t("Copy link to thread")}
iconClassName="mx_ThreadPanel_copyLinkToThread"
/>
}
</IconizedContextMenuOptionList>
</IconizedContextMenu>) }
</React.Fragment>;
return (
<React.Fragment>
<ContextMenuTooltipButton
{...props}
className="mx_BaseCard_header_title_button--option"
onClick={openMenu}
title={_t("Thread options")}
isExpanded={menuDisplayed}
inputRef={button}
data-testid="threadlist-dropdown-button"
/>
{menuDisplayed && (
<IconizedContextMenu
onFinished={closeThreadOptions}
className="mx_RoomTile_contextMenu"
compact
rightAligned
{...contextMenuBelow(button.current.getBoundingClientRect())}
>
<IconizedContextMenuOptionList>
{isMainSplitTimelineShown && (
<IconizedContextMenuOption
onClick={(e) => viewInRoom(e)}
label={_t("View in room")}
iconClassName="mx_ThreadPanel_viewInRoom"
/>
)}
{permalinkCreator && (
<IconizedContextMenuOption
data-testid="copy-thread-link"
onClick={(e) => copyLinkToThread(e)}
label={_t("Copy link to thread")}
iconClassName="mx_ThreadPanel_copyLinkToThread"
/>
)}
</IconizedContextMenuOptionList>
</IconizedContextMenu>
)}
</React.Fragment>
);
};
export default ThreadListContextMenu;

View file

@ -70,20 +70,19 @@ const WidgetContextMenu: React.FC<IProps> = ({
// XXX: won't i18n well, but looks like widget api only support 'message'?
const message = err.message || _t("Unable to start audio streaming.");
Modal.createDialog(ErrorDialog, {
title: _t('Failed to start livestream'),
title: _t("Failed to start livestream"),
description: message,
});
}
onFinished();
};
streamAudioStreamButton = <IconizedContextMenuOption
onClick={onStreamAudioClick}
label={_t("Start audio stream")}
/>;
streamAudioStreamButton = (
<IconizedContextMenuOption onClick={onStreamAudioClick} label={_t("Start audio stream")} />
);
}
const pinnedWidgets = WidgetLayoutStore.instance.getContainerWidgets(room, Container.Top);
const widgetIndex = pinnedWidgets.findIndex(widget => widget.id === app.id);
const widgetIndex = pinnedWidgets.findIndex((widget) => widget.id === app.id);
let editButton;
if (canModify && WidgetUtils.isManagedByManager(app)) {
@ -103,14 +102,17 @@ const WidgetContextMenu: React.FC<IProps> = ({
const screenshotsEnabled = SettingsStore.getValue("enableWidgetScreenshots");
if (screenshotsEnabled && widgetMessaging?.hasCapability(MatrixCapabilities.Screenshots)) {
const onSnapshotClick = () => {
widgetMessaging?.takeScreenshot().then(data => {
dis.dispatch({
action: 'picture_snapshot',
file: data.screenshot,
widgetMessaging
?.takeScreenshot()
.then((data) => {
dis.dispatch({
action: "picture_snapshot",
file: data.screenshot,
});
})
.catch((err) => {
logger.error("Failed to take screenshot: ", err);
});
}).catch(err => {
logger.error("Failed to take screenshot: ", err);
});
onFinished();
};
@ -128,7 +130,8 @@ const WidgetContextMenu: React.FC<IProps> = ({
title: _t("Delete Widget"),
description: _t(
"Deleting a widget removes it for all users in this room." +
" Are you sure you want to delete this widget?"),
" Are you sure you want to delete this widget?",
),
button: _t("Delete widget"),
onFinished: (confirmed) => {
if (!confirmed) return;
@ -140,15 +143,17 @@ const WidgetContextMenu: React.FC<IProps> = ({
onFinished();
};
deleteButton = <IconizedContextMenuOption
onClick={_onDeleteClick}
label={userWidget ? _t("Remove") : _t("Remove for everyone")}
/>;
deleteButton = (
<IconizedContextMenuOption
onClick={_onDeleteClick}
label={userWidget ? _t("Remove") : _t("Remove for everyone")}
/>
);
}
const isAllowedWidget =
(app.eventId !== undefined && (SettingsStore.getValue("allowedWidgets", roomId)[app.eventId] ?? false))
|| app.creatorUserId === cli.getUserId();
(app.eventId !== undefined && (SettingsStore.getValue("allowedWidgets", roomId)[app.eventId] ?? false)) ||
app.creatorUserId === cli.getUserId();
const isLocalWidget = WidgetType.JITSI.matches(app.type);
let revokeButton;
@ -158,7 +163,7 @@ const WidgetContextMenu: React.FC<IProps> = ({
const current = SettingsStore.getValue("allowedWidgets", roomId);
if (app.eventId !== undefined) current[app.eventId] = false;
const level = SettingsStore.firstSupportedLevel("allowedWidgets");
SettingsStore.setValue("allowedWidgets", roomId, level, current).catch(err => {
SettingsStore.setValue("allowedWidgets", roomId, level, current).catch((err) => {
logger.error(err);
// We don't really need to do anything about this - the user will just hit the button again.
});
@ -188,17 +193,19 @@ const WidgetContextMenu: React.FC<IProps> = ({
moveRightButton = <IconizedContextMenuOption onClick={onClick} label={_t("Move right")} />;
}
return <IconizedContextMenu {...props} chevronFace={ChevronFace.None} onFinished={onFinished}>
<IconizedContextMenuOptionList>
{ streamAudioStreamButton }
{ editButton }
{ revokeButton }
{ deleteButton }
{ snapshotButton }
{ moveLeftButton }
{ moveRightButton }
</IconizedContextMenuOptionList>
</IconizedContextMenu>;
return (
<IconizedContextMenu {...props} chevronFace={ChevronFace.None} onFinished={onFinished}>
<IconizedContextMenuOptionList>
{streamAudioStreamButton}
{editButton}
{revokeButton}
{deleteButton}
{snapshotButton}
{moveLeftButton}
{moveRightButton}
</IconizedContextMenuOptionList>
</IconizedContextMenu>
);
};
export default WidgetContextMenu;