Tidy up React JSX to make Sonar happier (#33946)

* Eradicate unused React props

* Fix unmatched defaultProps

* Remove spurious React fragments

* Remove unused JSX

* Remove unused React state field

* Remove unused React state field

* Update snapshots
This commit is contained in:
Michael Telatynski
2026-06-23 16:40:42 +00:00
committed by GitHub
parent d1dfd3a7ca
commit a26732b040
60 changed files with 242 additions and 418 deletions
@@ -35,14 +35,12 @@ import { shouldShowComponent } from "../../customisations/helpers/UIComponents";
import { UIComponent } from "../../settings/UIFeature"; import { UIComponent } from "../../settings/UIFeature";
import AccessibleButton, { type ButtonEvent } from "../views/elements/AccessibleButton"; import AccessibleButton, { type ButtonEvent } from "../views/elements/AccessibleButton";
import PosthogTrackers from "../../PosthogTrackers"; import PosthogTrackers from "../../PosthogTrackers";
import type PageType from "../../PageTypes";
import { Landmark, LandmarkNavigation } from "../../accessibility/LandmarkNavigation"; import { Landmark, LandmarkNavigation } from "../../accessibility/LandmarkNavigation";
import SettingsStore from "../../settings/SettingsStore"; import SettingsStore from "../../settings/SettingsStore";
import { RoomListPanel } from "../views/rooms/RoomListPanel"; import { RoomListPanel } from "../views/rooms/RoomListPanel";
interface IProps { interface IProps {
isMinimized: boolean; isMinimized: boolean;
pageType: PageType;
resizeNotifier: ResizeNotifier; resizeNotifier: ResizeNotifier;
} }
@@ -66,7 +66,6 @@ import LeftPanelLiveShareWarning from "../views/beacon/LeftPanelLiveShareWarning
import HomePage from "./HomePage"; import HomePage from "./HomePage";
import { PipContainer } from "./PipContainer"; import { PipContainer } from "./PipContainer";
import { monitorSyncedPushRules } from "../../utils/pushRules/monitorSyncedPushRules"; import { monitorSyncedPushRules } from "../../utils/pushRules/monitorSyncedPushRules";
import { type ConfigOptions } from "../../SdkConfig";
import { MatrixClientContextProvider } from "./MatrixClientContextProvider"; import { MatrixClientContextProvider } from "./MatrixClientContextProvider";
import { Landmark, LandmarkNavigation } from "../../accessibility/LandmarkNavigation"; import { Landmark, LandmarkNavigation } from "../../accessibility/LandmarkNavigation";
import { ModuleApi } from "../../modules/Api.ts"; import { ModuleApi } from "../../modules/Api.ts";
@@ -93,12 +92,10 @@ interface IProps {
hideToSRUsers: boolean; hideToSRUsers: boolean;
// eslint-disable-next-line camelcase // eslint-disable-next-line camelcase
page_type?: string; page_type?: string;
autoJoin?: boolean;
threepidInvite?: IThreepidInvite; threepidInvite?: IThreepidInvite;
roomOobData?: IOOBData; roomOobData?: IOOBData;
currentRoomId: string | null; currentRoomId: string | null;
collapseLhs: boolean; collapseLhs: boolean;
config: ConfigOptions;
currentUserId: string | null; currentUserId: string | null;
justRegistered?: boolean; justRegistered?: boolean;
roomJustCreatedOpts?: IOpts; roomJustCreatedOpts?: IOpts;
@@ -796,7 +793,6 @@ class LoggedInView extends React.Component<IProps, IState> {
data-collapsed={shouldUseMinimizedUI ? true : undefined} data-collapsed={shouldUseMinimizedUI ? true : undefined}
> >
<LeftPanel <LeftPanel
pageType={this.props.page_type as PageTypes}
isMinimized={shouldUseMinimizedUI || false} isMinimized={shouldUseMinimizedUI || false}
resizeNotifier={this.context.resizeNotifier} resizeNotifier={this.context.resizeNotifier}
/> />
@@ -220,10 +220,6 @@ interface IState {
export default class MatrixChat extends React.PureComponent<IProps, IState> { export default class MatrixChat extends React.PureComponent<IProps, IState> {
public static displayName = "MatrixChat"; public static displayName = "MatrixChat";
public static defaultProps: Partial<IProps> = {
config: {},
};
private firstSyncComplete = false; private firstSyncComplete = false;
private firstSyncPromise: PromiseWithResolvers<void>; private firstSyncPromise: PromiseWithResolvers<void>;
@@ -303,7 +303,6 @@ interface LocalRoomViewProps {
resizeNotifier: ResizeNotifier; resizeNotifier: ResizeNotifier;
permalinkCreator: RoomPermalinkCreator; permalinkCreator: RoomPermalinkCreator;
roomView: RefObject<HTMLElement | null>; roomView: RefObject<HTMLElement | null>;
mainSplitContentType: MainSplitContentType;
e2eStatus?: E2EStatus; e2eStatus?: E2EStatus;
} }
@@ -364,7 +363,6 @@ function LocalRoomView(props: LocalRoomViewProps): ReactElement {
interface ILocalRoomCreateLoaderProps { interface ILocalRoomCreateLoaderProps {
localRoom: LocalRoom; localRoom: LocalRoom;
names: string; names: string;
mainSplitContentType: MainSplitContentType;
} }
/** /**
@@ -2134,11 +2132,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
const names = this.state.room.getDefaultRoomName(this.context.client.getSafeUserId()); const names = this.state.room.getDefaultRoomName(this.context.client.getSafeUserId());
return ( return (
<ScopedRoomContextProvider {...this.state} roomViewStore={this.roomViewStore}> <ScopedRoomContextProvider {...this.state} roomViewStore={this.roomViewStore}>
<LocalRoomCreateLoader <LocalRoomCreateLoader localRoom={localRoom} names={names} />
localRoom={localRoom}
names={names}
mainSplitContentType={this.state.mainSplitContentType}
/>
</ScopedRoomContextProvider> </ScopedRoomContextProvider>
); );
} }
@@ -2152,7 +2146,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
resizeNotifier={this.context.resizeNotifier} resizeNotifier={this.context.resizeNotifier}
permalinkCreator={this.permalinkCreator} permalinkCreator={this.permalinkCreator}
roomView={this.roomView} roomView={this.roomView}
mainSplitContentType={this.state.mainSplitContentType}
/> />
</ScopedRoomContextProvider> </ScopedRoomContextProvider>
); );
@@ -2346,7 +2339,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
onForgetClick={this.onForgetClick} onForgetClick={this.onForgetClick}
onDeclineClick={this.onDeclineButtonClicked} onDeclineClick={this.onDeclineButtonClicked}
onDeclineAndBlockClick={this.onDeclineAndBlockButtonClicked} onDeclineAndBlockClick={this.onDeclineAndBlockButtonClicked}
promptRejectionOptions={true}
inviterName={inviterName} inviterName={inviterName}
canPreview={false} canPreview={false}
joining={this.state.joining} joining={this.state.joining}
@@ -2460,7 +2452,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
onJoinClick={this.onJoinButtonClicked} onJoinClick={this.onJoinButtonClicked}
onForgetClick={this.onForgetClick} onForgetClick={this.onForgetClick}
onDeclineClick={this.onRejectThreepidInviteButtonClicked} onDeclineClick={this.onRejectThreepidInviteButtonClicked}
promptRejectionOptions={true}
joining={this.state.joining} joining={this.state.joining}
inviterName={inviterName} inviterName={inviterName}
invitedEmail={invitedEmail} invitedEmail={invitedEmail}
@@ -863,25 +863,23 @@ const SpaceHierarchy: React.FC<IProps> = ({ space, initialText = "", showRoom, a
let results: JSX.Element | undefined; let results: JSX.Element | undefined;
if (filteredRoomSet.size && root) { if (filteredRoomSet.size && root) {
results = ( results = (
<> <HierarchyLevel
<HierarchyLevel root={root}
root={root} roomSet={filteredRoomSet}
roomSet={filteredRoomSet} hierarchy={hierarchy}
hierarchy={hierarchy} parents={new Set()}
parents={new Set()} selectedMap={selected}
selectedMap={selected} onToggleClick={hasPermissions ? onToggleClick : undefined}
onToggleClick={hasPermissions ? onToggleClick : undefined} onViewRoomClick={(roomId, roomType) => showRoom(cli, hierarchy, roomId, roomType)}
onViewRoomClick={(roomId, roomType) => showRoom(cli, hierarchy, roomId, roomType)} onJoinRoomClick={async (roomId, parents) => {
onJoinRoomClick={async (roomId, parents) => { for (const parent of parents) {
for (const parent of parents) { if (cli.getRoom(parent)?.getMyMembership() !== KnownMembership.Join) {
if (cli.getRoom(parent)?.getMyMembership() !== KnownMembership.Join) { await joinRoom(cli, roomContext.roomViewStore, hierarchy, parent);
await joinRoom(cli, roomContext.roomViewStore, hierarchy, parent);
}
} }
await joinRoom(cli, roomContext.roomViewStore, hierarchy, roomId); }
}} await joinRoom(cli, roomContext.roomViewStore, hierarchy, roomId);
/> }}
</> />
); );
} else if (!hierarchy.canLoadMore) { } else if (!hierarchy.canLoadMore) {
results = ( results = (
@@ -428,7 +428,6 @@ class LoginComponent extends React.PureComponent<IProps, IState> {
onPhoneNumberChanged={this.onPhoneNumberChanged} onPhoneNumberChanged={this.onPhoneNumberChanged}
onForgotPasswordClick={this.props.onForgotPasswordClick} onForgotPasswordClick={this.props.onForgotPasswordClick}
loginIncorrect={this.state.loginIncorrect} loginIncorrect={this.state.loginIncorrect}
serverConfig={this.props.serverConfig}
disableSubmit={this.isBusy()} disableSubmit={this.isBusy()}
busy={this.props.isSyncing || this.state.busyLoggingIn} busy={this.props.isSyncing || this.state.busyLoggingIn}
/> />
@@ -502,7 +501,7 @@ class LoginComponent extends React.PureComponent<IProps, IState> {
footer = ( footer = (
<div className="mx_AuthBody_paddedFooter"> <div className="mx_AuthBody_paddedFooter">
<div className="mx_AuthBody_paddedFooter_title"> <div className="mx_AuthBody_paddedFooter_title">
<InlineSpinner w={20} h={20} /> <InlineSpinner size={20} />
{this.props.isSyncing ? _t("auth|syncing") : _t("auth|signing_in")} {this.props.isSyncing ? _t("auth|syncing") : _t("auth|signing_in")}
</div> </div>
{this.props.isSyncing && ( {this.props.isSyncing && (
@@ -610,7 +610,6 @@ export default class Registration extends React.Component<IProps, IState> {
defaultPassword={this.state.formVals.password} defaultPassword={this.state.formVals.password}
onRegisterClick={this.onFormSubmit} onRegisterClick={this.onFormSubmit}
flows={this.state.flows} flows={this.state.flows}
serverConfig={this.props.serverConfig}
canSubmit={!this.state.serverErrorIsFatal} canSubmit={!this.state.serverErrorIsFatal}
matrixClient={this.state.matrixClient} matrixClient={this.state.matrixClient}
mobileRegister={this.props.mobileRegister} mobileRegister={this.props.mobileRegister}
@@ -26,10 +26,6 @@ interface IState {
* A waveform which shows the waveform of a live recording * A waveform which shows the waveform of a live recording
*/ */
export default class LiveRecordingWaveform extends React.PureComponent<IProps, IState> { export default class LiveRecordingWaveform extends React.PureComponent<IProps, IState> {
public static defaultProps = {
progress: 1,
};
private waveform: number[] = []; private waveform: number[] = [];
private scheduledUpdate: MarkedExecution = new MarkedExecution( private scheduledUpdate: MarkedExecution = new MarkedExecution(
() => this.updateWaveform(), () => this.updateWaveform(),
@@ -26,10 +26,6 @@ interface ICaptchaFormState {
* A pure UI component which displays a captcha form. * A pure UI component which displays a captcha form.
*/ */
export default class CaptchaForm extends React.Component<ICaptchaFormProps, ICaptchaFormState> { export default class CaptchaForm extends React.Component<ICaptchaFormProps, ICaptchaFormState> {
public static defaultProps = {
onCaptchaResponse: () => {},
};
private captchaWidgetId?: string; private captchaWidgetId?: string;
private recaptchaContainer = createRef<HTMLDivElement>(); private recaptchaContainer = createRef<HTMLDivElement>();
@@ -12,7 +12,6 @@ import { Button } from "@vector-im/compound-web";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import SdkConfig from "../../../SdkConfig"; import SdkConfig from "../../../SdkConfig";
import { type ValidatedServerConfig } from "../../../utils/ValidatedServerConfig";
import AccessibleButton, { type ButtonEvent } from "../elements/AccessibleButton"; import AccessibleButton, { type ButtonEvent } from "../elements/AccessibleButton";
import withValidation, { type IFieldState, type IValidationResult } from "../elements/Validation"; import withValidation, { type IFieldState, type IValidationResult } from "../elements/Validation";
import Field from "../elements/Field"; import Field from "../elements/Field";
@@ -28,7 +27,6 @@ interface IProps {
phoneCountry: string; phoneCountry: string;
phoneNumber: string; phoneNumber: string;
serverConfig: ValidatedServerConfig;
loginIncorrect: boolean; loginIncorrect: boolean;
disableSubmit?: boolean; disableSubmit?: boolean;
busy?: boolean; busy?: boolean;
@@ -9,7 +9,6 @@ Please see LICENSE files in the repository root for full details.
import React, { type JSX, type BaseSyntheticEvent, type ComponentProps, type ReactNode } from "react"; import React, { type JSX, type BaseSyntheticEvent, type ComponentProps, type ReactNode } from "react";
import { type MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix"; import { type MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { Button } from "@vector-im/compound-web"; import { Button } from "@vector-im/compound-web";
import * as Email from "../../../email"; import * as Email from "../../../email";
@@ -19,7 +18,6 @@ import { _t, _td } from "../../../languageHandler";
import SdkConfig from "../../../SdkConfig"; import SdkConfig from "../../../SdkConfig";
import { SAFE_LOCALPART_REGEX } from "../../../Registration"; import { SAFE_LOCALPART_REGEX } from "../../../Registration";
import withValidation, { type IFieldState, type IValidationResult } from "../elements/Validation"; import withValidation, { type IFieldState, type IValidationResult } from "../elements/Validation";
import { type ValidatedServerConfig } from "../../../utils/ValidatedServerConfig";
import EmailField from "./EmailField"; import EmailField from "./EmailField";
import PassphraseField from "./PassphraseField"; import PassphraseField from "./PassphraseField";
import Field from "../elements/Field"; import Field from "../elements/Field";
@@ -56,7 +54,6 @@ interface IProps {
flows: { flows: {
stages: string[]; stages: string[];
}[]; }[];
serverConfig: ValidatedServerConfig;
canSubmit?: boolean; canSubmit?: boolean;
matrixClient: MatrixClient; matrixClient: MatrixClient;
mobileRegister?: boolean; mobileRegister?: boolean;
@@ -68,7 +65,6 @@ interface IProps {
phoneCountry?: string; phoneCountry?: string;
phoneNumber?: string; phoneNumber?: string;
}): Promise<void>; }): Promise<void>;
onEditServerDetailsClick?(): void;
} }
interface IState { interface IState {
@@ -95,7 +91,6 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
private [RegistrationField.PhoneNumber]: Field | null = null; private [RegistrationField.PhoneNumber]: Field | null = null;
public static defaultProps = { public static defaultProps = {
onValidationChange: logger.error,
canSubmit: true, canSubmit: true,
}; };
@@ -69,14 +69,12 @@ const BeaconStatus: React.FC<Props & HTMLProps<HTMLDivElement>> = ({
)} )}
{displayStatus === BeaconDisplayStatus.Active && beacon && ( {displayStatus === BeaconDisplayStatus.Active && beacon && (
<> <>
<> <span className="mx_BeaconStatus_label">{label}</span>
<span className="mx_BeaconStatus_label">{label}</span> {displayLiveTimeRemaining ? (
{displayLiveTimeRemaining ? ( <LiveTimeRemaining beacon={beacon} />
<LiveTimeRemaining beacon={beacon} /> ) : (
) : ( <BeaconExpiryTime beacon={beacon} />
<BeaconExpiryTime beacon={beacon} /> )}
)}
</>
</> </>
)} )}
</div> </div>
@@ -372,7 +372,6 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
{ {
matrixClient, matrixClient,
event: this.props.mxEvent, event: this.props.mxEvent,
getRelationsForEvent: this.props.getRelationsForEvent,
}, },
"mx_Dialog_endPoll", "mx_Dialog_endPoll",
); );
@@ -15,13 +15,11 @@ import QuestionDialog from "./QuestionDialog";
import { findTopAnswer } from "../messages/MPollBody"; import { findTopAnswer } from "../messages/MPollBody";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import ErrorDialog from "./ErrorDialog"; import ErrorDialog from "./ErrorDialog";
import { type GetRelationsForEvent } from "../rooms/EventTile";
interface IProps { interface IProps {
matrixClient: MatrixClient; matrixClient: MatrixClient;
event: MatrixEvent; event: MatrixEvent;
onFinished: (success?: boolean) => void; onFinished: (success?: boolean) => void;
getRelationsForEvent?: GetRelationsForEvent;
} }
export default class EndPollDialog extends React.Component<IProps> { export default class EndPollDialog extends React.Component<IProps> {
@@ -377,16 +377,14 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
)} )}
{setAttachments && ( {setAttachments && (
<> <StyledCheckbox
<StyledCheckbox className="mx_ExportDialog_attachments-checkbox"
className="mx_ExportDialog_attachments-checkbox" id="include-attachments"
id="include-attachments" checked={includeAttachments}
checked={includeAttachments} onChange={(e) => setAttachments((e.target as HTMLInputElement).checked)}
onChange={(e) => setAttachments((e.target as HTMLInputElement).checked)} >
> {_t("export_chat|include_attachments")}
{_t("export_chat|include_attachments")} </StyledCheckbox>
</StyledCheckbox>
</>
)} )}
</div> </div>
{isExporting ? ( {isExporting ? (
@@ -207,7 +207,6 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
onCancel={this.onCancelClick} onCancel={this.onCancelClick}
onDone={this.onSasMatchesClick} onDone={this.onSasMatchesClick}
isSelf={this.props.verifier.userId === MatrixClientPeg.safeGet().getUserId()} isSelf={this.props.verifier.userId === MatrixClientPeg.safeGet().getUserId()}
inDialog={true}
/> />
); );
} }
@@ -14,7 +14,7 @@ import { _t } from "../../../languageHandler";
const InviteProgressBody: React.FC = () => { const InviteProgressBody: React.FC = () => {
return ( return (
<div className="mx_InviteProgressBody"> <div className="mx_InviteProgressBody">
<InlineSpinner w={32} h={32} /> <InlineSpinner size={32} />
<h1>{_t("invite|progress|preparing")}</h1> <h1>{_t("invite|progress|preparing")}</h1>
{_t("invite|progress|dont_close")} {_t("invite|progress|dont_close")}
</div> </div>
@@ -166,7 +166,7 @@ export default function UserSettingsDialog(props: IProps): JSX.Element {
UserTab.Preferences, UserTab.Preferences,
_td("common|preferences"), _td("common|preferences"),
<PreferencesIcon />, <PreferencesIcon />,
<PreferencesUserSettingsTab closeSettingsFn={props.onFinished} />, <PreferencesUserSettingsTab />,
"UserSettingsPreferences", "UserSettingsPreferences",
), ),
); );
@@ -206,7 +206,7 @@ export default function UserSettingsDialog(props: IProps): JSX.Element {
UserTab.Security, UserTab.Security,
_td("room_settings|security|title"), _td("room_settings|security|title"),
<LockIcon />, <LockIcon />,
<SecurityUserSettingsTab closeSettingsFn={props.onFinished} />, <SecurityUserSettingsTab />,
"UserSettingsSecurityPrivacy", "UserSettingsSecurityPrivacy",
), ),
); );
@@ -7,13 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/ */
import React, { type ChangeEventHandler } from "react"; import React, { type ChangeEventHandler } from "react";
import { import { type Capability, isTimelineCapability, WidgetEventCapability, type WidgetKind } from "matrix-widget-api";
type Capability,
isTimelineCapability,
type Widget,
WidgetEventCapability,
type WidgetKind,
} from "matrix-widget-api";
import { lexicographicCompare } from "matrix-js-sdk/src/utils"; import { lexicographicCompare } from "matrix-js-sdk/src/utils";
import { Form, SettingsToggleInput } from "@vector-im/compound-web"; import { Form, SettingsToggleInput } from "@vector-im/compound-web";
@@ -26,7 +20,6 @@ import { CapabilityText } from "../../../widgets/CapabilityText";
interface IProps { interface IProps {
requestedCapabilities: Set<Capability>; requestedCapabilities: Set<Capability>;
widget: Widget;
widgetKind: WidgetKind; // TODO: Refactor into the Widget class widgetKind: WidgetKind; // TODO: Refactor into the Widget class
onFinished(result?: { approved: Capability[]; remember: boolean }): void; onFinished(result?: { approved: Capability[]; remember: boolean }): void;
} }
@@ -848,55 +848,53 @@ export default class AppTile extends React.Component<IProps, IState> {
} }
return ( return (
<React.Fragment> <div className={appTileClasses} id={this.props.app.id}>
<div className={appTileClasses} id={this.props.app.id}> {this.props.showMenubar && (
{this.props.showMenubar && ( <div className="mx_AppTileMenuBar">
<div className="mx_AppTileMenuBar"> <span
<span className="mx_AppTileMenuBar_title"
className="mx_AppTileMenuBar_title" style={{ pointerEvents: this.props.handleMinimisePointerEvents ? "all" : "none" }}
style={{ pointerEvents: this.props.handleMinimisePointerEvents ? "all" : "none" }} >
> {this.props.showTitle && this.getTileTitle()}
{this.props.showTitle && this.getTileTitle()} </span>
</span> <span className="mx_AppTileMenuBar_widgets">
<span className="mx_AppTileMenuBar_widgets"> {layoutButtons}
{layoutButtons} {this.props.showPopout && !this.state.requiresClient && (
{this.props.showPopout && !this.state.requiresClient && ( <AccessibleButton
<AccessibleButton className="mx_AppTileMenuBar_widgets_button"
className="mx_AppTileMenuBar_widgets_button" title={_t("widget|popout")}
title={_t("widget|popout")} onClick={this.onPopoutWidgetClick}
onClick={this.onPopoutWidgetClick} >
> <PopOutIcon className="mx_Icon mx_Icon_12" />
<PopOutIcon className="mx_Icon mx_Icon_12" /> </AccessibleButton>
</AccessibleButton> )}
)} <I18nContext.Provider value={window.mxModuleApi.i18n}>
<I18nContext.Provider value={window.mxModuleApi.i18n}> <WidgetContextMenu
<WidgetContextMenu trigger={
trigger={ <ContextMenuButton
<ContextMenuButton className="mx_AppTileMenuBar_widgets_button"
className="mx_AppTileMenuBar_widgets_button" label={_t("common|options")}
label={_t("common|options")} isExpanded={this.state.menuDisplayed}
isExpanded={this.state.menuDisplayed} ref={this.contextMenuButton}
ref={this.contextMenuButton} onClick={this.onContextMenuClick}
onClick={this.onContextMenuClick} >
> <OverflowHorizontalIcon className="mx_Icon mx_Icon_12" />
<OverflowHorizontalIcon className="mx_Icon mx_Icon_12" /> </ContextMenuButton>
</ContextMenuButton> }
} app={this.props.app}
app={this.props.app} onFinished={this.closeContextMenu}
onFinished={this.closeContextMenu} showUnpin={!this.props.userWidget}
showUnpin={!this.props.userWidget} userWidget={this.props.userWidget}
userWidget={this.props.userWidget} onEditClick={this.props.onEditClick}
onEditClick={this.props.onEditClick} onDeleteClick={this.props.onDeleteClick}
onDeleteClick={this.props.onDeleteClick} menuDisplayed={this.state.menuDisplayed}
menuDisplayed={this.state.menuDisplayed} />
/> </I18nContext.Provider>
</I18nContext.Provider> </span>
</span> </div>
</div> )}
)} {appTileBody}
{appTileBody} </div>
</div>
</React.Fragment>
); );
} }
} }
@@ -37,10 +37,6 @@ interface IMenuOptionProps {
} }
class MenuOption extends React.Component<IMenuOptionProps> { class MenuOption extends React.Component<IMenuOptionProps> {
public static defaultProps = {
disabled: false,
};
private onMouseEnter = (): void => { private onMouseEnter = (): void => {
this.props.onMouseEnter(this.props.dropdownKey); this.props.onMouseEnter(this.props.dropdownKey);
}; };
@@ -16,8 +16,7 @@ interface IProps {
export default class InlineSpinner extends React.PureComponent<IProps> { export default class InlineSpinner extends React.PureComponent<IProps> {
public static defaultProps = { public static defaultProps = {
w: 16, size: 16,
h: 16,
}; };
public render(): React.ReactNode { public render(): React.ReactNode {
@@ -15,7 +15,6 @@ import { _t } from "../../../languageHandler";
import dis from "../../../dispatcher/dispatcher"; import dis from "../../../dispatcher/dispatcher";
import { makeUserPermalink, type RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; import { makeUserPermalink, type RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import { type Layout } from "../../../settings/enums/Layout";
import { getUserNameColorClass } from "../../../utils/FormattingUtils"; import { getUserNameColorClass } from "../../../utils/FormattingUtils";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import Spinner from "./Spinner"; import Spinner from "./Spinner";
@@ -37,8 +36,6 @@ interface IProps {
// the latest event in this chain of replies // the latest event in this chain of replies
parentEv: MatrixEvent; parentEv: MatrixEvent;
permalinkCreator?: RoomPermalinkCreator; permalinkCreator?: RoomPermalinkCreator;
// Specifies which layout to use.
layout?: Layout;
// Whether to always show a timestamp // Whether to always show a timestamp
alwaysShowTimestamps?: boolean; alwaysShowTimestamps?: boolean;
forExport?: boolean; forExport?: boolean;
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/ */
import React from "react"; import React from "react";
import { type MatrixEvent, type MatrixClient } from "matrix-js-sdk/src/matrix"; import { type MatrixEvent } from "matrix-js-sdk/src/matrix";
import BaseDialog from "../dialogs/BaseDialog"; import BaseDialog from "../dialogs/BaseDialog";
import { locationEventGeoUri, isSelfLocation } from "../../../utils/location"; import { locationEventGeoUri, isSelfLocation } from "../../../utils/location";
@@ -16,7 +16,6 @@ import SmartMarker from "./SmartMarker";
import ZoomButtons from "./ZoomButtons"; import ZoomButtons from "./ZoomButtons";
interface IProps { interface IProps {
matrixClient: MatrixClient;
mxEvent: MatrixEvent; mxEvent: MatrixEvent;
onFinished(): void; onFinished(): void;
} }
@@ -18,7 +18,7 @@ import type { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPaylo
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import AccessibleButton, { type AccessibleButtonKind, type ButtonEvent } from "../elements/AccessibleButton"; import AccessibleButton, { type AccessibleButtonKind, type ButtonEvent } from "../elements/AccessibleButton";
import MemberAvatar from "../avatars/MemberAvatar"; import MemberAvatar from "../avatars/MemberAvatar";
import { LiveContentSummary, LiveContentType } from "../rooms/LiveContentSummary"; import { LiveContentSummary } from "../rooms/LiveContentSummary";
import FacePile from "../elements/FacePile"; import FacePile from "../elements/FacePile";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { CallDuration, SessionDuration } from "../voip/CallDuration"; import { CallDuration, SessionDuration } from "../voip/CallDuration";
@@ -66,7 +66,6 @@ const ActiveCallEvent = ({
{_t("timeline|m.call|video_call_started_text", { name: senderName })} {_t("timeline|m.call|video_call_started_text", { name: senderName })}
</span> </span>
<LiveContentSummary <LiveContentSummary
type={LiveContentType.Video}
text={_t("voip|video_call")} text={_t("voip|video_call")}
active={false} active={false}
participantCount={participatingMembers.length} participantCount={participatingMembers.length}
@@ -53,7 +53,6 @@ export default class MLocationBody extends React.Component<IBodyProps, IState> {
Modal.createDialog( Modal.createDialog(
LocationViewDialog, LocationViewDialog,
{ {
matrixClient: this.context,
mxEvent: this.props.mxEvent, mxEvent: this.props.mxEvent,
}, },
"mx_LocationViewDialog_wrapper", "mx_LocationViewDialog_wrapper",
@@ -44,7 +44,7 @@ interface PollOptionProps extends PollOptionContentProps {
children?: ReactNode; children?: ReactNode;
} }
const ActivePollOption: React.FC<Omit<PollOptionProps, "totalVoteCount"> & { children: ReactNode }> = ({ const ActivePollOption: React.FC<Omit<PollOptionProps, "totalVoteCount">> = ({
pollId, pollId,
isChecked, isChecked,
isEnded, isEnded,
@@ -31,7 +31,6 @@ interface IProps {
onClose?(this: void, ev: MouseEvent<HTMLButtonElement>): void; onClose?(this: void, ev: MouseEvent<HTMLButtonElement>): void;
onBack?(this: void, ev: MouseEvent<HTMLButtonElement>): void; onBack?(this: void, ev: MouseEvent<HTMLButtonElement>): void;
onKeyDown?(this: void, ev: KeyboardEvent): void; onKeyDown?(this: void, ev: KeyboardEvent): void;
cardState?: any;
ref?: Ref<HTMLDivElement>; ref?: Ref<HTMLDivElement>;
// Ref for the 'close' button the card // Ref for the 'close' button the card
closeButtonRef?: Ref<HTMLButtonElement>; closeButtonRef?: Ref<HTMLButtonElement>;
@@ -167,7 +167,6 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
member={member} member={member}
request={request} request={request}
key={request.transactionId} key={request.transactionId}
inDialog={layout === "dialog"}
phase={phase} phase={phase}
/> />
); );
@@ -24,7 +24,6 @@ import { useIsEncrypted } from "../../../hooks/useIsEncrypted";
import BaseCard from "./BaseCard"; import BaseCard from "./BaseCard";
import QuestionDialog from "../dialogs/QuestionDialog"; import QuestionDialog from "../dialogs/QuestionDialog";
import RightPanelStore from "../../../stores/right-panel/RightPanelStore"; import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
import { type IRightPanelCardState } from "../../../stores/right-panel/RightPanelStoreIPanelState";
import PosthogTrackers from "../../../PosthogTrackers"; import PosthogTrackers from "../../../PosthogTrackers";
import { UserInfoHeaderView } from "./user_info/UserInfoHeaderView"; import { UserInfoHeaderView } from "./user_info/UserInfoHeaderView";
import { UserInfoBasicView } from "./user_info/UserInfoBasicView"; import { UserInfoBasicView } from "./user_info/UserInfoBasicView";
@@ -192,12 +191,6 @@ const UserInfo: React.FC<IProps> = ({ user, room, onClose, phase = RightPanelPha
const classes = ["mx_UserInfo"]; const classes = ["mx_UserInfo"];
let cardState: IRightPanelCardState = {};
// We have no previousPhase for when viewing a UserInfo without a Room at this time
if (room && phase === RightPanelPhases.EncryptionPanel) {
cardState = { member };
}
const onEncryptionPanelClose = (): void => { const onEncryptionPanelClose = (): void => {
RightPanelStore.instance.popCard(); RightPanelStore.instance.popCard();
}; };
@@ -229,14 +222,12 @@ const UserInfo: React.FC<IProps> = ({ user, room, onClose, phase = RightPanelPha
} }
const header = ( const header = (
<> <UserInfoHeaderView
<UserInfoHeaderView hideVerificationSection={phase === RightPanelPhases.EncryptionPanel}
hideVerificationSection={phase === RightPanelPhases.EncryptionPanel} member={member}
member={member} devices={devices}
devices={devices} roomId={room?.roomId}
roomId={room?.roomId} />
/>
</>
); );
return ( return (
@@ -245,7 +236,6 @@ const UserInfo: React.FC<IProps> = ({ user, room, onClose, phase = RightPanelPha
header={_t("common|profile")} header={_t("common|profile")}
onClose={onClose} onClose={onClose}
closeLabel={closeLabel} closeLabel={closeLabel}
cardState={cardState}
onBack={(ev: ButtonEvent) => { onBack={(ev: ButtonEvent) => {
if (RightPanelStore.instance.previousCard.phase === RightPanelPhases.MemberList) { if (RightPanelStore.instance.previousCard.phase === RightPanelPhases.MemberList) {
PosthogTrackers.trackInteraction("WebRightPanelRoomUserInfoBackButton", ev); PosthogTrackers.trackInteraction("WebRightPanelRoomUserInfoBackButton", ev);
@@ -37,7 +37,6 @@ interface IProps {
phase?: Phase; phase?: Phase;
onClose: () => void; onClose: () => void;
isRoomEncrypted: boolean; isRoomEncrypted: boolean;
inDialog: boolean;
} }
interface IState { interface IState {
@@ -327,7 +326,6 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
sas={this.state.sasEvent.sas} sas={this.state.sasEvent.sas}
onCancel={this.onSasMismatchesClick} onCancel={this.onSasMismatchesClick}
onDone={this.onSasMatchesClick} onDone={this.onSasMatchesClick}
inDialog={this.props.inDialog}
isSelf={request.isSelfVerification} isSelf={request.isSelfVerification}
/> />
) : ( ) : (
@@ -20,7 +20,6 @@ import { onSubmitPreventDefault } from "../../../utils/form.ts";
interface IProps { interface IProps {
roomId: string; roomId: string;
label?: string;
canSetCanonicalAlias?: boolean; canSetCanonicalAlias?: boolean;
} }
@@ -1080,7 +1080,6 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
ref={this.replyChain} ref={this.replyChain}
forExport={this.props.forExport} forExport={this.props.forExport}
permalinkCreator={this.props.permalinkCreator} permalinkCreator={this.props.permalinkCreator}
layout={this.props.layout}
alwaysShowTimestamps={eventTileSnapshot.replyChain.alwaysShowTimestamps} alwaysShowTimestamps={eventTileSnapshot.replyChain.alwaysShowTimestamps}
isQuoteExpanded={isQuoteExpanded} isQuoteExpanded={isQuoteExpanded}
setQuoteExpanded={this.setQuoteExpanded} setQuoteExpanded={this.setQuoteExpanded}
@@ -12,12 +12,7 @@ import { GroupIcon, VideoCallSolidIcon } from "@vector-im/compound-design-tokens
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
export enum LiveContentType {
Video,
}
interface Props { interface Props {
type: LiveContentType;
text: string; text: string;
active: boolean; active: boolean;
participantCount: number; participantCount: number;
@@ -123,7 +123,6 @@ export class MessageComposer extends React.Component<IProps, IState> {
public static defaultProps = { public static defaultProps = {
compact: false, compact: false,
isRichTextEnabled: true,
}; };
public constructor(props: IProps) { public constructor(props: IProps) {
@@ -64,41 +64,35 @@ export default class MessageComposerFormatBar extends React.PureComponent<IProps
onClick={() => this.props.onAction(Formatting.Bold)} onClick={() => this.props.onAction(Formatting.Bold)}
icon={<BoldIcon />} icon={<BoldIcon />}
shortcut={this.props.shortcuts.bold} shortcut={this.props.shortcuts.bold}
visible={this.state.visible}
/> />
<FormatButton <FormatButton
label={_t("composer|format_italics")} label={_t("composer|format_italics")}
onClick={() => this.props.onAction(Formatting.Italics)} onClick={() => this.props.onAction(Formatting.Italics)}
icon={<ItalicIcon />} icon={<ItalicIcon />}
shortcut={this.props.shortcuts.italics} shortcut={this.props.shortcuts.italics}
visible={this.state.visible}
/> />
<FormatButton <FormatButton
label={_t("composer|format_strikethrough")} label={_t("composer|format_strikethrough")}
onClick={() => this.props.onAction(Formatting.Strikethrough)} onClick={() => this.props.onAction(Formatting.Strikethrough)}
icon={<StrikethroughIcon />} icon={<StrikethroughIcon />}
visible={this.state.visible}
/> />
<FormatButton <FormatButton
label={_t("composer|format_code_block")} label={_t("composer|format_code_block")}
onClick={() => this.props.onAction(Formatting.Code)} onClick={() => this.props.onAction(Formatting.Code)}
icon={<InlineCodeIcon />} icon={<InlineCodeIcon />}
shortcut={this.props.shortcuts.code} shortcut={this.props.shortcuts.code}
visible={this.state.visible}
/> />
<FormatButton <FormatButton
label={_t("action|quote")} label={_t("action|quote")}
onClick={() => this.props.onAction(Formatting.Quote)} onClick={() => this.props.onAction(Formatting.Quote)}
icon={<QuoteIcon />} icon={<QuoteIcon />}
shortcut={this.props.shortcuts.quote} shortcut={this.props.shortcuts.quote}
visible={this.state.visible}
/> />
<FormatButton <FormatButton
label={_t("composer|format_insert_link")} label={_t("composer|format_insert_link")}
onClick={() => this.props.onAction(Formatting.InsertLink)} onClick={() => this.props.onAction(Formatting.InsertLink)}
icon={<LinkIcon />} icon={<LinkIcon />}
shortcut={this.props.shortcuts.insert_link} shortcut={this.props.shortcuts.insert_link}
visible={this.state.visible}
/> />
</Toolbar> </Toolbar>
); );
@@ -126,7 +120,6 @@ interface IFormatButtonProps {
label: string; label: string;
icon: JSX.Element; icon: JSX.Element;
shortcut?: string; shortcut?: string;
visible?: boolean;
onClick(): void; onClick(): void;
} }
@@ -124,8 +124,6 @@ export function ReadReceiptGroup({
readReceiptPosition={readReceiptPosition} readReceiptPosition={readReceiptPosition}
checkUnmounting={checkUnmounting} checkUnmounting={checkUnmounting}
suppressAnimation={suppressAnimation} suppressAnimation={suppressAnimation}
timestamp={receipt.ts}
showTwelveHour={isTwelveHour}
/> />
); );
}) })
@@ -46,12 +46,6 @@ interface IProps {
// unmounted, to avoid unnecessary work. Should return true if we // unmounted, to avoid unnecessary work. Should return true if we
// are being unmounted. // are being unmounted.
checkUnmounting?: () => boolean; checkUnmounting?: () => boolean;
// Timestamp when the receipt was read
timestamp?: number;
// True to show twelve hour format, false otherwise
showTwelveHour?: boolean;
} }
interface IState { interface IState {
@@ -459,93 +459,91 @@ export default function RoomHeader({
}; };
return ( return (
<> <CurrentRightPanelPhaseContextProvider roomId={room.roomId}>
<CurrentRightPanelPhaseContextProvider roomId={room.roomId}> <Flex as="header" align="center" gap="var(--cpd-space-3x)" className="mx_RoomHeader light-panel">
<Flex as="header" align="center" gap="var(--cpd-space-3x)" className="mx_RoomHeader light-panel"> <WithPresenceIndicator room={room}>
<WithPresenceIndicator room={room}> {/* We hide this from the tabIndex list as it is a pointer shortcut and superfluous for a11y */}
{/* We hide this from the tabIndex list as it is a pointer shortcut and superfluous for a11y */}
{/* Disable on-click actions until the room is created */}
<RoomAvatar
room={room}
size="40px"
oobData={oobData}
onClick={room instanceof LocalRoom ? undefined : onAvatarClick}
tabIndex={-1}
aria-label={_t("room|header_avatar_open_settings_label")}
/>
</WithPresenceIndicator>
{/* Disable on-click actions until the room is created */} {/* Disable on-click actions until the room is created */}
<button <RoomAvatar
aria-label={_t("right_panel|room_summary_card|title")} room={room}
tabIndex={0} size="40px"
onClick={ oobData={oobData}
room instanceof LocalRoom onClick={room instanceof LocalRoom ? undefined : onAvatarClick}
? undefined tabIndex={-1}
: () => RightPanelStore.instance.showOrHidePhase(RightPanelPhases.RoomSummary) aria-label={_t("room|header_avatar_open_settings_label")}
} />
className="mx_RoomHeader_infoWrapper" </WithPresenceIndicator>
> {/* Disable on-click actions until the room is created */}
<Box flex="1" className="mx_RoomHeader_info"> <button
<Text aria-label={_t("right_panel|room_summary_card|title")}
as="div" tabIndex={0}
size="lg" onClick={
weight="semibold" room instanceof LocalRoom
dir="auto" ? undefined
role="heading" : () => RightPanelStore.instance.showOrHidePhase(RightPanelPhases.RoomSummary)
aria-level={1} }
className="mx_RoomHeader_heading" className="mx_RoomHeader_infoWrapper"
> >
<span className="mx_RoomHeader_truncated mx_lineClamp">{roomName}</span> <Box flex="1" className="mx_RoomHeader_info">
<Text
as="div"
size="lg"
weight="semibold"
dir="auto"
role="heading"
aria-level={1}
className="mx_RoomHeader_heading"
>
<span className="mx_RoomHeader_truncated mx_lineClamp">{roomName}</span>
{!isDirectMessage && joinRule === JoinRule.Public && ( {!isDirectMessage && joinRule === JoinRule.Public && (
<Tooltip label={_t("common|public_room")} placement="right"> <Tooltip label={_t("common|public_room")} placement="right">
<PublicIcon <PublicIcon
width="16px" width="16px"
height="16px" height="16px"
className="mx_RoomHeader_icon" className="mx_RoomHeader_icon"
color="var(--cpd-color-icon-info-primary)" color="var(--cpd-color-icon-info-primary)"
aria-label={_t("common|public_room")} aria-label={_t("common|public_room")}
/> />
</Tooltip> </Tooltip>
)} )}
{isDirectMessage && e2eStatus === E2EStatus.Verified && ( {isDirectMessage && e2eStatus === E2EStatus.Verified && (
<Tooltip label={_t("common|verified")} placement="right"> <Tooltip label={_t("common|verified")} placement="right">
<VerifiedIcon <VerifiedIcon
width="16px" width="16px"
height="16px" height="16px"
className="mx_RoomHeader_icon mx_Verified" className="mx_RoomHeader_icon mx_Verified"
aria-label={_t("common|verified")} aria-label={_t("common|verified")}
/> />
</Tooltip> </Tooltip>
)} )}
{isDirectMessage && e2eStatus === E2EStatus.Warning && ( {isDirectMessage && e2eStatus === E2EStatus.Warning && (
<Tooltip label={_t("room|header_untrusted_label")} placement="right"> <Tooltip label={_t("room|header_untrusted_label")} placement="right">
<ErrorIcon <ErrorIcon
width="16px" width="16px"
height="16px" height="16px"
className="mx_RoomHeader_icon mx_Untrusted" className="mx_RoomHeader_icon mx_Untrusted"
aria-label={_t("room|header_untrusted_label")} aria-label={_t("room|header_untrusted_label")}
/> />
</Tooltip> </Tooltip>
)} )}
{isRoomEncrypted && historyVisibilityIcon(historyVisibility)} {isRoomEncrypted && historyVisibilityIcon(historyVisibility)}
</Text> </Text>
</Box> </Box>
</button> </button>
{/* If the room is local-only then we don't want to show any additional buttons, as it won't work */} {/* If the room is local-only then we don't want to show any additional buttons, as it won't work */}
{room instanceof LocalRoom === false && ( {room instanceof LocalRoom === false && (
<RoomHeaderButtons <RoomHeaderButtons
room={room} room={room}
legacyAdditionalButtons={legacyAdditionalButtons} legacyAdditionalButtons={legacyAdditionalButtons}
extraButtons={extraButtons} extraButtons={extraButtons}
/> />
)} )}
</Flex> </Flex>
{askToJoinEnabled && <RoomKnocksBar room={room} />} {askToJoinEnabled && <RoomKnocksBar room={room} />}
</CurrentRightPanelPhaseContextProvider> </CurrentRightPanelPhaseContextProvider>
</>
); );
} }
@@ -99,11 +99,6 @@ interface IProps {
canAskToJoinAndMembershipIsLeave?: boolean; canAskToJoinAndMembershipIsLeave?: boolean;
promptAskToJoin?: boolean; promptAskToJoin?: boolean;
/**
* If true, this will prompt for additional safety options
* like reporting an invite or ignoring the user.
*/
promptRejectionOptions?: boolean;
knocked?: boolean; knocked?: boolean;
onSubmitAskToJoin?(reason?: string): void; onSubmitAskToJoin?(reason?: string): void;
onCancelAskToJoin?(): void; onCancelAskToJoin?(): void;
@@ -322,7 +317,6 @@ class RoomPreviewBar extends React.Component<IProps, IState> {
let dangerActionHandler: (() => void) | undefined; let dangerActionHandler: (() => void) | undefined;
let dangerActionLabel: string | undefined; let dangerActionLabel: string | undefined;
let footer: JSX.Element | undefined; let footer: JSX.Element | undefined;
const extraComponents: JSX.Element[] = [];
const messageCase = this.getMessageCase(); const messageCase = this.getMessageCase();
switch (messageCase) { switch (messageCase) {
@@ -715,13 +709,11 @@ class RoomPreviewBar extends React.Component<IProps, IState> {
<> <>
{dangerActionButton} {dangerActionButton}
{secondaryButton} {secondaryButton}
{extraComponents}
{primaryButton} {primaryButton}
</> </>
) : ( ) : (
<> <>
{primaryButton} {primaryButton}
{extraComponents}
{secondaryButton} {secondaryButton}
{dangerActionButton} {dangerActionButton}
</> </>
@@ -818,25 +818,23 @@ export default class RoomSublist extends React.Component<IProps, IState> {
}); });
content = ( content = (
<React.Fragment> <Resizable
<Resizable size={{ height: this.state.height } as any}
size={{ height: this.state.height } as any} minHeight={minTilesPx}
minHeight={minTilesPx} maxHeight={maxTilesPx}
maxHeight={maxTilesPx} onResizeStart={this.onResizeStart}
onResizeStart={this.onResizeStart} onResizeStop={this.onResizeStop}
onResizeStop={this.onResizeStop} onResize={this.onResize}
onResize={this.onResize} handleWrapperClass={handleWrapperClasses}
handleWrapperClass={handleWrapperClasses} handleClasses={{ bottom: "mx_RoomSublist_resizerHandle" }}
handleClasses={{ bottom: "mx_RoomSublist_resizerHandle" }} className="mx_RoomSublist_resizeBox"
className="mx_RoomSublist_resizeBox" enable={handles}
enable={handles} >
> <div className="mx_RoomSublist_tiles" ref={this.tilesRef}>
<div className="mx_RoomSublist_tiles" ref={this.tilesRef}> {visibleTiles}
{visibleTiles} </div>
</div> {showNButton}
{showNButton} </Resizable>
</Resizable>
</React.Fragment>
); );
} else if (this.props.showSkeleton && this.state.isExpanded) { } else if (this.props.showSkeleton && this.state.isExpanded) {
content = <div className="mx_RoomSublist_skeletonUI" />; content = <div className="mx_RoomSublist_skeletonUI" />;
@@ -446,36 +446,34 @@ class RoomTile extends React.PureComponent<Props, State> {
} }
return ( return (
<React.Fragment> <RovingTabIndexWrapper inputRef={this.roomTileRef}>
<RovingTabIndexWrapper inputRef={this.roomTileRef}> {({ onFocus, isActive, ref }) => (
{({ onFocus, isActive, ref }) => ( <AccessibleButton
<AccessibleButton onFocus={onFocus}
onFocus={onFocus} tabIndex={isActive ? 0 : -1}
tabIndex={isActive ? 0 : -1} ref={ref}
ref={ref} className={classes}
className={classes} onClick={this.onTileClick}
onClick={this.onTileClick} onContextMenu={this.onContextMenu}
onContextMenu={this.onContextMenu} role="treeitem"
role="treeitem" aria-label={ariaLabel}
aria-label={ariaLabel} aria-selected={this.state.selected}
aria-selected={this.state.selected} aria-describedby={ariaDescribedBy}
aria-describedby={ariaDescribedBy} title={this.props.isMinimized && !this.state.generalMenuPosition ? name : undefined}
title={this.props.isMinimized && !this.state.generalMenuPosition ? name : undefined} >
> <DecoratedRoomAvatar
<DecoratedRoomAvatar room={this.props.room}
room={this.props.room} size="32px"
size="32px" displayBadge={this.props.isMinimized}
displayBadge={this.props.isMinimized} tooltipProps={{ tabIndex: isActive ? 0 : -1 }}
tooltipProps={{ tabIndex: isActive ? 0 : -1 }} />
/> {titleContainer}
{titleContainer} {badge}
{badge} {this.renderGeneralMenu()}
{this.renderGeneralMenu()} {this.renderNotificationsMenu(isActive)}
{this.renderNotificationsMenu(isActive)} </AccessibleButton>
</AccessibleButton> )}
)} </RovingTabIndexWrapper>
</RovingTabIndexWrapper>
</React.Fragment>
); );
} }
} }
@@ -12,7 +12,7 @@ import type { Call } from "../../../models/Call";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { useConnectionState, useParticipantCount } from "../../../hooks/useCall"; import { useConnectionState, useParticipantCount } from "../../../hooks/useCall";
import { ConnectionState } from "../../../models/Call"; import { ConnectionState } from "../../../models/Call";
import { LiveContentSummary, LiveContentType } from "./LiveContentSummary"; import { LiveContentSummary } from "./LiveContentSummary";
interface Props { interface Props {
call: Call; call: Call;
@@ -34,12 +34,5 @@ export const RoomTileCallSummary: FC<Props> = ({ call }) => {
break; break;
} }
return ( return <LiveContentSummary text={text} active={active} participantCount={useParticipantCount(call)} />;
<LiveContentSummary
type={LiveContentType.Video}
text={text}
active={active}
participantCount={useParticipantCount(call)}
/>
);
}; };
@@ -169,11 +169,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
const accessError = (): void => { const accessError = (): void => {
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: _t("voip|unable_to_access_audio_input_title"), title: _t("voip|unable_to_access_audio_input_title"),
description: ( description: <p>{_t("voip|unable_to_access_audio_input_description")}</p>,
<>
<p>{_t("voip|unable_to_access_audio_input_description")}</p>
</>
),
}); });
}; };
@@ -184,11 +180,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
if (!devices?.[MediaDeviceKindEnum.AudioInput]?.length) { if (!devices?.[MediaDeviceKindEnum.AudioInput]?.length) {
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: _t("voip|no_audio_input_title"), title: _t("voip|no_audio_input_title"),
description: ( description: <p>{_t("voip|no_audio_input_description")}</p>,
<>
<p>{_t("voip|no_audio_input_description")}</p>
</>
),
}); });
return; return;
} }
@@ -288,7 +280,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
if (this.state.recordingPhase === RecordingState.Uploading) { if (this.state.recordingPhase === RecordingState.Uploading) {
uploadIndicator = ( uploadIndicator = (
<span className="mx_VoiceRecordComposerTile_uploadingState"> <span className="mx_VoiceRecordComposerTile_uploadingState">
<InlineSpinner w={16} h={16} /> <InlineSpinner size={16} />
</span> </span>
); );
} else if (this.state.didUploadFail && this.state.recordingPhase === RecordingState.Ended) { } else if (this.state.didUploadFail && this.state.recordingPhase === RecordingState.Ended) {
@@ -38,7 +38,6 @@ interface IProps {
buttonClassName?: string; buttonClassName?: string;
buttonKind?: AccessibleButtonKind; buttonKind?: AccessibleButtonKind;
buttonLabel?: string; buttonLabel?: string;
confirm?: boolean;
// Whether to autoFocus the new password input // Whether to autoFocus the new password input
autoFocusNewPasswordInput?: boolean; autoFocusNewPasswordInput?: boolean;
className?: string; className?: string;
@@ -61,8 +60,6 @@ export default class ChangePassword extends React.Component<IProps, IState> {
public static defaultProps: Partial<IProps> = { public static defaultProps: Partial<IProps> = {
onFinished() {}, onFinished() {},
onError() {}, onError() {},
confirm: true,
}; };
public constructor(props: IProps) { public constructor(props: IProps) {
@@ -132,7 +132,6 @@ export const DiscoverySettings: React.FC = () => {
<> <>
<InlineTermsAgreement <InlineTermsAgreement
policiesAndServicePairs={requiredPolicyInfo.policiesAndServices} policiesAndServicePairs={requiredPolicyInfo.policiesAndServices}
agreedUrls={requiredPolicyInfo.agreedUrls}
onFinished={requiredPolicyInfo.resolve} onFinished={requiredPolicyInfo.resolve}
introElement={intro} introElement={intro}
/> />
@@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details.
import React, { type ChangeEvent, type JSX, type ReactElement, useCallback, useEffect, useState } from "react"; import React, { type ChangeEvent, type JSX, type ReactElement, useCallback, useEffect, useState } from "react";
import { SettingsToggleInput } from "@vector-im/compound-web"; import { SettingsToggleInput } from "@vector-im/compound-web";
import { type EmptyObject } from "matrix-js-sdk/src/matrix";
import { type NonEmptyArray } from "../../../../../@types/common"; import { type NonEmptyArray } from "../../../../../@types/common";
import { _t, getCurrentLanguage } from "../../../../../languageHandler"; import { _t, getCurrentLanguage } from "../../../../../languageHandler";
@@ -36,14 +37,9 @@ import { MediaPreviewAccountSettings } from "./MediaPreviewAccountSettings.tsx";
import { InviteRulesAccountSetting } from "./InviteRulesAccountSettings.tsx"; import { InviteRulesAccountSetting } from "./InviteRulesAccountSettings.tsx";
import SettingsDropdown from "../../../elements/SettingsDropdown.tsx"; import SettingsDropdown from "../../../elements/SettingsDropdown.tsx";
interface IProps {
closeSettingsFn(success: boolean): void;
}
interface IState { interface IState {
timezone: string | undefined; timezone: string | undefined;
timezones: string[]; timezones: string[];
timezoneSearch: string | undefined;
autocompleteDelay: string; autocompleteDelay: string;
readMarkerInViewThresholdMs: string; readMarkerInViewThresholdMs: string;
readMarkerOutOfViewThresholdMs: string; readMarkerOutOfViewThresholdMs: string;
@@ -120,7 +116,7 @@ const SpellCheckSection: React.FC = () => {
); );
}; };
export default class PreferencesUserSettingsTab extends React.Component<IProps, IState> { export default class PreferencesUserSettingsTab extends React.Component<EmptyObject, IState> {
private static ROOM_LIST_SETTINGS: BooleanSettingKey[] = ["breadcrumbs"]; private static ROOM_LIST_SETTINGS: BooleanSettingKey[] = ["breadcrumbs"];
private static SPACES_SETTINGS: BooleanSettingKey[] = ["Spaces.allRoomsInHome"]; private static SPACES_SETTINGS: BooleanSettingKey[] = ["Spaces.allRoomsInHome"];
@@ -171,13 +167,12 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
// Autocomplete delay (niche text box) // Autocomplete delay (niche text box)
]; ];
public constructor(props: IProps) { public constructor(props: EmptyObject) {
super(props); super(props);
this.state = { this.state = {
timezone: TimezoneHandler.getUserTimezone(), timezone: TimezoneHandler.getUserTimezone(),
timezones: TimezoneHandler.getAllTimezones(), timezones: TimezoneHandler.getAllTimezones(),
timezoneSearch: undefined,
autocompleteDelay: SettingsStore.getValueAt(SettingLevel.DEVICE, "autocompleteDelay").toString(10), autocompleteDelay: SettingsStore.getValueAt(SettingLevel.DEVICE, "autocompleteDelay").toString(10),
readMarkerInViewThresholdMs: SettingsStore.getValueAt( readMarkerInViewThresholdMs: SettingsStore.getValueAt(
SettingLevel.DEVICE, SettingLevel.DEVICE,
@@ -206,7 +201,7 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
}) })
: TimezoneHandler.getAllTimezones(); : TimezoneHandler.getAllTimezones();
this.setState({ timezones, timezoneSearch }); this.setState({ timezones });
}; };
private onAutocompleteDelayChange = (e: React.ChangeEvent<HTMLInputElement>): void => { private onAutocompleteDelayChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import React, { type JSX, type ReactNode } from "react"; import React, { type JSX, type ReactNode } from "react";
import { sleep } from "matrix-js-sdk/src/utils"; import { sleep } from "matrix-js-sdk/src/utils";
import { type Room, RoomEvent, type IServerVersions } from "matrix-js-sdk/src/matrix"; import { type Room, RoomEvent, type EmptyObject } from "matrix-js-sdk/src/matrix";
import { KnownMembership, type Membership } from "matrix-js-sdk/src/types"; import { KnownMembership, type Membership } from "matrix-js-sdk/src/types";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { WarningIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { WarningIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
@@ -80,22 +80,17 @@ export class IgnoredUser extends React.Component<IIgnoredUserProps> {
} }
} }
interface IProps {
closeSettingsFn: () => void;
}
interface IState { interface IState {
ignoredUserIds: string[]; ignoredUserIds: string[];
waitingUnignored: string[]; waitingUnignored: string[];
managingInvites: boolean; managingInvites: boolean;
invitedRoomIds: Set<string>; invitedRoomIds: Set<string>;
versions?: IServerVersions;
} }
export default class SecurityUserSettingsTab extends React.Component<IProps, IState> { export default class SecurityUserSettingsTab extends React.Component<EmptyObject, IState> {
private dispatcherRef?: string; private dispatcherRef?: string;
public constructor(props: IProps) { public constructor(props: EmptyObject) {
super(props); super(props);
// Get rooms we're invited to // Get rooms we're invited to
@@ -120,9 +115,6 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
public componentDidMount(): void { public componentDidMount(): void {
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
MatrixClientPeg.safeGet().on(RoomEvent.MyMembership, this.onMyMembership); MatrixClientPeg.safeGet().on(RoomEvent.MyMembership, this.onMyMembership);
MatrixClientPeg.safeGet()
.getVersions()
.then((versions) => this.setState({ versions }));
} }
public componentWillUnmount(): void { public componentWillUnmount(): void {
@@ -18,7 +18,6 @@ import ExternalLink from "../elements/ExternalLink.tsx";
interface IProps { interface IProps {
policiesAndServicePairs: ServicePolicyPair[]; policiesAndServicePairs: ServicePolicyPair[];
onFinished: (accepted: string[]) => void; onFinished: (accepted: string[]) => void;
agreedUrls: string[]; // array of URLs the user has accepted
introElement: React.ReactNode; introElement: React.ReactNode;
} }
@@ -16,7 +16,6 @@ import { PendingActionSpinner } from "../right_panel/EncryptionInfo";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";
interface IProps { interface IProps {
pending?: boolean;
displayName?: string; // required if pending is true displayName?: string; // required if pending is true
/** Details of the other device involved in the verification, if known */ /** Details of the other device involved in the verification, if known */
@@ -26,7 +25,6 @@ interface IProps {
onCancel: () => void; onCancel: () => void;
sas: GeneratedSas; sas: GeneratedSas;
isSelf?: boolean; isSelf?: boolean;
inDialog?: boolean; // whether this component is being shown in a dialog and to use DialogButtons
} }
interface IState { interface IState {
+5 -7
View File
@@ -427,13 +427,11 @@ export const SETTINGS: Settings = {
betaInfo: { betaInfo: {
title: _td("labs|notification_settings_beta_title"), title: _td("labs|notification_settings_beta_title"),
caption: () => ( caption: () => (
<> <p>
<p> {_t("labs|notification_settings_beta_caption", {
{_t("labs|notification_settings_beta_caption", { brand: SdkConfig.get().brand,
brand: SdkConfig.get().brand, })}
})} </p>
</p>
</>
), ),
}, },
}, },
@@ -281,7 +281,6 @@ export class ElementWidgetDriver extends WidgetDriver {
try { try {
const [result] = await Modal.createDialog(WidgetCapabilitiesPromptDialog, { const [result] = await Modal.createDialog(WidgetCapabilitiesPromptDialog, {
requestedCapabilities: missing, requestedCapabilities: missing,
widget: this.forWidget,
widgetKind: this.forWidgetKind, widgetKind: this.forWidgetKind,
}).finished; }).finished;
result?.approved?.forEach((cap) => allowedSoFar.add(cap)); result?.approved?.forEach((cap) => allowedSoFar.add(cap));
@@ -86,9 +86,7 @@ const MAX_RING_TIME_MS = 90 * 1000;
interface JoinCallButtonWithCallProps { interface JoinCallButtonWithCallProps {
onClick: (e: ButtonEvent) => void; onClick: (e: ButtonEvent) => void;
call: Call | null;
disabledTooltip: string | undefined; disabledTooltip: string | undefined;
isRinging: boolean;
} }
function JoinCallButtonWithCall({ onClick, disabledTooltip }: JoinCallButtonWithCallProps): JSX.Element { function JoinCallButtonWithCall({ onClick, disabledTooltip }: JoinCallButtonWithCallProps): JSX.Element {
@@ -379,8 +377,6 @@ export function IncomingCallToast({ notificationEvent, toastKey }: Props): JSX.E
/> />
<JoinCallButtonWithCall <JoinCallButtonWithCall
onClick={onJoinClick} onClick={onJoinClick}
call={call}
isRinging={notificationContent.notification_type === "ring"}
disabledTooltip={otherCallIsOngoing ? "Ongoing call" : undefined} disabledTooltip={otherCallIsOngoing ? "Ongoing call" : undefined}
/> />
</div> </div>
@@ -12,7 +12,6 @@ import { render, type RenderResult, screen } from "jest-matrix-react";
import { mocked } from "jest-mock"; import { mocked } from "jest-mock";
import LeftPanel from "../../../../src/components/structures/LeftPanel"; import LeftPanel from "../../../../src/components/structures/LeftPanel";
import PageType from "../../../../src/PageTypes";
import ResizeNotifier from "../../../../src/utils/ResizeNotifier"; import ResizeNotifier from "../../../../src/utils/ResizeNotifier";
import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents"; import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents";
import { UIComponent } from "../../../../src/settings/UIFeature"; import { UIComponent } from "../../../../src/settings/UIFeature";
@@ -23,9 +22,7 @@ jest.mock("../../../../src/customisations/helpers/UIComponents", () => ({
describe("LeftPanel", () => { describe("LeftPanel", () => {
function renderComponent(): RenderResult { function renderComponent(): RenderResult {
return render( return render(<LeftPanel isMinimized={false} resizeNotifier={new ResizeNotifier()} />);
<LeftPanel isMinimized={false} pageType={PageType.RoomView} resizeNotifier={new ResizeNotifier()} />,
);
} }
it("does not show filter container when disabled by UIComponent customisations", () => { it("does not show filter container when disabled by UIComponent customisations", () => {
@@ -13,11 +13,6 @@ import WidgetCapabilitiesPromptDialog from "../../../../../src/components/views/
import { stubClient } from "../../../../test-utils"; import { stubClient } from "../../../../test-utils";
describe("WidgetCapabilitiesPromptDialog", () => { describe("WidgetCapabilitiesPromptDialog", () => {
const mockWidget = {
id: "test-widget",
name: "Test Widget",
} as any;
const onFinished = jest.fn(); const onFinished = jest.fn();
beforeEach(() => { beforeEach(() => {
@@ -39,7 +34,6 @@ describe("WidgetCapabilitiesPromptDialog", () => {
const { container } = render( const { container } = render(
<WidgetCapabilitiesPromptDialog <WidgetCapabilitiesPromptDialog
requestedCapabilities={capabilities} requestedCapabilities={capabilities}
widget={mockWidget}
widgetKind={WidgetKind.Room} widgetKind={WidgetKind.Room}
onFinished={onFinished} onFinished={onFinished}
/>, />,
@@ -65,7 +59,6 @@ describe("WidgetCapabilitiesPromptDialog", () => {
render( render(
<WidgetCapabilitiesPromptDialog <WidgetCapabilitiesPromptDialog
requestedCapabilities={capabilities} requestedCapabilities={capabilities}
widget={mockWidget}
widgetKind={WidgetKind.Room} widgetKind={WidgetKind.Room}
onFinished={onFinished} onFinished={onFinished}
/>, />,
@@ -85,7 +78,6 @@ describe("WidgetCapabilitiesPromptDialog", () => {
const { container } = render( const { container } = render(
<WidgetCapabilitiesPromptDialog <WidgetCapabilitiesPromptDialog
requestedCapabilities={capabilities} requestedCapabilities={capabilities}
widget={mockWidget}
widgetKind={WidgetKind.Room} widgetKind={WidgetKind.Room}
onFinished={onFinished} onFinished={onFinished}
/>, />,
@@ -104,7 +96,6 @@ describe("WidgetCapabilitiesPromptDialog", () => {
const { container } = render( const { container } = render(
<WidgetCapabilitiesPromptDialog <WidgetCapabilitiesPromptDialog
requestedCapabilities={capabilities} requestedCapabilities={capabilities}
widget={mockWidget}
widgetKind={WidgetKind.Room} widgetKind={WidgetKind.Room}
onFinished={onFinished} onFinished={onFinished}
/>, />,
@@ -120,7 +111,6 @@ describe("WidgetCapabilitiesPromptDialog", () => {
const { container } = render( const { container } = render(
<WidgetCapabilitiesPromptDialog <WidgetCapabilitiesPromptDialog
requestedCapabilities={capabilities} requestedCapabilities={capabilities}
widget={mockWidget}
widgetKind={WidgetKind.Room} widgetKind={WidgetKind.Room}
onFinished={onFinished} onFinished={onFinished}
/>, />,
@@ -15,7 +15,7 @@ exports[`InviteProgressBody should match snapshot 1`] = `
fill="currentColor" fill="currentColor"
height="1em" height="1em"
role="progressbar" role="progressbar"
style="width: 20px; height: 20px;" style="width: 32px; height: 32px;"
viewBox="0 0 24 24" viewBox="0 0 24 24"
width="1em" width="1em"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@@ -197,7 +197,7 @@ exports[`<RoomSettingsDialog /> poll history displays poll history when tab clic
fill="currentColor" fill="currentColor"
height="1em" height="1em"
role="progressbar" role="progressbar"
style="width: 20px; height: 20px;" style="width: 16px; height: 16px;"
viewBox="0 0 24 24" viewBox="0 0 24 24"
width="1em" width="1em"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@@ -201,7 +201,7 @@ exports[`<PollHistory /> renders a no polls message and a load more button when
fill="currentColor" fill="currentColor"
height="1em" height="1em"
role="progressbar" role="progressbar"
style="width: 20px; height: 20px;" style="width: 16px; height: 16px;"
viewBox="0 0 24 24" viewBox="0 0 24 24"
width="1em" width="1em"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@@ -31,7 +31,7 @@ describe("PreferencesUserSettingsTab", () => {
}); });
const renderTab = (): RenderResult => { const renderTab = (): RenderResult => {
return render(<PreferencesUserSettingsTab closeSettingsFn={() => {}} />); return render(<PreferencesUserSettingsTab />);
}; };
it("should render", () => { it("should render", () => {
@@ -25,10 +25,6 @@ import { UIFeature } from "../../../../../../../src/settings/UIFeature";
import SettingsStore from "../../../../../../../src/settings/SettingsStore"; import SettingsStore from "../../../../../../../src/settings/SettingsStore";
describe("<SecurityUserSettingsTab />", () => { describe("<SecurityUserSettingsTab />", () => {
const defaultProps = {
closeSettingsFn: jest.fn(),
};
const getIgnoredUsers = jest.fn(); const getIgnoredUsers = jest.fn();
const setIgnoredUsers = jest.fn(); const setIgnoredUsers = jest.fn();
@@ -51,7 +47,7 @@ describe("<SecurityUserSettingsTab />", () => {
const getComponent = () => ( const getComponent = () => (
<MatrixClientContext.Provider value={mockClient}> <MatrixClientContext.Provider value={mockClient}>
<SDKContext.Provider value={sdkContext}> <SDKContext.Provider value={sdkContext}>
<SecurityUserSettingsTab {...defaultProps} /> <SecurityUserSettingsTab />
</SDKContext.Provider> </SDKContext.Provider>
</MatrixClientContext.Provider> </MatrixClientContext.Provider>
); );