Merge pull request #5155 from matrix-org/t3chguy/lint-ts

Fix eslint ts override tsx matching and delint
This commit is contained in:
Michael Telatynski 2020-09-01 16:44:22 +01:00 committed by GitHub
commit 7c4a84aae0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 257 additions and 242 deletions

View file

@ -19,7 +19,7 @@ module.exports = {
}, },
overrides: [{ overrides: [{
"files": ["src/**/*.{ts, tsx}"], "files": ["src/**/*.{ts,tsx}"],
"extends": ["matrix-org/ts"], "extends": ["matrix-org/ts"],
"rules": { "rules": {
// We disable this while we're transitioning // We disable this while we're transitioning

View file

@ -70,6 +70,7 @@ interface IContent {
interface IThumbnail { interface IThumbnail {
info: { info: {
// eslint-disable-next-line camelcase
thumbnail_info: { thumbnail_info: {
w: number; w: number;
h: number; h: number;
@ -104,7 +105,12 @@ interface IAbortablePromise<T> extends Promise<T> {
* @return {Promise} A promise that resolves with an object with an info key * @return {Promise} A promise that resolves with an object with an info key
* and a thumbnail key. * and a thumbnail key.
*/ */
function createThumbnail(element: ThumbnailableElement, inputWidth: number, inputHeight: number, mimeType: string): Promise<IThumbnail> { function createThumbnail(
element: ThumbnailableElement,
inputWidth: number,
inputHeight: number,
mimeType: string,
): Promise<IThumbnail> {
return new Promise((resolve) => { return new Promise((resolve) => {
let targetWidth = inputWidth; let targetWidth = inputWidth;
let targetHeight = inputHeight; let targetHeight = inputHeight;
@ -437,11 +443,13 @@ export default class ContentMessages {
for (let i = 0; i < okFiles.length; ++i) { for (let i = 0; i < okFiles.length; ++i) {
const file = okFiles[i]; const file = okFiles[i];
if (!uploadAll) { if (!uploadAll) {
const {finished} = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation', '', UploadConfirmDialog, { const {finished} = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation',
file, '', UploadConfirmDialog, {
currentIndex: i, file,
totalFiles: okFiles.length, currentIndex: i,
}); totalFiles: okFiles.length,
},
);
const [shouldContinue, shouldUploadAll] = await finished; const [shouldContinue, shouldUploadAll] = await finished;
if (!shouldContinue) break; if (!shouldContinue) break;
if (shouldUploadAll) { if (shouldUploadAll) {

View file

@ -339,33 +339,9 @@ class HtmlHighlighter extends BaseHighlighter<string> {
} }
} }
class TextHighlighter extends BaseHighlighter<React.ReactNode> {
private key = 0;
/* create a <span> node to hold the given content
*
* snippet: content of the span
* highlight: true to highlight as a search match
*
* returns a React node
*/
protected processSnippet(snippet: string, highlight: boolean): React.ReactNode {
const key = this.key++;
let node = <span key={key} className={highlight ? this.highlightClass : null}>
{ snippet }
</span>;
if (highlight && this.highlightLink) {
node = <a key={key} href={this.highlightLink}>{ node }</a>;
}
return node;
}
}
interface IContent { interface IContent {
format?: string; format?: string;
// eslint-disable-next-line camelcase
formatted_body?: string; formatted_body?: string;
body: string; body: string;
} }
@ -474,8 +450,13 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts
}); });
return isDisplayedWithHtml ? return isDisplayedWithHtml ?
<span key="body" ref={opts.ref} className={className} dangerouslySetInnerHTML={{ __html: safeBody }} dir="auto" /> : <span
<span key="body" ref={opts.ref} className={className} dir="auto">{ strippedBody }</span>; key="body"
ref={opts.ref}
className={className}
dangerouslySetInnerHTML={{ __html: safeBody }}
dir="auto"
/> : <span key="body" ref={opts.ref} className={className} dir="auto">{ strippedBody }</span>;
} }
/** /**

View file

@ -151,7 +151,7 @@ export class ModalManager {
prom: Promise<React.ComponentType>, prom: Promise<React.ComponentType>,
props?: IProps<T>, props?: IProps<T>,
className?: string, className?: string,
options?: IOptions<T> options?: IOptions<T>,
) { ) {
const modal: IModal<T> = { const modal: IModal<T> = {
onFinished: props ? props.onFinished : null, onFinished: props ? props.onFinished : null,
@ -182,7 +182,7 @@ export class ModalManager {
private getCloseFn<T extends any[]>( private getCloseFn<T extends any[]>(
modal: IModal<T>, modal: IModal<T>,
props: IProps<T> props: IProps<T>,
): [IHandle<T>["close"], IHandle<T>["finished"]] { ): [IHandle<T>["close"], IHandle<T>["finished"]] {
const deferred = defer<T>(); const deferred = defer<T>();
return [async (...args: T) => { return [async (...args: T) => {
@ -264,7 +264,7 @@ export class ModalManager {
className?: string, className?: string,
isPriorityModal = false, isPriorityModal = false,
isStaticModal = false, isStaticModal = false,
options: IOptions<T> = {} options: IOptions<T> = {},
): IHandle<T> { ): IHandle<T> {
const {modal, closeDialog, onFinishedProm} = this.buildModal<T>(prom, props, className, options); const {modal, closeDialog, onFinishedProm} = this.buildModal<T>(prom, props, className, options);
if (isPriorityModal) { if (isPriorityModal) {
@ -287,7 +287,7 @@ export class ModalManager {
private appendDialogAsync<T extends any[]>( private appendDialogAsync<T extends any[]>(
prom: Promise<React.ComponentType>, prom: Promise<React.ComponentType>,
props?: IProps<T>, props?: IProps<T>,
className?: string className?: string,
): IHandle<T> { ): IHandle<T> {
const {modal, closeDialog, onFinishedProm} = this.buildModal<T>(prom, props, className, {}); const {modal, closeDialog, onFinishedProm} = this.buildModal<T>(prom, props, className, {});

View file

@ -860,12 +860,12 @@ export const Commands = [
_t('WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session' + _t('WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session' +
' %(deviceId)s is "%(fprint)s" which does not match the provided key ' + ' %(deviceId)s is "%(fprint)s" which does not match the provided key ' +
'"%(fingerprint)s". This could mean your communications are being intercepted!', '"%(fingerprint)s". This could mean your communications are being intercepted!',
{ {
fprint, fprint,
userId, userId,
deviceId, deviceId,
fingerprint, fingerprint,
})); }));
} }
await cli.setDeviceVerified(userId, deviceId, true); await cli.setDeviceVerified(userId, deviceId, true);
@ -879,7 +879,7 @@ export const Commands = [
{ {
_t('The signing key you provided matches the signing key you received ' + _t('The signing key you provided matches the signing key you received ' +
'from %(userId)s\'s session %(deviceId)s. Session marked as verified.', 'from %(userId)s\'s session %(deviceId)s. Session marked as verified.',
{userId, deviceId}) {userId, deviceId})
} }
</p> </p>
</div>, </div>,

View file

@ -168,7 +168,7 @@ const shortcuts: Record<Categories, IShortcut[]> = {
key: Key.U, key: Key.U,
}], }],
description: _td("Upload a file"), description: _td("Upload a file"),
} },
], ],
[Categories.ROOM_LIST]: [ [Categories.ROOM_LIST]: [

View file

@ -190,7 +190,7 @@ export const RovingTabIndexProvider: React.FC<IProps> = ({children, handleHomeEn
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
} else if (onKeyDown) { } else if (onKeyDown) {
return onKeyDown(ev, state); return onKeyDown(ev, context.state);
} }
}, [context.state, onKeyDown, handleHomeEnd]); }, [context.state, onKeyDown, handleHomeEnd]);

View file

@ -30,6 +30,7 @@ const Toolbar: React.FC<IProps> = ({children, ...props}) => {
const target = ev.target as HTMLElement; const target = ev.target as HTMLElement;
let handled = true; let handled = true;
// HOME and END are handled by RovingTabIndexProvider
switch (ev.key) { switch (ev.key) {
case Key.ARROW_UP: case Key.ARROW_UP:
case Key.ARROW_DOWN: case Key.ARROW_DOWN:
@ -47,8 +48,6 @@ const Toolbar: React.FC<IProps> = ({children, ...props}) => {
} }
break; break;
// HOME and END are handled by RovingTabIndexProvider
default: default:
handled = false; handled = false;
} }

View file

@ -20,7 +20,7 @@ import React from "react";
import AccessibleTooltipButton from "../../components/views/elements/AccessibleTooltipButton"; import AccessibleTooltipButton from "../../components/views/elements/AccessibleTooltipButton";
interface IProps extends React.ComponentProps<typeof AccessibleTooltipButton> { interface IProps extends React.ComponentProps<typeof AccessibleTooltipButton> {
// whether or not the context menu is currently open // whether or not the context menu is currently open
isExpanded: boolean; isExpanded: boolean;
} }

View file

@ -20,7 +20,8 @@ import AccessibleTooltipButton from "../../components/views/elements/AccessibleT
import {useRovingTabIndex} from "../RovingTabIndex"; import {useRovingTabIndex} from "../RovingTabIndex";
import {Ref} from "./types"; import {Ref} from "./types";
interface IProps extends Omit<React.ComponentProps<typeof AccessibleTooltipButton>, "onFocus" | "inputRef" | "tabIndex"> { type ATBProps = React.ComponentProps<typeof AccessibleTooltipButton>;
interface IProps extends Omit<ATBProps, "onFocus" | "inputRef" | "tabIndex"> {
inputRef?: Ref; inputRef?: Ref;
} }

View file

@ -16,7 +16,6 @@ limitations under the License.
import React from "react"; import React from "react";
import AccessibleButton from "../../components/views/elements/AccessibleButton";
import {useRovingTabIndex} from "../RovingTabIndex"; import {useRovingTabIndex} from "../RovingTabIndex";
import {FocusHandler, Ref} from "./types"; import {FocusHandler, Ref} from "./types";

View file

@ -89,7 +89,11 @@ export default class CommandProvider extends AutocompleteProvider {
renderCompletions(completions: React.ReactNode[]): React.ReactNode { renderCompletions(completions: React.ReactNode[]): React.ReactNode {
return ( return (
<div className="mx_Autocomplete_Completion_container_block" role="listbox" aria-label={_t("Command Autocomplete")}> <div
className="mx_Autocomplete_Completion_container_block"
role="listbox"
aria-label={_t("Command Autocomplete")}
>
{ completions } { completions }
</div> </div>
); );

View file

@ -91,15 +91,15 @@ export default class CommunityProvider extends AutocompleteProvider {
href: makeGroupPermalink(groupId), href: makeGroupPermalink(groupId),
component: ( component: (
<PillCompletion title={name} description={groupId}> <PillCompletion title={name} description={groupId}>
<BaseAvatar name={name || groupId} <BaseAvatar
width={24} name={name || groupId}
height={24} width={24}
url={avatarUrl ? cli.mxcUrlToHttp(avatarUrl, 24, 24) : null} /> height={24}
url={avatarUrl ? cli.mxcUrlToHttp(avatarUrl, 24, 24) : null} />
</PillCompletion> </PillCompletion>
), ),
range, range,
})) })).slice(0, 4);
.slice(0, 4);
} }
return completions; return completions;
} }

View file

@ -34,9 +34,9 @@ export const TextualCompletion = forwardRef<ITextualCompletionProps, any>((props
const {title, subtitle, description, className, ...restProps} = props; const {title, subtitle, description, className, ...restProps} = props;
return ( return (
<div {...restProps} <div {...restProps}
className={classNames('mx_Autocomplete_Completion_block', className)} className={classNames('mx_Autocomplete_Completion_block', className)}
role="option" role="option"
ref={ref} ref={ref}
> >
<span className="mx_Autocomplete_Completion_title">{ title }</span> <span className="mx_Autocomplete_Completion_title">{ title }</span>
<span className="mx_Autocomplete_Completion_subtitle">{ subtitle }</span> <span className="mx_Autocomplete_Completion_subtitle">{ subtitle }</span>
@ -53,9 +53,9 @@ export const PillCompletion = forwardRef<IPillCompletionProps, any>((props, ref)
const {title, subtitle, description, className, children, ...restProps} = props; const {title, subtitle, description, className, children, ...restProps} = props;
return ( return (
<div {...restProps} <div {...restProps}
className={classNames('mx_Autocomplete_Completion_pill', className)} className={classNames('mx_Autocomplete_Completion_pill', className)}
role="option" role="option"
ref={ref} ref={ref}
> >
{ children } { children }
<span className="mx_Autocomplete_Completion_title">{ title }</span> <span className="mx_Autocomplete_Completion_title">{ title }</span>

View file

@ -139,7 +139,11 @@ export default class EmojiProvider extends AutocompleteProvider {
renderCompletions(completions: React.ReactNode[]): React.ReactNode { renderCompletions(completions: React.ReactNode[]): React.ReactNode {
return ( return (
<div className="mx_Autocomplete_Completion_container_pill" role="listbox" aria-label={_t("Emoji Autocomplete")}> <div
className="mx_Autocomplete_Completion_container_pill"
role="listbox"
aria-label={_t("Emoji Autocomplete")}
>
{ completions } { completions }
</div> </div>
); );

View file

@ -110,9 +110,7 @@ export default class RoomProvider extends AutocompleteProvider {
), ),
range, range,
}; };
}) }).filter((completion) => !!completion.completion && completion.completion.length > 0).slice(0, 4);
.filter((completion) => !!completion.completion && completion.completion.length > 0)
.slice(0, 4);
} }
return completions; return completions;
} }

View file

@ -71,8 +71,13 @@ export default class UserProvider extends AutocompleteProvider {
} }
} }
private onRoomTimeline = (ev: MatrixEvent, room: Room, toStartOfTimeline: boolean, removed: boolean, private onRoomTimeline = (
data: IRoomTimelineData) => { ev: MatrixEvent,
room: Room,
toStartOfTimeline: boolean,
removed: boolean,
data: IRoomTimelineData,
) => {
if (!room) return; if (!room) return;
if (removed) return; if (removed) return;
if (room.roomId !== this.room.roomId) return; if (room.roomId !== this.room.roomId) return;
@ -171,7 +176,11 @@ export default class UserProvider extends AutocompleteProvider {
renderCompletions(completions: React.ReactNode[]): React.ReactNode { renderCompletions(completions: React.ReactNode[]): React.ReactNode {
return ( return (
<div className="mx_Autocomplete_Completion_container_pill" role="listbox" aria-label={_t("User Autocomplete")}> <div
className="mx_Autocomplete_Completion_container_pill"
role="listbox"
aria-label={_t("User Autocomplete")}
>
{ completions } { completions }
</div> </div>
); );

View file

@ -233,8 +233,7 @@ export class ContextMenu extends React.PureComponent<IProps, IState> {
switch (ev.key) { switch (ev.key) {
case Key.TAB: case Key.TAB:
case Key.ESCAPE: case Key.ESCAPE:
// close on left and right arrows too for when it is a context menu on a <Toolbar /> case Key.ARROW_LEFT: // close on left and right arrows too for when it is a context menu on a <Toolbar />
case Key.ARROW_LEFT:
case Key.ARROW_RIGHT: case Key.ARROW_RIGHT:
this.props.onFinished(); this.props.onFinished();
break; break;

View file

@ -377,7 +377,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
public render(): React.ReactNode { public render(): React.ReactNode {
const tagPanel = !this.state.showTagPanel ? null : ( const tagPanel = !this.state.showTagPanel ? null : (
<div className="mx_LeftPanel_tagPanelContainer"> <div className="mx_LeftPanel_tagPanelContainer">
<TagPanel/> <TagPanel />
{SettingsStore.getValue("feature_custom_tags") ? <CustomRoomTagPanel /> : null} {SettingsStore.getValue("feature_custom_tags") ? <CustomRoomTagPanel /> : null}
</div> </div>
); );

View file

@ -43,11 +43,11 @@ import PlatformPeg from "../../PlatformPeg";
import { DefaultTagID } from "../../stores/room-list/models"; import { DefaultTagID } from "../../stores/room-list/models";
import { import {
showToast as showSetPasswordToast, showToast as showSetPasswordToast,
hideToast as hideSetPasswordToast hideToast as hideSetPasswordToast,
} from "../../toasts/SetPasswordToast"; } from "../../toasts/SetPasswordToast";
import { import {
showToast as showServerLimitToast, showToast as showServerLimitToast,
hideToast as hideServerLimitToast hideToast as hideServerLimitToast,
} from "../../toasts/ServerLimitToast"; } from "../../toasts/ServerLimitToast";
import { Action } from "../../dispatcher/actions"; import { Action } from "../../dispatcher/actions";
import LeftPanel from "./LeftPanel"; import LeftPanel from "./LeftPanel";
@ -79,6 +79,7 @@ interface IProps {
initialEventPixelOffset: number; initialEventPixelOffset: number;
leftDisabled: boolean; leftDisabled: boolean;
rightDisabled: boolean; rightDisabled: boolean;
// eslint-disable-next-line camelcase
page_type: string; page_type: string;
autoJoin: boolean; autoJoin: boolean;
thirdPartyInvite?: object; thirdPartyInvite?: object;
@ -98,7 +99,9 @@ interface IProps {
} }
interface IUsageLimit { interface IUsageLimit {
// eslint-disable-next-line camelcase
limit_type: "monthly_active_user" | string; limit_type: "monthly_active_user" | string;
// eslint-disable-next-line camelcase
admin_contact?: string; admin_contact?: string;
} }
@ -316,10 +319,10 @@ class LoggedInView extends React.Component<IProps, IState> {
} }
}; };
_calculateServerLimitToast(syncErrorData: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) { _calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) {
const error = syncErrorData && syncErrorData.error && syncErrorData.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED"; const error = syncError && syncError.error && syncError.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED";
if (error) { if (error) {
usageLimitEventContent = syncErrorData.error.data; usageLimitEventContent = syncError.error.data;
} }
if (usageLimitEventContent) { if (usageLimitEventContent) {
@ -620,18 +623,18 @@ class LoggedInView extends React.Component<IProps, IState> {
switch (this.props.page_type) { switch (this.props.page_type) {
case PageTypes.RoomView: case PageTypes.RoomView:
pageElement = <RoomView pageElement = <RoomView
ref={this._roomView} ref={this._roomView}
autoJoin={this.props.autoJoin} autoJoin={this.props.autoJoin}
onRegistered={this.props.onRegistered} onRegistered={this.props.onRegistered}
thirdPartyInvite={this.props.thirdPartyInvite} thirdPartyInvite={this.props.thirdPartyInvite}
oobData={this.props.roomOobData} oobData={this.props.roomOobData}
viaServers={this.props.viaServers} viaServers={this.props.viaServers}
eventPixelOffset={this.props.initialEventPixelOffset} eventPixelOffset={this.props.initialEventPixelOffset}
key={this.props.currentRoomId || 'roomview'} key={this.props.currentRoomId || 'roomview'}
disabled={this.props.middleDisabled} disabled={this.props.middleDisabled}
ConferenceHandler={this.props.ConferenceHandler} ConferenceHandler={this.props.ConferenceHandler}
resizeNotifier={this.props.resizeNotifier} resizeNotifier={this.props.resizeNotifier}
/>; />;
break; break;
case PageTypes.MyGroups: case PageTypes.MyGroups:

View file

@ -69,7 +69,7 @@ import { ViewUserPayload } from "../../dispatcher/payloads/ViewUserPayload";
import { Action } from "../../dispatcher/actions"; import { Action } from "../../dispatcher/actions";
import { import {
showToast as showAnalyticsToast, showToast as showAnalyticsToast,
hideToast as hideAnalyticsToast hideToast as hideAnalyticsToast,
} from "../../toasts/AnalyticsToast"; } from "../../toasts/AnalyticsToast";
import {showToast as showNotificationsToast} from "../../toasts/DesktopNotificationsToast"; import {showToast as showNotificationsToast} from "../../toasts/DesktopNotificationsToast";
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload"; import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
@ -129,6 +129,7 @@ interface IScreen {
params?: object; params?: object;
} }
/* eslint-disable camelcase */
interface IRoomInfo { interface IRoomInfo {
room_id?: string; room_id?: string;
room_alias?: string; room_alias?: string;
@ -140,6 +141,7 @@ interface IRoomInfo {
oob_data?: object; oob_data?: object;
via_servers?: string[]; via_servers?: string[];
} }
/* eslint-enable camelcase */
interface IProps { // TODO type things better interface IProps { // TODO type things better
config: Record<string, any>; config: Record<string, any>;
@ -165,6 +167,7 @@ interface IState {
// the master view we are showing. // the master view we are showing.
view: Views; view: Views;
// What the LoggedInView would be showing if visible // What the LoggedInView would be showing if visible
// eslint-disable-next-line camelcase
page_type?: PageTypes; page_type?: PageTypes;
// The ID of the room we're viewing. This is either populated directly // The ID of the room we're viewing. This is either populated directly
// in the case where we view a room by ID or by RoomView when it resolves // in the case where we view a room by ID or by RoomView when it resolves
@ -180,8 +183,11 @@ interface IState {
middleDisabled: boolean; middleDisabled: boolean;
// the right panel's disabled state is tracked in its store. // the right panel's disabled state is tracked in its store.
// Parameters used in the registration dance with the IS // Parameters used in the registration dance with the IS
// eslint-disable-next-line camelcase
register_client_secret?: string; register_client_secret?: string;
// eslint-disable-next-line camelcase
register_session_id?: string; register_session_id?: string;
// eslint-disable-next-line camelcase
register_id_sid?: string; register_id_sid?: string;
// When showing Modal dialogs we need to set aria-hidden on the root app element // When showing Modal dialogs we need to set aria-hidden on the root app element
// and disable it when there are no dialogs // and disable it when there are no dialogs
@ -341,6 +347,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle stage // TODO: [REACT-WARNING] Replace with appropriate lifecycle stage
// eslint-disable-next-line camelcase
UNSAFE_componentWillUpdate(props, state) { UNSAFE_componentWillUpdate(props, state) {
if (this.shouldTrackPageChange(this.state, state)) { if (this.shouldTrackPageChange(this.state, state)) {
this.startPageChangeTimer(); this.startPageChangeTimer();
@ -610,8 +617,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog"); const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog");
Modal.createTrackedDialog('User settings', '', UserSettingsDialog, Modal.createTrackedDialog('User settings', '', UserSettingsDialog,
{initialTabId: tabPayload.initialTabId}, {initialTabId: tabPayload.initialTabId},
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true /*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
);
// View the welcome or home page if we need something to look at // View the welcome or home page if we need something to look at
this.viewSomethingBehindModal(); this.viewSomethingBehindModal();
@ -1080,7 +1086,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
title: _t("Leave room"), title: _t("Leave room"),
description: ( description: (
<span> <span>
{ _t("Are you sure you want to leave the room '%(roomName)s'?", {roomName: roomToLeave.name}) } { _t("Are you sure you want to leave the room '%(roomName)s'?", {roomName: roomToLeave.name}) }
{ warnings } { warnings }
</span> </span>
), ),
@ -1433,7 +1439,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
cli.on("crypto.warning", (type) => { cli.on("crypto.warning", (type) => {
switch (type) { switch (type) {
case 'CRYPTO_WARNING_OLD_VERSION_DETECTED': case 'CRYPTO_WARNING_OLD_VERSION_DETECTED':
const brand = SdkConfig.get().brand;
Modal.createTrackedDialog('Crypto migrated', '', ErrorDialog, { Modal.createTrackedDialog('Crypto migrated', '', ErrorDialog, {
title: _t('Old cryptography data detected'), title: _t('Old cryptography data detected'),
description: _t( description: _t(
@ -1444,7 +1449,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
"in this version. This may also cause messages exchanged with this " + "in this version. This may also cause messages exchanged with this " +
"version to fail. If you experience problems, log out and back in " + "version to fail. If you experience problems, log out and back in " +
"again. To retain message history, export and re-import your keys.", "again. To retain message history, export and re-import your keys.",
{ brand }, { brand: SdkConfig.get().brand },
), ),
}); });
break; break;

View file

@ -20,7 +20,6 @@ import classNames from "classnames";
import defaultDispatcher from "../../dispatcher/dispatcher"; import defaultDispatcher from "../../dispatcher/dispatcher";
import { _t } from "../../languageHandler"; import { _t } from "../../languageHandler";
import { ActionPayload } from "../../dispatcher/payloads"; import { ActionPayload } from "../../dispatcher/payloads";
import { throttle } from 'lodash';
import { Key } from "../../Keyboard"; import { Key } from "../../Keyboard";
import AccessibleButton from "../views/elements/AccessibleButton"; import AccessibleButton from "../views/elements/AccessibleButton";
import { Action } from "../../dispatcher/actions"; import { Action } from "../../dispatcher/actions";
@ -137,7 +136,7 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
}); });
let icon = ( let icon = (
<div className='mx_RoomSearch_icon'/> <div className='mx_RoomSearch_icon' />
); );
let input = ( let input = (
<input <input

View file

@ -18,7 +18,6 @@ limitations under the License.
import * as React from "react"; import * as React from "react";
import {_t} from '../../languageHandler'; import {_t} from '../../languageHandler';
import * as PropTypes from "prop-types";
import * as sdk from "../../index"; import * as sdk from "../../index";
import AutoHideScrollbar from './AutoHideScrollbar'; import AutoHideScrollbar from './AutoHideScrollbar';
import { ReactNode } from "react"; import { ReactNode } from "react";

View file

@ -40,7 +40,7 @@ import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
import { SettingLevel } from "../../settings/SettingLevel"; import { SettingLevel } from "../../settings/SettingLevel";
import IconizedContextMenu, { import IconizedContextMenu, {
IconizedContextMenuOption, IconizedContextMenuOption,
IconizedContextMenuOptionList IconizedContextMenuOptionList,
} from "../views/context_menus/IconizedContextMenu"; } from "../views/context_menus/IconizedContextMenu";
interface IProps { interface IProps {
@ -234,12 +234,12 @@ export default class UserMenu extends React.Component<IProps, IState> {
> >
<div className="mx_UserMenu_contextMenu_header"> <div className="mx_UserMenu_contextMenu_header">
<div className="mx_UserMenu_contextMenu_name"> <div className="mx_UserMenu_contextMenu_name">
<span className="mx_UserMenu_contextMenu_displayName"> <span className="mx_UserMenu_contextMenu_displayName">
{OwnProfileStore.instance.displayName} {OwnProfileStore.instance.displayName}
</span> </span>
<span className="mx_UserMenu_contextMenu_userId"> <span className="mx_UserMenu_contextMenu_userId">
{MatrixClientPeg.get().getUserId()} {MatrixClientPeg.get().getUserId()}
</span> </span>
</div> </div>
<AccessibleTooltipButton <AccessibleTooltipButton
className="mx_UserMenu_contextMenu_themeButton" className="mx_UserMenu_contextMenu_themeButton"

View file

@ -17,7 +17,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, {useCallback, useContext, useEffect, useMemo, useState} from 'react'; import React, {useCallback, useContext, useEffect, useState} from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import * as AvatarLogic from '../../../Avatar'; import * as AvatarLogic from '../../../Avatar';
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
@ -96,7 +96,7 @@ const BaseAvatar = (props: IProps) => {
urls, urls,
width = 40, width = 40,
height = 40, height = 40,
resizeMethod = "crop", // eslint-disable-line no-unused-vars resizeMethod = "crop", // eslint-disable-line @typescript-eslint/no-unused-vars
defaultToInitialLetter = true, defaultToInitialLetter = true,
onClick, onClick,
inputRef, inputRef,

View file

@ -126,7 +126,7 @@ export default class DecoratedRoomAvatar extends React.PureComponent<IProps, ISt
private onPresenceUpdate = () => { private onPresenceUpdate = () => {
if (this.isUnmounted) return; if (this.isUnmounted) return;
let newIcon = this.getPresenceIcon(); const newIcon = this.getPresenceIcon();
if (newIcon !== this.state.icon) this.setState({icon: newIcon}); if (newIcon !== this.state.icon) this.setState({icon: newIcon});
}; };

View file

@ -47,7 +47,7 @@ export default class GroupAvatar extends React.Component<IProps> {
render() { render() {
// extract the props we use from props so we can pass any others through // extract the props we use from props so we can pass any others through
// should consider adding this as a global rule in js-sdk? // should consider adding this as a global rule in js-sdk?
/*eslint no-unused-vars: ["error", { "ignoreRestSiblings": true }]*/ /* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */
const {groupId, groupAvatarUrl, groupName, ...otherProps} = this.props; const {groupId, groupAvatarUrl, groupName, ...otherProps} = this.props;
return ( return (

View file

@ -21,9 +21,6 @@ import { IDialogProps } from "./IDialogProps";
import Field from "../elements/Field"; import Field from "../elements/Field";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import InfoTooltip from "../elements/InfoTooltip";
import dis from "../../../dispatcher/dispatcher";
import {showCommunityRoomInviteDialog} from "../../../RoomInvite";
import { arrayFastClone } from "../../../utils/arrays"; import { arrayFastClone } from "../../../utils/arrays";
import SdkConfig from "../../../SdkConfig"; import SdkConfig from "../../../SdkConfig";
import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { RoomMember } from "matrix-js-sdk/src/models/room-member";
@ -31,7 +28,6 @@ import InviteDialog from "./InviteDialog";
import BaseAvatar from "../avatars/BaseAvatar"; import BaseAvatar from "../avatars/BaseAvatar";
import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo"; import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo";
import {inviteMultipleToRoom, showAnyInviteErrors} from "../../../RoomInvite"; import {inviteMultipleToRoom, showAnyInviteErrors} from "../../../RoomInvite";
import {humanizeTime} from "../../../utils/humanize";
import StyledCheckbox from "../elements/StyledCheckbox"; import StyledCheckbox from "../elements/StyledCheckbox";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import ErrorDialog from "./ErrorDialog"; import ErrorDialog from "./ErrorDialog";
@ -171,7 +167,7 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent<
public render() { public render() {
const emailAddresses = []; const emailAddresses = [];
this.state.emailTargets.forEach((address, i) => { this.state.emailTargets.forEach((address, i) => {
emailAddresses.push( emailAddresses.push((
<Field <Field
key={i} key={i}
value={address} value={address}
@ -180,11 +176,11 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent<
placeholder={_t("Email address")} placeholder={_t("Email address")}
onBlur={() => this.onAddressBlur(i)} onBlur={() => this.onAddressBlur(i)}
/> />
); ));
}); });
// Push a clean input // Push a clean input
emailAddresses.push( emailAddresses.push((
<Field <Field
key={emailAddresses.length} key={emailAddresses.length}
value={""} value={""}
@ -192,23 +188,23 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent<
label={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")} label={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
placeholder={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")} placeholder={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
/> />
); ));
let peopleIntro = null; let peopleIntro = null;
let people = []; const people = [];
if (this.state.showPeople) { if (this.state.showPeople) {
const humansToPresent = this.state.people.slice(0, this.state.numPeople); const humansToPresent = this.state.people.slice(0, this.state.numPeople);
humansToPresent.forEach((person, i) => { humansToPresent.forEach((person, i) => {
people.push(this.renderPerson(person, i)); people.push(this.renderPerson(person, i));
}); });
if (humansToPresent.length < this.state.people.length) { if (humansToPresent.length < this.state.people.length) {
people.push( people.push((
<AccessibleButton <AccessibleButton
onClick={this.onShowMorePeople} onClick={this.onShowMorePeople}
kind="link" key="more" kind="link" key="more"
className="mx_CommunityPrototypeInviteDialog_morePeople" className="mx_CommunityPrototypeInviteDialog_morePeople"
>{_t("Show more")}</AccessibleButton> >{_t("Show more")}</AccessibleButton>
); ));
} }
} }
if (this.state.people.length > 0) { if (this.state.people.length > 0) {

View file

@ -163,8 +163,9 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
</span> </span>
); );
if (this.state.error) { if (this.state.error) {
const classes = "mx_CreateCommunityPrototypeDialog_subtext mx_CreateCommunityPrototypeDialog_subtext_error";
helpText = ( helpText = (
<span className="mx_CreateCommunityPrototypeDialog_subtext mx_CreateCommunityPrototypeDialog_subtext_error"> <span className={classes}>
{this.state.error} {this.state.error}
</span> </span>
); );
@ -205,7 +206,10 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
ref={this.avatarUploadRef} accept="image/*" ref={this.avatarUploadRef} accept="image/*"
onChange={this.onAvatarChanged} onChange={this.onAvatarChanged}
/> />
<AccessibleButton onClick={this.onChangeAvatar} className="mx_CreateCommunityPrototypeDialog_avatarContainer"> <AccessibleButton
onClick={this.onChangeAvatar}
className="mx_CreateCommunityPrototypeDialog_avatarContainer"
>
{preview} {preview}
</AccessibleButton> </AccessibleButton>
<div className="mx_CreateCommunityPrototypeDialog_tip"> <div className="mx_CreateCommunityPrototypeDialog_tip">

View file

@ -186,8 +186,8 @@ export default class ShareDialog extends React.PureComponent<IProps, IState> {
title = _t('Share Room Message'); title = _t('Share Room Message');
checkbox = <div> checkbox = <div>
<StyledCheckbox <StyledCheckbox
checked={this.state.linkSpecificEvent} checked={this.state.linkSpecificEvent}
onClick={this.onLinkSpecificEventCheckboxClick} onClick={this.onLinkSpecificEventCheckboxClick}
> >
{ _t('Link to selected message') } { _t('Link to selected message') }
</StyledCheckbox> </StyledCheckbox>
@ -198,16 +198,18 @@ export default class ShareDialog extends React.PureComponent<IProps, IState> {
const encodedUrl = encodeURIComponent(matrixToUrl); const encodedUrl = encodeURIComponent(matrixToUrl);
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
return <BaseDialog title={title} return <BaseDialog
className='mx_ShareDialog' title={title}
contentId='mx_Dialog_content' className='mx_ShareDialog'
onFinished={this.props.onFinished} contentId='mx_Dialog_content'
onFinished={this.props.onFinished}
> >
<div className="mx_ShareDialog_content"> <div className="mx_ShareDialog_content">
<div className="mx_ShareDialog_matrixto"> <div className="mx_ShareDialog_matrixto">
<a href={matrixToUrl} <a
onClick={ShareDialog.onLinkClick} href={matrixToUrl}
className="mx_ShareDialog_matrixto_link" onClick={ShareDialog.onLinkClick}
className="mx_ShareDialog_matrixto_link"
> >
{ matrixToUrl } { matrixToUrl }
</a> </a>

View file

@ -34,7 +34,6 @@ export interface ILocationState {
} }
export default class Draggable extends React.Component<IProps, IState> { export default class Draggable extends React.Component<IProps, IState> {
constructor(props: IProps) { constructor(props: IProps) {
super(props); super(props);
@ -77,5 +76,4 @@ export default class Draggable extends React.Component<IProps, IState> {
render() { render() {
return <div className={this.props.className} onMouseDown={this.onMouseDown.bind(this)} />; return <div className={this.props.className} onMouseDown={this.onMouseDown.bind(this)} />;
} }
} }

View file

@ -39,11 +39,13 @@ interface IProps {
className: string; className: string;
} }
/* eslint-disable camelcase */
interface IState { interface IState {
userId: string; userId: string;
displayname: string; displayname: string;
avatar_url: string; avatar_url: string;
} }
/* eslint-enable camelcase */
const AVATAR_SIZE = 32; const AVATAR_SIZE = 32;
@ -63,19 +65,18 @@ export default class EventTilePreview extends React.Component<IProps, IState> {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
const userId = client.getUserId(); const userId = client.getUserId();
const profileInfo = await client.getProfileInfo(userId); const profileInfo = await client.getProfileInfo(userId);
const avatar_url = Avatar.avatarUrlForUser( const avatarUrl = Avatar.avatarUrlForUser(
{avatarUrl: profileInfo.avatar_url}, {avatarUrl: profileInfo.avatar_url},
AVATAR_SIZE, AVATAR_SIZE, "crop"); AVATAR_SIZE, AVATAR_SIZE, "crop");
this.setState({ this.setState({
userId, userId,
displayname: profileInfo.displayname, displayname: profileInfo.displayname,
avatar_url, avatar_url: avatarUrl,
}); });
} }
private fakeEvent({userId, displayname, avatar_url}: IState) { private fakeEvent({userId, displayname, avatar_url: avatarUrl}: IState) {
// Fake it till we make it // Fake it till we make it
const event = new MatrixEvent(JSON.parse(`{ const event = new MatrixEvent(JSON.parse(`{
"type": "m.room.message", "type": "m.room.message",
@ -85,12 +86,12 @@ export default class EventTilePreview extends React.Component<IProps, IState> {
"msgtype": "m.text", "msgtype": "m.text",
"body": "${this.props.message}", "body": "${this.props.message}",
"displayname": "${displayname}", "displayname": "${displayname}",
"avatar_url": "${avatar_url}" "avatar_url": "${avatarUrl}"
}, },
"msgtype": "m.text", "msgtype": "m.text",
"body": "${this.props.message}", "body": "${this.props.message}",
"displayname": "${displayname}", "displayname": "${displayname}",
"avatar_url": "${avatar_url}" "avatar_url": "${avatarUrl}"
}, },
"unsigned": { "unsigned": {
"age": 97 "age": 97
@ -104,7 +105,7 @@ export default class EventTilePreview extends React.Component<IProps, IState> {
name: displayname, name: displayname,
userId: userId, userId: userId,
getAvatarUrl: (..._) => { getAvatarUrl: (..._) => {
return avatar_url; return avatarUrl;
}, },
}; };
@ -114,13 +115,10 @@ export default class EventTilePreview extends React.Component<IProps, IState> {
public render() { public render() {
const event = this.fakeEvent(this.state); const event = this.fakeEvent(this.state);
let className = classnames( const className = classnames(this.props.className, {
this.props.className, "mx_IRCLayout": this.props.useIRCLayout,
{ "mx_GroupLayout": !this.props.useIRCLayout,
"mx_IRCLayout": this.props.useIRCLayout, });
"mx_GroupLayout": !this.props.useIRCLayout,
}
);
return <div className={className}> return <div className={className}>
<EventTile mxEvent={event} useIRCLayout={this.props.useIRCLayout} /> <EventTile mxEvent={event} useIRCLayout={this.props.useIRCLayout} />

View file

@ -198,11 +198,9 @@ export default class Field extends React.PureComponent<PropShapes, IState> {
} }
} }
public render() { public render() {
const { /* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */
element, prefixComponent, postfixComponent, className, onValidate, children, const { element, prefixComponent, postfixComponent, className, onValidate, children,
tooltipContent, forceValidity, tooltipClassName, list, ...inputProps} = this.props; tooltipContent, forceValidity, tooltipClassName, list, ...inputProps} = this.props;
// Set some defaults for the <input> element // Set some defaults for the <input> element

View file

@ -78,7 +78,12 @@ export default class IRCTimelineProfileResizer extends React.Component<IProps, I
private onMoueUp(event: MouseEvent) { private onMoueUp(event: MouseEvent) {
if (this.props.roomId) { if (this.props.roomId) {
SettingsStore.setValue("ircDisplayNameWidth", this.props.roomId, SettingLevel.ROOM_DEVICE, this.state.width); SettingsStore.setValue(
"ircDisplayNameWidth",
this.props.roomId,
SettingLevel.ROOM_DEVICE,
this.state.width,
);
} }
} }

View file

@ -18,7 +18,6 @@ limitations under the License.
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import AccessibleButton from "./AccessibleButton";
import Tooltip from './Tooltip'; import Tooltip from './Tooltip';
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";

View file

@ -41,7 +41,7 @@ const QRCode: React.FC<IProps> = ({data, className, ...options}) => {
return () => { return () => {
cancelled = true; cancelled = true;
}; };
}, [JSON.stringify(data), options]); }, [JSON.stringify(data), options]); // eslint-disable-line react-hooks/exhaustive-deps
return <div className={classNames("mx_QRCode", className)}> return <div className={classNames("mx_QRCode", className)}>
{ dataUri ? <img src={dataUri} className="mx_VerificationQRCode" alt={_t("QR Code")} /> : <Spinner /> } { dataUri ? <img src={dataUri} className="mx_VerificationQRCode" alt={_t("QR Code")} /> : <Spinner /> }

View file

@ -45,7 +45,7 @@ export default class Slider extends React.Component<IProps> {
// non linear slider. // non linear slider.
private offset(values: number[], value: number): number { private offset(values: number[], value: number): number {
// the index of the first number greater than value. // the index of the first number greater than value.
let closest = values.reduce((prev, curr) => { const closest = values.reduce((prev, curr) => {
return (value > curr ? prev + 1 : prev); return (value > curr ? prev + 1 : prev);
}, 0); }, 0);
@ -68,17 +68,16 @@ export default class Slider extends React.Component<IProps> {
const linearInterpolation = (value - closestLessValue) / (closestGreaterValue - closestLessValue); const linearInterpolation = (value - closestLessValue) / (closestGreaterValue - closestLessValue);
return 100 * (closest - 1 + linearInterpolation) * intervalWidth; return 100 * (closest - 1 + linearInterpolation) * intervalWidth;
} }
render(): React.ReactNode { render(): React.ReactNode {
const dots = this.props.values.map(v => const dots = this.props.values.map(v => <Dot
<Dot active={v <= this.props.value} active={v <= this.props.value}
label={this.props.displayFunc(v)} label={this.props.displayFunc(v)}
onClick={this.props.disabled ? () => {} : () => this.props.onSelectionChange(v)} onClick={this.props.disabled ? () => {} : () => this.props.onSelectionChange(v)}
key={v} key={v}
disabled={this.props.disabled} disabled={this.props.disabled}
/>); />);
let selection = null; let selection = null;
@ -93,7 +92,7 @@ export default class Slider extends React.Component<IProps> {
return <div className="mx_Slider"> return <div className="mx_Slider">
<div> <div>
<div className="mx_Slider_bar"> <div className="mx_Slider_bar">
<hr onClick={this.props.disabled ? () => {} : this.onClick.bind(this)}/> <hr onClick={this.props.disabled ? () => {} : this.onClick.bind(this)} />
{ selection } { selection }
</div> </div>
<div className="mx_Slider_dotContainer"> <div className="mx_Slider_dotContainer">

View file

@ -17,8 +17,6 @@ limitations under the License.
import React from "react"; import React from "react";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { randomString } from "matrix-js-sdk/src/randomstring";
const CHECK_BOX_SVG = require("../../../../res/img/feather-customised/check.svg");
interface IProps extends React.InputHTMLAttributes<HTMLInputElement> { interface IProps extends React.InputHTMLAttributes<HTMLInputElement> {
} }
@ -39,13 +37,14 @@ export default class StyledCheckbox extends React.PureComponent<IProps, IState>
} }
public render() { public render() {
/* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */
const { children, className, ...otherProps } = this.props; const { children, className, ...otherProps } = this.props;
return <span className={"mx_Checkbox " + className}> return <span className={"mx_Checkbox " + className}>
<input id={this.id} {...otherProps} type="checkbox" /> <input id={this.id} {...otherProps} type="checkbox" />
<label htmlFor={this.id}> <label htmlFor={this.id}>
{/* Using the div to center the image */} {/* Using the div to center the image */}
<div className="mx_Checkbox_background"> <div className="mx_Checkbox_background">
<img src={CHECK_BOX_SVG}/> <img src={require("../../../../res/img/feather-customised/check.svg")} />
</div> </div>
<div> <div>
{ this.props.children } { this.props.children }

View file

@ -76,14 +76,16 @@ const EncryptionInfo: React.FC<IProps> = ({
description = ( description = (
<div> <div>
<p>{_t("Messages in this room are end-to-end encrypted.")}</p> <p>{_t("Messages in this room are end-to-end encrypted.")}</p>
<p>{_t("Your messages are secured and only you and the recipient have the unique keys to unlock them.")}</p> <p>{_t("Your messages are secured and only you and the recipient have " +
"the unique keys to unlock them.")}</p>
</div> </div>
); );
} else { } else {
description = ( description = (
<div> <div>
<p>{_t("Messages in this room are not end-to-end encrypted.")}</p> <p>{_t("Messages in this room are not end-to-end encrypted.")}</p>
<p>{_t("In encrypted rooms, your messages are secured and only you and the recipient have the unique keys to unlock them.")}</p> <p>{_t("In encrypted rooms, your messages are secured and only you and the recipient have " +
"the unique keys to unlock them.")}</p>
</div> </div>
); );
} }

View file

@ -23,7 +23,10 @@ import dis from '../../../dispatcher/dispatcher';
import RightPanelStore from "../../../stores/RightPanelStore"; import RightPanelStore from "../../../stores/RightPanelStore";
import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; import {RightPanelPhases} from "../../../stores/RightPanelStorePhases";
import {Action} from '../../../dispatcher/actions'; import {Action} from '../../../dispatcher/actions';
import {SetRightPanelPhasePayload, SetRightPanelPhaseRefireParams} from '../../../dispatcher/payloads/SetRightPanelPhasePayload'; import {
SetRightPanelPhasePayload,
SetRightPanelPhaseRefireParams,
} from '../../../dispatcher/payloads/SetRightPanelPhasePayload';
import {EventSubscription} from "fbemitter"; import {EventSubscription} from "fbemitter";
export enum HeaderKind { export enum HeaderKind {
@ -38,7 +41,7 @@ interface IState {
interface IProps {} interface IProps {}
export default class HeaderButtons extends React.Component<IProps, IState> { export default abstract class HeaderButtons extends React.Component<IProps, IState> {
private storeToken: EventSubscription; private storeToken: EventSubscription;
private dispatcherRef: string; private dispatcherRef: string;
@ -92,14 +95,7 @@ export default class HeaderButtons extends React.Component<IProps, IState> {
} }
// XXX: Make renderButtons a prop // XXX: Make renderButtons a prop
public renderButtons(): JSX.Element[] { public abstract renderButtons(): JSX.Element[];
// Ignore - intended to be overridden by subclasses
// Return empty fragment to satisfy the type
return [
<React.Fragment>
</React.Fragment>
];
}
public render() { public render() {
// inline style as this will be swapped around in future commits // inline style as this will be swapped around in future commits

View file

@ -30,8 +30,6 @@ import {_t} from "../../../languageHandler";
import SdkConfig from "../../../SdkConfig"; import SdkConfig from "../../../SdkConfig";
import E2EIcon from "../rooms/E2EIcon"; import E2EIcon from "../rooms/E2EIcon";
import { import {
PHASE_UNSENT,
PHASE_REQUESTED,
PHASE_READY, PHASE_READY,
PHASE_DONE, PHASE_DONE,
PHASE_STARTED, PHASE_STARTED,
@ -104,14 +102,15 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
</div>; </div>;
} }
if (showSAS) { if (showSAS) {
sasBlockDialog = sasBlockDialog = <div className='mx_VerificationPanel_QRPhase_startOption'>
<div className='mx_VerificationPanel_QRPhase_startOption'> <p>{_t("Compare unique emoji")}</p>
<p>{_t("Compare unique emoji")}</p> <span className='mx_VerificationPanel_QRPhase_helpText'>
<span className='mx_VerificationPanel_QRPhase_helpText'>{_t("Compare a unique set of emoji if you don't have a camera on either device")}</span> {_t("Compare a unique set of emoji if you don't have a camera on either device")}
<AccessibleButton disabled={this.state.emojiButtonClicked} onClick={this.startSAS} kind='primary'> </span>
{_t("Start")} <AccessibleButton disabled={this.state.emojiButtonClicked} onClick={this.startSAS} kind='primary'>
</AccessibleButton> {_t("Start")}
</div>; </AccessibleButton>
</div>;
} }
const or = qrBlockDialog && sasBlockDialog ? const or = qrBlockDialog && sasBlockDialog ?
<div className='mx_VerificationPanel_QRPhase_betweenText'>{_t("or")}</div> : null; <div className='mx_VerificationPanel_QRPhase_betweenText'>{_t("or")}</div> : null;
@ -165,8 +164,8 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
} }
const noCommonMethodBlock = noCommonMethodError ? const noCommonMethodBlock = noCommonMethodError ?
<div className="mx_UserInfo_container">{noCommonMethodError}</div> : <div className="mx_UserInfo_container">{noCommonMethodError}</div> :
null; null;
// TODO: add way to open camera to scan a QR code // TODO: add way to open camera to scan a QR code
return <React.Fragment> return <React.Fragment>

View file

@ -92,6 +92,7 @@ export default class NotificationBadge extends React.PureComponent<XOR<IProps, I
}; };
public render(): React.ReactElement { public render(): React.ReactElement {
/* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */
const {notification, forceCount, roomId, onClick, ...props} = this.props; const {notification, forceCount, roomId, onClick, ...props} = this.props;
// Don't show a badge if we don't need to // Don't show a badge if we don't need to

View file

@ -218,7 +218,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
private getRoomDelta = (roomId: string, delta: number, unread = false) => { private getRoomDelta = (roomId: string, delta: number, unread = false) => {
const lists = RoomListStore.instance.orderedLists; const lists = RoomListStore.instance.orderedLists;
let rooms: Room = []; const rooms: Room = [];
TAG_ORDER.forEach(t => { TAG_ORDER.forEach(t => {
let listRooms = lists[t]; let listRooms = lists[t];
@ -290,7 +290,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
// TODO: Put community invites in a more sensible place (not in the room list) // TODO: Put community invites in a more sensible place (not in the room list)
// See https://github.com/vector-im/element-web/issues/14456 // See https://github.com/vector-im/element-web/issues/14456
return MatrixClientPeg.get().getGroups().filter(g => { return MatrixClientPeg.get().getGroups().filter(g => {
return g.myMembership === 'invite'; return g.myMembership === 'invite';
}).map(g => { }).map(g => {
const avatar = ( const avatar = (
<GroupAvatar <GroupAvatar
@ -346,21 +346,19 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
: TAG_AESTHETICS[orderedTagId]; : TAG_AESTHETICS[orderedTagId];
if (!aesthetics) throw new Error(`Tag ${orderedTagId} does not have aesthetics`); if (!aesthetics) throw new Error(`Tag ${orderedTagId} does not have aesthetics`);
components.push( components.push(<RoomSublist
<RoomSublist key={`sublist-${orderedTagId}`}
key={`sublist-${orderedTagId}`} tagId={orderedTagId}
tagId={orderedTagId} forRooms={true}
forRooms={true} startAsHidden={aesthetics.defaultHidden}
startAsHidden={aesthetics.defaultHidden} label={aesthetics.sectionLabelRaw ? aesthetics.sectionLabelRaw : _t(aesthetics.sectionLabel)}
label={aesthetics.sectionLabelRaw ? aesthetics.sectionLabelRaw : _t(aesthetics.sectionLabel)} onAddRoom={aesthetics.onAddRoom}
onAddRoom={aesthetics.onAddRoom} addRoomLabel={aesthetics.addRoomLabel ? _t(aesthetics.addRoomLabel) : aesthetics.addRoomLabel}
addRoomLabel={aesthetics.addRoomLabel ? _t(aesthetics.addRoomLabel) : aesthetics.addRoomLabel} addRoomContextMenu={aesthetics.addRoomContextMenu}
addRoomContextMenu={aesthetics.addRoomContextMenu} isMinimized={this.props.isMinimized}
isMinimized={this.props.isMinimized} onResize={this.props.onResize}
onResize={this.props.onResize} extraBadTilesThatShouldntExist={extraTiles}
extraBadTilesThatShouldntExist={extraTiles} />);
/>
);
} }
return components; return components;

View file

@ -517,15 +517,13 @@ export default class RoomSublist extends React.Component<IProps, IState> {
if (this.state.rooms) { if (this.state.rooms) {
const visibleRooms = this.state.rooms.slice(0, this.numVisibleTiles); const visibleRooms = this.state.rooms.slice(0, this.numVisibleTiles);
for (const room of visibleRooms) { for (const room of visibleRooms) {
tiles.push( tiles.push(<RoomTile
<RoomTile room={room}
room={room} key={`room-${room.roomId}`}
key={`room-${room.roomId}`} showMessagePreview={this.layout.showPreviews}
showMessagePreview={this.layout.showPreviews} isMinimized={this.props.isMinimized}
isMinimized={this.props.isMinimized} tag={this.props.tagId}
tag={this.props.tagId} />);
/>
);
} }
} }
@ -710,7 +708,12 @@ export default class RoomSublist extends React.Component<IProps, IState> {
// doesn't become sticky. // doesn't become sticky.
// The same applies to the notification badge. // The same applies to the notification badge.
return ( return (
<div className={classes} onKeyDown={this.onHeaderKeyDown} onFocus={onFocus} aria-label={this.props.label}> <div
className={classes}
onKeyDown={this.onHeaderKeyDown}
onFocus={onFocus}
aria-label={this.props.label}
>
<div className="mx_RoomSublist_stickable"> <div className="mx_RoomSublist_stickable">
<Button <Button
onFocus={onFocus} onFocus={onFocus}
@ -762,7 +765,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
const showMoreAtMinHeight = minTiles < this.numTiles; const showMoreAtMinHeight = minTiles < this.numTiles;
const minHeightPadding = RESIZE_HANDLE_HEIGHT + (showMoreAtMinHeight ? SHOW_N_BUTTON_HEIGHT : 0); const minHeightPadding = RESIZE_HANDLE_HEIGHT + (showMoreAtMinHeight ? SHOW_N_BUTTON_HEIGHT : 0);
const minTilesPx = layout.tilesToPixelsWithPadding(minTiles, minHeightPadding); const minTilesPx = layout.tilesToPixelsWithPadding(minTiles, minHeightPadding);
let maxTilesPx = layout.tilesToPixelsWithPadding(this.numTiles, this.padding); const maxTilesPx = layout.tilesToPixelsWithPadding(this.numTiles, this.padding);
const showMoreBtnClasses = classNames({ const showMoreBtnClasses = classNames({
'mx_RoomSublist_showNButton': true, 'mx_RoomSublist_showNButton': true,
}); });

View file

@ -31,7 +31,7 @@ import { ChevronFace, ContextMenuTooltipButton } from "../../structures/ContextM
import { DefaultTagID, TagID } from "../../../stores/room-list/models"; import { DefaultTagID, TagID } from "../../../stores/room-list/models";
import { MessagePreviewStore, ROOM_PREVIEW_CHANGED } from "../../../stores/room-list/MessagePreviewStore"; import { MessagePreviewStore, ROOM_PREVIEW_CHANGED } from "../../../stores/room-list/MessagePreviewStore";
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar"; import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
import { ALL_MESSAGES, ALL_MESSAGES_LOUD, MENTIONS_ONLY, MUTE, } from "../../../RoomNotifs"; import { ALL_MESSAGES, ALL_MESSAGES_LOUD, MENTIONS_ONLY, MUTE } from "../../../RoomNotifs";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import NotificationBadge from "./NotificationBadge"; import NotificationBadge from "./NotificationBadge";
import { Volume } from "../../../RoomNotifsTypes"; import { Volume } from "../../../RoomNotifsTypes";
@ -48,7 +48,7 @@ import IconizedContextMenu, {
IconizedContextMenuCheckbox, IconizedContextMenuCheckbox,
IconizedContextMenuOption, IconizedContextMenuOption,
IconizedContextMenuOptionList, IconizedContextMenuOptionList,
IconizedContextMenuRadio IconizedContextMenuRadio,
} from "../context_menus/IconizedContextMenu"; } from "../context_menus/IconizedContextMenu";
import { CommunityPrototypeStore, IRoomProfile } from "../../../stores/CommunityPrototypeStore"; import { CommunityPrototypeStore, IRoomProfile } from "../../../stores/CommunityPrototypeStore";
import { UPDATE_EVENT } from "../../../stores/AsyncStore"; import { UPDATE_EVENT } from "../../../stores/AsyncStore";
@ -249,7 +249,7 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
removeTag, removeTag,
addTag, addTag,
undefined, undefined,
0 0,
)); ));
} else { } else {
console.warn(`Unexpected tag ${tagId} applied to ${this.props.room.room_id}`); console.warn(`Unexpected tag ${tagId} applied to ${this.props.room.room_id}`);

View file

@ -19,9 +19,7 @@ import classNames from "classnames";
import { import {
RovingAccessibleButton, RovingAccessibleButton,
RovingAccessibleTooltipButton, RovingAccessibleTooltipButton,
RovingTabIndexWrapper
} from "../../../accessibility/RovingTabIndex"; } from "../../../accessibility/RovingTabIndex";
import AccessibleButton from "../../views/elements/AccessibleButton";
import NotificationBadge from "./NotificationBadge"; import NotificationBadge from "./NotificationBadge";
import { NotificationState } from "../../../stores/notifications/NotificationState"; import { NotificationState } from "../../../stores/notifications/NotificationState";

View file

@ -42,7 +42,7 @@ function getStatusText(status: UpdateCheckStatus, errorDetail?: string) {
return _t('Downloading update...'); return _t('Downloading update...');
case UpdateCheckStatus.Ready: case UpdateCheckStatus.Ready:
return _t("New version available. <a>Update now.</a>", {}, { return _t("New version available. <a>Update now.</a>", {}, {
a: sub => <AccessibleButton kind="link" onClick={installUpdate}>{sub}</AccessibleButton> a: sub => <AccessibleButton kind="link" onClick={installUpdate}>{sub}</AccessibleButton>,
}); });
} }
} }

View file

@ -170,7 +170,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
"baseFontSize", "baseFontSize",
null, null,
SettingLevel.DEVICE, SettingLevel.DEVICE,
parseInt(value, 10) - FontWatcher.SIZE_DIFF parseInt(value, 10) - FontWatcher.SIZE_DIFF,
); );
return {valid: true, feedback: _t('Use between %(min)s pt and %(max)s pt', {min, max})}; return {valid: true, feedback: _t('Use between %(min)s pt and %(max)s pt', {min, max})};
@ -294,7 +294,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
/> />
</div> </div>
{customThemeForm} {customThemeForm}
</div> </div>
); );
} }

View file

@ -29,7 +29,15 @@ interface IProps extends IGenericToastProps {
const SECOND = 1000; const SECOND = 1000;
const GenericExpiringToast: React.FC<IProps> = ({description, acceptLabel, dismissLabel, onAccept, onDismiss, toastKey, numSeconds}) => { const GenericExpiringToast: React.FC<IProps> = ({
description,
acceptLabel,
dismissLabel,
onAccept,
onDismiss,
toastKey,
numSeconds,
}) => {
const onReject = () => { const onReject = () => {
if (onDismiss) onDismiss(); if (onDismiss) onDismiss();
ToastStore.sharedInstance().dismissToast(toastKey); ToastStore.sharedInstance().dismissToast(toastKey);

View file

@ -31,7 +31,13 @@ interface IPropsExtended extends IProps {
onReject(); onReject();
} }
const GenericToast: React.FC<XOR<IPropsExtended, IProps>> = ({description, acceptLabel, rejectLabel, onAccept, onReject}) => { const GenericToast: React.FC<XOR<IPropsExtended, IProps>> = ({
description,
acceptLabel,
rejectLabel,
onAccept,
onReject,
}) => {
return <div> return <div>
<div className="mx_Toast_description"> <div className="mx_Toast_description">
{ description } { description }

View file

@ -97,10 +97,7 @@ export default class CallView extends React.Component<IProps, IState> {
if (this.props.room) { if (this.props.room) {
const roomId = this.props.room.roomId; const roomId = this.props.room.roomId;
call = CallHandler.getCallForRoom(roomId) || call = CallHandler.getCallForRoom(roomId) ||
(this.props.ConferenceHandler ? (this.props.ConferenceHandler ? this.props.ConferenceHandler.getConferenceCallForRoom(roomId) : null);
this.props.ConferenceHandler.getConferenceCallForRoom(roomId) :
null
);
if (this.call) { if (this.call) {
this.setState({ call: call }); this.setState({ call: call });

View file

@ -51,7 +51,7 @@ export default class IncomingCallBox extends React.Component<IProps, IState> {
private onAction = (payload: ActionPayload) => { private onAction = (payload: ActionPayload) => {
switch (payload.action) { switch (payload.action) {
case 'call_state': case 'call_state': {
const call = CallHandler.getCall(payload.room_id); const call = CallHandler.getCall(payload.room_id);
if (call && call.call_state === 'ringing') { if (call && call.call_state === 'ringing') {
this.setState({ this.setState({
@ -62,6 +62,7 @@ export default class IncomingCallBox extends React.Component<IProps, IState> {
incomingCall: null, incomingCall: null,
}); });
} }
}
} }
}; };

View file

@ -442,7 +442,7 @@ export function pickBestLanguage(langs: string[]): string {
} }
function getLangsJson(): Promise<object> { function getLangsJson(): Promise<object> {
return new Promise(async (resolve, reject) => { return new Promise((resolve, reject) => {
let url; let url;
if (typeof(webpackLangJsonUrl) === 'string') { // in Jest this 'url' isn't a URL, so just fall through if (typeof(webpackLangJsonUrl) === 'string') { // in Jest this 'url' isn't a URL, so just fall through
url = webpackLangJsonUrl; url = webpackLangJsonUrl;
@ -453,7 +453,7 @@ function getLangsJson(): Promise<object> {
{ method: "GET", url }, { method: "GET", url },
(err, response, body) => { (err, response, body) => {
if (err || response.status < 200 || response.status >= 300) { if (err || response.status < 200 || response.status >= 300) {
reject({err: err, response: response}); reject(err);
return; return;
} }
resolve(JSON.parse(body)); resolve(JSON.parse(body));
@ -488,7 +488,7 @@ function getLanguage(langPath: string): object {
{ method: "GET", url: langPath }, { method: "GET", url: langPath },
(err, response, body) => { (err, response, body) => {
if (err || response.status < 200 || response.status >= 300) { if (err || response.status < 200 || response.status >= 300) {
reject({err: err, response: response}); reject(err);
return; return;
} }
resolve(weblateToCounterpart(JSON.parse(body))); resolve(weblateToCounterpart(JSON.parse(body)));