From afa6f377ea785f7532c59285e61e1f18c2869841 Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Tue, 4 Feb 2025 07:14:36 +0100 Subject: [PATCH 1/5] [create-pull-request] automated change (#29165) Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com> --- playwright/testcontainers/synapse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playwright/testcontainers/synapse.ts b/playwright/testcontainers/synapse.ts index fcd9a995e7..a0aa8d7991 100644 --- a/playwright/testcontainers/synapse.ts +++ b/playwright/testcontainers/synapse.ts @@ -19,7 +19,7 @@ import { HomeserverContainer, StartedHomeserverContainer } from "./HomeserverCon import { StartedMatrixAuthenticationServiceContainer } from "./mas.ts"; import { Api, ClientServerApi, Verb } from "../plugins/utils/api.ts"; -const TAG = "develop@sha256:e6b4c69101a0d8fd6ff6a26233eb6f92e984d578476f087c26a0fb72cddc9623"; +const TAG = "develop@sha256:098126c6be750dffaff5bd19db254609aadaf34f76c70f2dca9821cb12428613"; const DEFAULT_CONFIG = { server_name: "localhost", From 1ea1d386abb8749351facd81d7a977cd4a39d765 Mon Sep 17 00:00:00 2001 From: R Midhun Suresh Date: Tue, 4 Feb 2025 14:35:48 +0530 Subject: [PATCH 2/5] Make profile header section match the designs (#29163) * Update styling to match design * Fix tests --- .../user-view.spec.ts/user-info-linux.png | Bin 20997 -> 20963 bytes res/css/views/right_panel/_UserInfo.pcss | 53 +++++++++++++++++- src/components/views/right_panel/UserInfo.tsx | 15 +++-- .../__snapshots__/UserInfo-test.tsx.snap | 8 +-- 4 files changed, 63 insertions(+), 13 deletions(-) diff --git a/playwright/snapshots/user-view/user-view.spec.ts/user-info-linux.png b/playwright/snapshots/user-view/user-view.spec.ts/user-info-linux.png index 30206f1a255fe4bc43a433cce5fb69c2b5045090..4e305879350fc9f5c09a5386ef424f204cd2174a 100644 GIT binary patch delta 19014 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 Jefs9Z{{YpiHuC@g delta 19115 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 RzUK}Fx@m4}M!R-D`oAtYwaEYg diff --git a/res/css/views/right_panel/_UserInfo.pcss b/res/css/views/right_panel/_UserInfo.pcss index 0af5585d1a..7a67986ae8 100644 --- a/res/css/views/right_panel/_UserInfo.pcss +++ b/res/css/views/right_panel/_UserInfo.pcss @@ -34,7 +34,7 @@ Please see LICENSE files in the repository root for full details. } .mx_UserInfo_container { - padding: var(--cpd-space-4x) 0; + padding: var(--cpd-space-2x) 0 var(--cpd-space-4x); margin: 0 var(--cpd-space-4x); .mx_UserInfo_container_verifyButton { @@ -65,7 +65,7 @@ Please see LICENSE files in the repository root for full details. } .mx_UserInfo_avatar { - margin: $spacing-24 $spacing-32 0 $spacing-32; + margin: var(--cpd-space-12x) var(--cpd-space-4x) 0 var(--cpd-space-4x); .mx_UserInfo_avatar_transition { max-width: 120px; @@ -98,8 +98,18 @@ Please see LICENSE files in the repository root for full details. margin: 5px 0; } + .mx_UserInfo_header { + margin-bottom: var(--cpd-space-8x); + padding-bottom: 0; + } + .mx_UserInfo_profile { + display: flex; + flex-direction: column; + gap: var(--cpd-space-1x); + h1 { + margin: 0; font-size: $font-20px; line-height: $font-25px; @@ -119,8 +129,45 @@ Please see LICENSE files in the repository root for full details. } } + .mx_UserInfo_profile_name { + height: 30px; + } + + .mx_UserInfo_profile_mxid { + color: var(--cpd-color-text-secondary); + height: 28px; + } + .mx_UserInfo_profileStatus { - margin: var(--cpd-space-1x) 0; + height: 20px; + } + + .mx_UserInfo_timezone { + height: 20px; + margin: 0; + display: flex; + align-items: center; + } + + /** Overrides for the copy to clipboard button **/ + .mx_CopyableText { + align-items: center; + } + + .mx_CopyableText_copyButton { + width: 28px; + height: 28px; + display: flex; + justify-content: center; + align-items: center; + position: unset; + padding-left: var(--cpd-space-2x); + } + + .mx_CopyableText_copyButton::before { + width: 20px; + height: 20px; + background-color: var(--cpd-color-icon-secondary-alpha); } } diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 4e8968afaa..3be3725576 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -85,6 +85,7 @@ import { asyncSome } from "../../../utils/arrays"; import { Flex } from "../../utils/Flex"; import CopyableText from "../elements/CopyableText"; import { useUserTimezone } from "../../../hooks/useUserTimezone"; + export interface IDevice extends Device { ambiguous?: boolean; } @@ -580,8 +581,10 @@ export const warnSelfDemote = async (isSpace: boolean): Promise => { const Container: React.FC<{ children: ReactNode; -}> = ({ children }) => { - return
{children}
; + className?: string; +}> = ({ children, className }) => { + const classes = classNames("mx_UserInfo_container", className); + return
{children}
; }; interface IPowerLevelsContent { @@ -1707,10 +1710,10 @@ export const UserInfoHeader: React.FC<{ - + - + {displayName} {e2eIcon} @@ -1718,11 +1721,11 @@ export const UserInfoHeader: React.FC<{ {presenceLabel} {timezoneInfo && ( - + {timezoneInfo?.friendly ?? ""} - + )} diff --git a/test/unit-tests/components/views/right_panel/__snapshots__/UserInfo-test.tsx.snap b/test/unit-tests/components/views/right_panel/__snapshots__/UserInfo-test.tsx.snap index 1744081389..5ba2d3b5fc 100644 --- a/test/unit-tests/components/views/right_panel/__snapshots__/UserInfo-test.tsx.snap +++ b/test/unit-tests/components/views/right_panel/__snapshots__/UserInfo-test.tsx.snap @@ -142,7 +142,7 @@ exports[` with crypto enabled renders 1`] = `
with crypto enabled renders 1`] = ` dir="auto" >
@user:example.com @@ -456,7 +456,7 @@ exports[` with crypto enabled should render a deactivate button for
with crypto enabled should render a deactivate button for dir="auto" >
@user:example.com From 8cae1e9f5e85692862296ae14f8218b7638fdc91 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 4 Feb 2025 12:18:54 +0000 Subject: [PATCH 3/5] Improve rendering of empty topics in the timeline (#29152) * Improve display of empty topic events in the timeline. * Use topic parser for topic events. * Revert changes i18n for the moment * Use the correct import pattern * Add tests for topic rendering --- src/TextForEvent.tsx | 14 ++++-- .../room_settings/RoomProfileSettings.tsx | 6 ++- src/i18n/strings/en_EN.json | 5 ++- test/unit-tests/TextForEvent-test.ts | 44 +++++++++++++++++++ 4 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/TextForEvent.tsx b/src/TextForEvent.tsx index bdb7e8cbe0..5b34fe83b2 100644 --- a/src/TextForEvent.tsx +++ b/src/TextForEvent.tsx @@ -17,6 +17,7 @@ import { MsgType, M_POLL_START, M_POLL_END, + ContentHelpers, } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; import { logger } from "matrix-js-sdk/src/logger"; @@ -227,11 +228,16 @@ function textForMemberEvent( function textForTopicEvent(ev: MatrixEvent): (() => string) | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); + const topic = ContentHelpers.parseTopicContent(ev.getContent()).text; return () => - _t("timeline|m.room.topic", { - senderDisplayName, - topic: ev.getContent().topic, - }); + topic + ? _t("timeline|m.room.topic|changed", { + senderDisplayName, + topic, + }) + : _t("timeline|m.room.topic|removed", { + senderDisplayName, + }); } function textForRoomAvatarEvent(ev: MatrixEvent): (() => string) | null { diff --git a/src/components/views/room_settings/RoomProfileSettings.tsx b/src/components/views/room_settings/RoomProfileSettings.tsx index 8789ea48fc..15ed6f461c 100644 --- a/src/components/views/room_settings/RoomProfileSettings.tsx +++ b/src/components/views/room_settings/RoomProfileSettings.tsx @@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details. import React, { createRef } from "react"; import classNames from "classnames"; -import { EventType } from "matrix-js-sdk/src/matrix"; +import { ContentHelpers, EventType } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../languageHandler"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; @@ -51,7 +51,7 @@ export default class RoomProfileSettings extends React.Component const avatarUrl = avatarEvent?.getContent()["url"] ?? null; const topicEvent = room.currentState.getStateEvents(EventType.RoomTopic, ""); - const topic = topicEvent && topicEvent.getContent() ? topicEvent.getContent()["topic"] : ""; + const topic = (topicEvent && ContentHelpers.parseTopicContent(topicEvent.getContent()).text) || ""; const nameEvent = room.currentState.getStateEvents(EventType.RoomName, ""); const name = nameEvent && nameEvent.getContent() ? nameEvent.getContent()["name"] : ""; @@ -145,6 +145,8 @@ export default class RoomProfileSettings extends React.Component if (this.state.originalTopic !== this.state.topic) { const html = htmlSerializeFromMdIfNeeded(this.state.topic, { forceHTML: false }); + // XXX: Note that we deliberately send an empty string on an empty topic rather + // than a clearer `undefined` value. Synapse still requires a string in a topic. await client.setRoomTopic(this.props.roomId, this.state.topic, html); newState.originalTopic = this.state.topic; } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 7e28469362..4ba1444c41 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -3493,7 +3493,10 @@ "sent": "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room." }, "m.room.tombstone": "%(senderDisplayName)s upgraded this room.", - "m.room.topic": "%(senderDisplayName)s changed the topic to \"%(topic)s\".", + "m.room.topic": { + "changed": "%(senderDisplayName)s changed the topic to \"%(topic)s\".", + "removed": "%(senderDisplayName)s removed the topic." + }, "m.sticker": "%(senderDisplayName)s sent a sticker.", "m.video": { "error_decrypting": "Error decrypting video" diff --git a/test/unit-tests/TextForEvent-test.ts b/test/unit-tests/TextForEvent-test.ts index 4dfccbb93e..17437de894 100644 --- a/test/unit-tests/TextForEvent-test.ts +++ b/test/unit-tests/TextForEvent-test.ts @@ -12,6 +12,7 @@ import { JoinRule, MatrixClient, MatrixEvent, + MRoomTopicEventContent, Room, RoomMember, } from "matrix-js-sdk/src/matrix"; @@ -613,4 +614,47 @@ describe("TextForEvent", () => { }, ); }); + + describe("textForTopicEvent()", () => { + type TestCase = [string, MRoomTopicEventContent, { result: string }]; + const testCases: TestCase[] = [ + ["the legacy key", { topic: "My topic" }, { result: '@a changed the topic to "My topic".' }], + [ + "the legacy key with an empty m.topic key", + { "topic": "My topic", "m.topic": [] }, + { result: '@a changed the topic to "My topic".' }, + ], + [ + "the m.topic key", + { "topic": "Ignore this", "m.topic": [{ mimetype: "text/plain", body: "My topic" }] }, + { result: '@a changed the topic to "My topic".' }, + ], + [ + "the m.topic key and the legacy key undefined", + { "topic": undefined, "m.topic": [{ mimetype: "text/plain", body: "My topic" }] }, + { result: '@a changed the topic to "My topic".' }, + ], + ["the legacy key undefined", { topic: undefined }, { result: "@a removed the topic." }], + ["the legacy key empty string", { topic: "" }, { result: "@a removed the topic." }], + [ + "both the legacy and new keys removed", + { "topic": undefined, "m.topic": [] }, + { result: "@a removed the topic." }, + ], + ]; + + it.each(testCases)("returns correct message for topic event with %s", (_caseName, content, { result }) => { + expect( + textForEvent( + new MatrixEvent({ + type: "m.room.topic", + sender: "@a", + content: content, + state_key: "", + }), + mockClient, + ), + ).toEqual(result); + }); + }); }); From 7eb969bbc2f5aaf39705489d0a3e30c66e1fb999 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Feb 2025 13:41:34 +0000 Subject: [PATCH 4/5] Apply lint rule @typescript-eslint/no-empty-object-type (#29159) * Apply lint rule @typescript-eslint/no-empty-object-type To avoid the footgun that is https://www.totaltypescript.com/the-empty-object-type-in-typescript Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .eslintrc.js | 10 +++++++-- playwright/pages/client.ts | 7 ++++--- src/@types/diff-dom.d.ts | 1 + src/@types/matrix-js-sdk.d.ts | 5 +++-- src/@types/react.d.ts | 2 +- src/AddThreepid.ts | 1 + src/WorkerManager.ts | 2 +- src/autocomplete/QueryMatcher.ts | 4 ++-- .../structures/AutoHideScrollbar.tsx | 2 +- .../structures/NonUrgentToastContainer.tsx | 7 +++---- src/components/structures/ToastContainer.tsx | 5 +++-- .../auth/header/AuthHeaderProvider.tsx | 2 +- .../views/audio_messages/Waveform.tsx | 4 +--- .../auth/InteractiveAuthEntryComponents.tsx | 2 +- src/components/views/auth/Welcome.tsx | 5 ++--- .../views/elements/EditableItemList.tsx | 2 +- .../views/elements/StyledCheckbox.tsx | 4 +--- .../views/elements/StyledRadioButton.tsx | 4 +--- src/components/views/rooms/Autocomplete.tsx | 4 ++-- .../views/rooms/RoomBreadcrumbs.tsx | 8 +++---- .../rooms/wysiwyg_composer/hooks/utils.ts | 2 +- .../views/settings/CrossSigningPanel.tsx | 6 +++--- .../views/settings/CryptographyPanel.tsx | 7 +++---- .../views/settings/EventIndexPanel.tsx | 5 +++-- .../views/settings/FontScalingPanel.tsx | 7 +++---- .../views/settings/ImageSizePanel.tsx | 9 +++----- .../views/settings/Notifications.tsx | 11 +++++----- .../views/settings/SecureBackupPanel.tsx | 5 +++-- .../views/settings/SetIntegrationManager.tsx | 7 +++---- .../tabs/user/AppearanceUserSettingsTab.tsx | 7 +++---- .../tabs/user/HelpUserSettingsTab.tsx | 7 +++---- .../tabs/user/LabsUserSettingsTab.tsx | 5 +++-- .../tabs/user/MjolnirUserSettingsTab.tsx | 5 +++-- .../tabs/user/VoiceUserSettingsTab.tsx | 5 +++-- src/contexts/MatrixClientContext.tsx | 2 +- src/editor/autocomplete.ts | 4 ++-- src/hooks/useAccountData.ts | 4 ++-- src/stores/CallStore.ts | 4 ++-- src/stores/WidgetStore.ts | 6 ++---- .../RoomNotificationStateStore.ts | 6 ++---- src/stores/room-list/MessagePreviewStore.ts | 16 ++++++++------ src/stores/room-list/RoomListLayoutStore.ts | 5 ++--- src/stores/room-list/RoomListStore.ts | 8 ++----- src/stores/room-list/SlidingRoomListStore.ts | 8 ++----- src/stores/spaces/SpaceStore.ts | 5 ++--- src/stores/widgets/WidgetMessagingStore.ts | 3 ++- src/utils/MultiInviter.ts | 4 ++-- src/utils/PinningUtils.ts | 12 +++++++++-- src/utils/notifications.ts | 21 +++++++++++-------- src/utils/objects.ts | 16 +++++++------- src/vector/app.tsx | 3 ++- src/vector/init.tsx | 3 ++- src/vector/platform/IPCManager.ts | 2 +- .../tabs/user/LabsUserSettingsTab-test.tsx | 5 +---- .../tabs/user/SessionManagerTab-test.tsx | 5 +++-- test/unit-tests/hooks/useProfileInfo-test.tsx | 4 ++-- 56 files changed, 157 insertions(+), 158 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index f310384972..892d7cdbb1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -200,8 +200,13 @@ module.exports = { "@typescript-eslint/ban-ts-comment": "off", // We're okay with assertion errors when we ask for them "@typescript-eslint/no-non-null-assertion": "off", - // We do this sometimes to brand interfaces - "@typescript-eslint/no-empty-object-type": "off", + "@typescript-eslint/no-empty-object-type": [ + "error", + { + // We do this sometimes to brand interfaces + allowInterfaces: "with-single-extends", + }, + ], }, }, // temporary override for offending icon require files @@ -247,6 +252,7 @@ module.exports = { // We don't need super strict typing in test utilities "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/explicit-member-accessibility": "off", + "@typescript-eslint/no-empty-object-type": "off", // Jest/Playwright specific diff --git a/playwright/pages/client.ts b/playwright/pages/client.ts index 611a6cef19..d1ce3709d3 100644 --- a/playwright/pages/client.ts +++ b/playwright/pages/client.ts @@ -25,6 +25,7 @@ import type { StateEvents, TimelineEvents, AccountDataEvents, + EmptyObject, } from "matrix-js-sdk/src/matrix"; import type { RoomMessageEventContent } from "matrix-js-sdk/src/types"; import { Credentials } from "../plugins/homeserver"; @@ -363,7 +364,7 @@ export class Client { event: JSHandle, receiptType?: ReceiptType, unthreaded?: boolean, - ): Promise<{}> { + ): Promise { const client = await this.prepareClient(); return client.evaluate( (client, { event, receiptType, unthreaded }) => { @@ -386,7 +387,7 @@ export class Client { * @return {Promise} Resolves: {} an empty object. * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public async setDisplayName(name: string): Promise<{}> { + public async setDisplayName(name: string): Promise { const client = await this.prepareClient(); return client.evaluate(async (cli: MatrixClient, name) => cli.setDisplayName(name), name); } @@ -397,7 +398,7 @@ export class Client { * @return {Promise} Resolves: {} an empty object. * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public async setAvatarUrl(url: string): Promise<{}> { + public async setAvatarUrl(url: string): Promise { const client = await this.prepareClient(); return client.evaluate(async (cli: MatrixClient, url) => cli.setAvatarUrl(url), url); } diff --git a/src/@types/diff-dom.d.ts b/src/@types/diff-dom.d.ts index 986a84dc0b..12587446d0 100644 --- a/src/@types/diff-dom.d.ts +++ b/src/@types/diff-dom.d.ts @@ -18,6 +18,7 @@ declare module "diff-dom" { newValue: HTMLElement | string; } + // eslint-disable-next-line @typescript-eslint/no-empty-object-type interface IOpts {} export class DiffDOM { diff --git a/src/@types/matrix-js-sdk.d.ts b/src/@types/matrix-js-sdk.d.ts index 6ffa09dd4f..92b76c4c4d 100644 --- a/src/@types/matrix-js-sdk.d.ts +++ b/src/@types/matrix-js-sdk.d.ts @@ -11,6 +11,7 @@ import type { BLURHASH_FIELD } from "../utils/image-media"; import type { JitsiCallMemberEventType, JitsiCallMemberContent } from "../call-types"; import type { ILayoutStateEvent, WIDGET_LAYOUT_EVENT_TYPE } from "../stores/widgets/types"; import type { EncryptedFile } from "matrix-js-sdk/src/types"; +import type { EmptyObject } from "matrix-js-sdk/src/matrix"; import type { DeviceClientInformation } from "../utils/device/types.ts"; import type { UserWidget } from "../utils/WidgetUtils-types.ts"; @@ -35,7 +36,7 @@ declare module "matrix-js-sdk/src/types" { [JitsiCallMemberEventType]: JitsiCallMemberContent; // Unstable widgets state events - "im.vector.modular.widgets": IWidget | {}; + "im.vector.modular.widgets": IWidget | EmptyObject; [WIDGET_LAYOUT_EVENT_TYPE]: ILayoutStateEvent; // Element custom state events @@ -104,6 +105,6 @@ declare module "matrix-js-sdk/src/types" { // https://github.com/matrix-org/matrix-doc/pull/3246 waveform?: number[]; }; - "org.matrix.msc3245.voice"?: {}; + "org.matrix.msc3245.voice"?: EmptyObject; } } diff --git a/src/@types/react.d.ts b/src/@types/react.d.ts index 2573bc0ab9..b1f6352adb 100644 --- a/src/@types/react.d.ts +++ b/src/@types/react.d.ts @@ -10,7 +10,7 @@ import React, { PropsWithChildren } from "react"; declare module "react" { // Fix forwardRef types for Generic components - https://stackoverflow.com/a/58473012 - function forwardRef( + function forwardRef( render: (props: PropsWithChildren

, ref: React.ForwardedRef) => React.ReactElement | null, ): (props: P & React.RefAttributes) => React.ReactElement | null; diff --git a/src/AddThreepid.ts b/src/AddThreepid.ts index 757ea18180..10c28bfc4a 100644 --- a/src/AddThreepid.ts +++ b/src/AddThreepid.ts @@ -249,6 +249,7 @@ export default class AddThreepid { * @param {{type: string, session?: string}} auth UI auth object * @return {Promise} Response from /3pid/add call (in current spec, an empty object) */ + // eslint-disable-next-line @typescript-eslint/no-empty-object-type private makeAddThreepidOnlyRequest = (auth?: IAddThreePidOnlyBody["auth"] | null): Promise<{}> => { return this.matrixClient.addThreePidOnly({ sid: this.sessionId!, diff --git a/src/WorkerManager.ts b/src/WorkerManager.ts index 089463dc91..f34d8dbfd1 100644 --- a/src/WorkerManager.ts +++ b/src/WorkerManager.ts @@ -10,7 +10,7 @@ import { defer, IDeferred } from "matrix-js-sdk/src/utils"; import { WorkerPayload } from "./workers/worker"; -export class WorkerManager { +export class WorkerManager { private readonly worker: Worker; private seq = 0; private pendingDeferredMap = new Map>(); diff --git a/src/autocomplete/QueryMatcher.ts b/src/autocomplete/QueryMatcher.ts index 985ca3a516..d23bac2128 100644 --- a/src/autocomplete/QueryMatcher.ts +++ b/src/autocomplete/QueryMatcher.ts @@ -14,7 +14,7 @@ import { removeHiddenChars } from "matrix-js-sdk/src/utils"; import { TimelineRenderingType } from "../contexts/RoomContext"; import { Leaves } from "../@types/common"; -interface IOptions { +interface IOptions { keys: Array>; funcs?: Array<(o: T) => string | string[]>; shouldMatchWordsOnly?: boolean; @@ -37,7 +37,7 @@ interface IOptions { * @param {function[]} options.funcs List of functions that when called with the * object as an arg will return a string to use as an index */ -export default class QueryMatcher { +export default class QueryMatcher { private _options: IOptions; private _items = new Map(); diff --git a/src/components/structures/AutoHideScrollbar.tsx b/src/components/structures/AutoHideScrollbar.tsx index 764a712d44..da27f25cdb 100644 --- a/src/components/structures/AutoHideScrollbar.tsx +++ b/src/components/structures/AutoHideScrollbar.tsx @@ -11,7 +11,7 @@ import classNames from "classnames"; import React, { HTMLAttributes, ReactHTML, ReactNode, WheelEvent } from "react"; type DynamicHtmlElementProps = - JSX.IntrinsicElements[T] extends HTMLAttributes<{}> ? DynamicElementProps : DynamicElementProps<"div">; + JSX.IntrinsicElements[T] extends HTMLAttributes ? DynamicElementProps : DynamicElementProps<"div">; type DynamicElementProps = Partial>; export type IProps = Omit, "onScroll"> & { diff --git a/src/components/structures/NonUrgentToastContainer.tsx b/src/components/structures/NonUrgentToastContainer.tsx index aa445a5498..eac92f8af6 100644 --- a/src/components/structures/NonUrgentToastContainer.tsx +++ b/src/components/structures/NonUrgentToastContainer.tsx @@ -7,19 +7,18 @@ Please see LICENSE files in the repository root for full details. */ import * as React from "react"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import { ComponentClass } from "../../@types/common"; import NonUrgentToastStore from "../../stores/NonUrgentToastStore"; import { UPDATE_EVENT } from "../../stores/AsyncStore"; -interface IProps {} - interface IState { toasts: ComponentClass[]; } -export default class NonUrgentToastContainer extends React.PureComponent { - public constructor(props: IProps) { +export default class NonUrgentToastContainer extends React.PureComponent { + public constructor(props: EmptyObject) { super(props); this.state = { diff --git a/src/components/structures/ToastContainer.tsx b/src/components/structures/ToastContainer.tsx index 02db99a0e0..862e4150aa 100644 --- a/src/components/structures/ToastContainer.tsx +++ b/src/components/structures/ToastContainer.tsx @@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details. import * as React from "react"; import classNames from "classnames"; import { Text } from "@vector-im/compound-web"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import ToastStore, { IToast } from "../../stores/ToastStore"; @@ -17,8 +18,8 @@ interface IState { countSeen: number; } -export default class ToastContainer extends React.Component<{}, IState> { - public constructor(props: {}) { +export default class ToastContainer extends React.Component { + public constructor(props: EmptyObject) { super(props); this.state = { toasts: ToastStore.sharedInstance().getToasts(), diff --git a/src/components/structures/auth/header/AuthHeaderProvider.tsx b/src/components/structures/auth/header/AuthHeaderProvider.tsx index 0189b69212..4c4eb62098 100644 --- a/src/components/structures/auth/header/AuthHeaderProvider.tsx +++ b/src/components/structures/auth/header/AuthHeaderProvider.tsx @@ -24,7 +24,7 @@ interface AuthHeaderAction { export type AuthHeaderReducer = Reducer[], AuthHeaderAction>; -export function AuthHeaderProvider({ children }: PropsWithChildren<{}>): JSX.Element { +export function AuthHeaderProvider({ children }: PropsWithChildren): JSX.Element { const [state, dispatch] = useReducer( (state: ComponentProps[], action: AuthHeaderAction) => { switch (action.type) { diff --git a/src/components/views/audio_messages/Waveform.tsx b/src/components/views/audio_messages/Waveform.tsx index 83d02b81fd..2110622403 100644 --- a/src/components/views/audio_messages/Waveform.tsx +++ b/src/components/views/audio_messages/Waveform.tsx @@ -18,8 +18,6 @@ interface IProps { progress: number; // percent complete, 0-1, default 100% } -interface IState {} - /** * A simple waveform component. This renders bars (centered vertically) for each * height provided in the component properties. Updating the properties will update @@ -28,7 +26,7 @@ interface IState {} * For CSS purposes, a mx_Waveform_bar_100pct class is added when the bar should be * "filled", as a demonstration of the progress property. */ -export default class Waveform extends React.PureComponent { +export default class Waveform extends React.PureComponent { public static defaultProps = { progress: 1, }; diff --git a/src/components/views/auth/InteractiveAuthEntryComponents.tsx b/src/components/views/auth/InteractiveAuthEntryComponents.tsx index 68ea886554..92440dc203 100644 --- a/src/components/views/auth/InteractiveAuthEntryComponents.tsx +++ b/src/components/views/auth/InteractiveAuthEntryComponents.tsx @@ -894,7 +894,7 @@ export class SSOAuthEntry extends React.Component extends React.Component { +export class FallbackAuthEntry extends React.Component { protected popupWindow: Window | null; protected fallbackButton = createRef(); diff --git a/src/components/views/auth/Welcome.tsx b/src/components/views/auth/Welcome.tsx index 39d5f95a8d..dc7eb4ad40 100644 --- a/src/components/views/auth/Welcome.tsx +++ b/src/components/views/auth/Welcome.tsx @@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details. import React from "react"; import classNames from "classnames"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import SdkConfig from "../../../SdkConfig"; import AuthPage from "./AuthPage"; @@ -16,9 +17,7 @@ import LanguageSelector from "./LanguageSelector"; import EmbeddedPage from "../../structures/EmbeddedPage"; import { MATRIX_LOGO_HTML } from "../../structures/static-page-vars"; -interface IProps {} - -export default class Welcome extends React.PureComponent { +export default class Welcome extends React.PureComponent { public render(): React.ReactNode { const pagesConfig = SdkConfig.getObject("embedded_pages"); let pageUrl: string | undefined; diff --git a/src/components/views/elements/EditableItemList.tsx b/src/components/views/elements/EditableItemList.tsx index 134c615194..f08b65e24f 100644 --- a/src/components/views/elements/EditableItemList.tsx +++ b/src/components/views/elements/EditableItemList.tsx @@ -101,7 +101,7 @@ interface IProps { onNewItemChanged?(item: string): void; } -export default class EditableItemList

extends React.PureComponent { +export default class EditableItemList

extends React.PureComponent { protected onItemAdded = (e: ButtonEvent): void => { e.stopPropagation(); e.preventDefault(); diff --git a/src/components/views/elements/StyledCheckbox.tsx b/src/components/views/elements/StyledCheckbox.tsx index 8e1905924a..2445859341 100644 --- a/src/components/views/elements/StyledCheckbox.tsx +++ b/src/components/views/elements/StyledCheckbox.tsx @@ -21,9 +21,7 @@ interface IProps extends React.InputHTMLAttributes { id?: string; } -interface IState {} - -export default class StyledCheckbox extends React.PureComponent { +export default class StyledCheckbox extends React.PureComponent { private id: string; public static readonly defaultProps = { diff --git a/src/components/views/elements/StyledRadioButton.tsx b/src/components/views/elements/StyledRadioButton.tsx index 01e4de1dad..caf40c7f1a 100644 --- a/src/components/views/elements/StyledRadioButton.tsx +++ b/src/components/views/elements/StyledRadioButton.tsx @@ -18,9 +18,7 @@ interface IProps extends React.InputHTMLAttributes { childrenInLabel?: boolean; } -interface IState {} - -export default class StyledRadioButton extends React.PureComponent { +export default class StyledRadioButton extends React.PureComponent { public static readonly defaultProps = { className: "", childrenInLabel: true, diff --git a/src/components/views/rooms/Autocomplete.tsx b/src/components/views/rooms/Autocomplete.tsx index f77f394d8c..33d3435dfc 100644 --- a/src/components/views/rooms/Autocomplete.tsx +++ b/src/components/views/rooms/Autocomplete.tsx @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import React, { createRef, KeyboardEvent, RefObject } from "react"; +import React, { createRef, RefObject } from "react"; import classNames from "classnames"; import { flatMap } from "lodash"; import { Room } from "matrix-js-sdk/src/matrix"; @@ -206,7 +206,7 @@ export default class Autocomplete extends React.PureComponent { this.setSelection(1 + index); } - public onEscape(e: KeyboardEvent): boolean | undefined { + public onEscape(e: KeyboardEvent | React.KeyboardEvent): boolean | undefined { const completionCount = this.countCompletions(); if (completionCount === 0) { // autocomplete is already empty, so don't preventDefault diff --git a/src/components/views/rooms/RoomBreadcrumbs.tsx b/src/components/views/rooms/RoomBreadcrumbs.tsx index 40290358f5..ce87718197 100644 --- a/src/components/views/rooms/RoomBreadcrumbs.tsx +++ b/src/components/views/rooms/RoomBreadcrumbs.tsx @@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details. */ import React, { createRef } from "react"; -import { Room } from "matrix-js-sdk/src/matrix"; +import { EmptyObject, Room } from "matrix-js-sdk/src/matrix"; import { CSSTransition } from "react-transition-group"; import { BreadcrumbsStore } from "../../../stores/BreadcrumbsStore"; @@ -21,8 +21,6 @@ import { Action } from "../../../dispatcher/actions"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; -interface IProps {} - interface IState { // Both of these control the animation for the breadcrumbs. For details on the // actual animation, see the CSS. @@ -59,11 +57,11 @@ const RoomBreadcrumbTile: React.FC<{ room: Room; onClick: (ev: ButtonEvent) => v ); }; -export default class RoomBreadcrumbs extends React.PureComponent { +export default class RoomBreadcrumbs extends React.PureComponent { private unmounted = false; private toolbar = createRef(); - public constructor(props: IProps) { + public constructor(props: EmptyObject) { super(props); this.state = { diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/utils.ts b/src/components/views/rooms/wysiwyg_composer/hooks/utils.ts index 52a61ac0e3..48b73d352b 100644 --- a/src/components/views/rooms/wysiwyg_composer/hooks/utils.ts +++ b/src/components/views/rooms/wysiwyg_composer/hooks/utils.ts @@ -92,7 +92,7 @@ export function handleEventWithAutocomplete( handled = true; break; case KeyBindingAction.CancelAutocomplete: - autocompleteRef.current.onEscape(event as {} as React.KeyboardEvent); + autocompleteRef.current.onEscape(event); handled = true; break; default: diff --git a/src/components/views/settings/CrossSigningPanel.tsx b/src/components/views/settings/CrossSigningPanel.tsx index 9ec9e9f6c1..5b7a39aad2 100644 --- a/src/components/views/settings/CrossSigningPanel.tsx +++ b/src/components/views/settings/CrossSigningPanel.tsx @@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details. */ import React from "react"; -import { ClientEvent, MatrixEvent } from "matrix-js-sdk/src/matrix"; +import { ClientEvent, EmptyObject, MatrixEvent } from "matrix-js-sdk/src/matrix"; import { logger } from "matrix-js-sdk/src/logger"; import { CryptoEvent } from "matrix-js-sdk/src/crypto-api"; @@ -33,10 +33,10 @@ interface IState { crossSigningReady?: boolean; } -export default class CrossSigningPanel extends React.PureComponent<{}, IState> { +export default class CrossSigningPanel extends React.PureComponent { private unmounted = false; - public constructor(props: {}) { + public constructor(props: EmptyObject) { super(props); this.state = { diff --git a/src/components/views/settings/CryptographyPanel.tsx b/src/components/views/settings/CryptographyPanel.tsx index beb08ab1e9..d0cabf7af9 100644 --- a/src/components/views/settings/CryptographyPanel.tsx +++ b/src/components/views/settings/CryptographyPanel.tsx @@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details. import React, { lazy } from "react"; import { logger } from "matrix-js-sdk/src/logger"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../languageHandler"; import Modal from "../../../Modal"; @@ -19,8 +20,6 @@ import { SettingLevel } from "../../../settings/SettingLevel"; import { SettingsSubsection, SettingsSubsectionText } from "./shared/SettingsSubsection"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -interface IProps {} - interface IState { /** The device's base64-encoded Ed25519 identity key, or: * @@ -30,11 +29,11 @@ interface IState { deviceIdentityKey: string | undefined | null; } -export default class CryptographyPanel extends React.Component { +export default class CryptographyPanel extends React.Component { public static contextType = MatrixClientContext; declare public context: React.ContextType; - public constructor(props: IProps, context: React.ContextType) { + public constructor(props: EmptyObject, context: React.ContextType) { super(props); if (!context.getCrypto()) { diff --git a/src/components/views/settings/EventIndexPanel.tsx b/src/components/views/settings/EventIndexPanel.tsx index 41845eb94e..c314f72f38 100644 --- a/src/components/views/settings/EventIndexPanel.tsx +++ b/src/components/views/settings/EventIndexPanel.tsx @@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details. */ import React, { lazy } from "react"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; @@ -28,8 +29,8 @@ interface IState { eventIndexingEnabled: boolean; } -export default class EventIndexPanel extends React.Component<{}, IState> { - public constructor(props: {}) { +export default class EventIndexPanel extends React.Component { + public constructor(props: EmptyObject) { super(props); this.state = { diff --git a/src/components/views/settings/FontScalingPanel.tsx b/src/components/views/settings/FontScalingPanel.tsx index e1a7f4902f..f2f1d6a93b 100644 --- a/src/components/views/settings/FontScalingPanel.tsx +++ b/src/components/views/settings/FontScalingPanel.tsx @@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details. */ import React from "react"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import EventTilePreview from "../elements/EventTilePreview"; import SettingsStore from "../../../settings/SettingsStore"; @@ -18,8 +19,6 @@ import { SettingsSubsection } from "./shared/SettingsSubsection"; import Field from "../elements/Field"; import { FontWatcher } from "../../../settings/watchers/FontWatcher"; -interface IProps {} - interface IState { browserFontSize: number; // String displaying the current selected fontSize. @@ -34,7 +33,7 @@ interface IState { avatarUrl?: string; } -export default class FontScalingPanel extends React.Component { +export default class FontScalingPanel extends React.Component { private readonly MESSAGE_PREVIEW_TEXT = _t("common|preview_message"); /** * Font sizes available (in px) @@ -43,7 +42,7 @@ export default class FontScalingPanel extends React.Component { private layoutWatcherRef?: string; private unmounted = false; - public constructor(props: IProps) { + public constructor(props: EmptyObject) { super(props); this.state = { diff --git a/src/components/views/settings/ImageSizePanel.tsx b/src/components/views/settings/ImageSizePanel.tsx index 8079ea1654..cae714d002 100644 --- a/src/components/views/settings/ImageSizePanel.tsx +++ b/src/components/views/settings/ImageSizePanel.tsx @@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details. */ import React from "react"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import SettingsStore from "../../../settings/SettingsStore"; import StyledRadioButton from "../elements/StyledRadioButton"; @@ -15,16 +16,12 @@ import { SettingLevel } from "../../../settings/SettingLevel"; import { ImageSize } from "../../../settings/enums/ImageSize"; import { SettingsSubsection } from "./shared/SettingsSubsection"; -interface IProps { - // none -} - interface IState { size: ImageSize; } -export default class ImageSizePanel extends React.Component { - public constructor(props: IProps) { +export default class ImageSizePanel extends React.Component { + public constructor(props: EmptyObject) { super(props); this.state = { diff --git a/src/components/views/settings/Notifications.tsx b/src/components/views/settings/Notifications.tsx index 6cf4f8abea..1b9d266a94 100644 --- a/src/components/views/settings/Notifications.tsx +++ b/src/components/views/settings/Notifications.tsx @@ -16,6 +16,7 @@ import { IThreepid, ThreepidMedium, LocalNotificationSettings, + EmptyObject, } from "matrix-js-sdk/src/matrix"; import { logger } from "matrix-js-sdk/src/logger"; @@ -108,8 +109,6 @@ interface IVectorPushRule { syncedVectorState?: VectorState; } -interface IProps {} - interface IState { phase: Phase; @@ -205,10 +204,10 @@ const NotificationActivitySettings = (): JSX.Element => { /** * The old, deprecated notifications tab view, only displayed if the user has the labs flag disabled. */ -export default class Notifications extends React.PureComponent { +export default class Notifications extends React.PureComponent { private settingWatchers: string[] = []; - public constructor(props: IProps) { + public constructor(props: EmptyObject) { super(props); this.state = { @@ -255,7 +254,7 @@ export default class Notifications extends React.PureComponent { this.settingWatchers.forEach((watcher) => SettingsStore.unwatchSetting(watcher)); } - public componentDidUpdate(prevProps: Readonly, prevState: Readonly): void { + public componentDidUpdate(prevProps: Readonly, prevState: Readonly): void { if (this.state.deviceNotificationsEnabled !== prevState.deviceNotificationsEnabled) { this.persistLocalNotificationSettings(this.state.deviceNotificationsEnabled); } @@ -291,7 +290,7 @@ export default class Notifications extends React.PureComponent { } } - private persistLocalNotificationSettings(enabled: boolean): Promise<{}> { + private persistLocalNotificationSettings(enabled: boolean): Promise { const cli = MatrixClientPeg.safeGet(); return cli.setAccountData(getLocalNotificationAccountDataEventType(cli.deviceId), { is_silenced: !enabled, diff --git a/src/components/views/settings/SecureBackupPanel.tsx b/src/components/views/settings/SecureBackupPanel.tsx index 3d24567832..722c3fe38f 100644 --- a/src/components/views/settings/SecureBackupPanel.tsx +++ b/src/components/views/settings/SecureBackupPanel.tsx @@ -10,6 +10,7 @@ Please see LICENSE files in the repository root for full details. import React, { lazy, ReactNode } from "react"; import { CryptoEvent, BackupTrustInfo, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api"; import { logger } from "matrix-js-sdk/src/logger"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { _t } from "../../../languageHandler"; @@ -60,10 +61,10 @@ interface IState { sessionsRemaining: number | null; } -export default class SecureBackupPanel extends React.PureComponent<{}, IState> { +export default class SecureBackupPanel extends React.PureComponent { private unmounted = false; - public constructor(props: {}) { + public constructor(props: EmptyObject) { super(props); this.state = { diff --git a/src/components/views/settings/SetIntegrationManager.tsx b/src/components/views/settings/SetIntegrationManager.tsx index 01dab79547..fbf9ff710f 100644 --- a/src/components/views/settings/SetIntegrationManager.tsx +++ b/src/components/views/settings/SetIntegrationManager.tsx @@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details. import React from "react"; import { logger } from "matrix-js-sdk/src/logger"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../languageHandler"; import { IntegrationManagers } from "../../../integrations/IntegrationManagers"; @@ -19,15 +20,13 @@ import Heading from "../typography/Heading"; import { SettingsSubsectionText } from "./shared/SettingsSubsection"; import { UIFeature } from "../../../settings/UIFeature"; -interface IProps {} - interface IState { currentManager: IntegrationManagerInstance | null; provisioningEnabled: boolean; } -export default class SetIntegrationManager extends React.Component { - public constructor(props: IProps) { +export default class SetIntegrationManager extends React.Component { + public constructor(props: EmptyObject) { super(props); const currentManager = IntegrationManagers.sharedInstance().getPrimaryManager(); diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx index 4586191db1..8720c55a91 100644 --- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx @@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details. */ import React, { ChangeEvent, ReactNode } from "react"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../../../languageHandler"; import SdkConfig from "../../../../../SdkConfig"; @@ -25,8 +26,6 @@ import SettingsTab from "../SettingsTab"; import { SettingsSection } from "../../shared/SettingsSection"; import { SettingsSubsection } from "../../shared/SettingsSubsection"; -interface IProps {} - interface IState { useBundledEmojiFont: boolean; useSystemFont: boolean; @@ -34,8 +33,8 @@ interface IState { showAdvanced: boolean; } -export default class AppearanceUserSettingsTab extends React.Component { - public constructor(props: IProps) { +export default class AppearanceUserSettingsTab extends React.Component { + public constructor(props: EmptyObject) { super(props); this.state = { diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx index d28c820d20..1d24875482 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx @@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details. import React, { ReactNode } from "react"; import { logger } from "matrix-js-sdk/src/logger"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import AccessibleButton from "../../../elements/AccessibleButton"; import { _t } from "../../../../../languageHandler"; @@ -23,18 +24,16 @@ import { SettingsSubsection, SettingsSubsectionText } from "../../shared/Setting import ExternalLink from "../../../elements/ExternalLink"; import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; -interface IProps {} - interface IState { appVersion: string | null; canUpdate: boolean; } -export default class HelpUserSettingsTab extends React.Component { +export default class HelpUserSettingsTab extends React.Component { public static contextType = MatrixClientContext; declare public context: React.ContextType; - public constructor(props: IProps, context: React.ContextType) { + public constructor(props: EmptyObject, context: React.ContextType) { super(props, context); this.state = { diff --git a/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx b/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx index 5cee63b48e..140b599b4a 100644 --- a/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx @@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details. import React from "react"; import { sortBy } from "lodash"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../../../languageHandler"; import SettingsStore from "../../../../../settings/SettingsStore"; @@ -24,11 +25,11 @@ export const showLabsFlags = (): boolean => { return SdkConfig.get("show_labs_settings") || SettingsStore.getValue("developerMode"); }; -export default class LabsUserSettingsTab extends React.Component<{}> { +export default class LabsUserSettingsTab extends React.Component { private readonly labs: FeatureSettingKey[]; private readonly betas: FeatureSettingKey[]; - public constructor(props: {}) { + public constructor(props: EmptyObject) { super(props); const features = SettingsStore.getFeatureSettingNames(); diff --git a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx index 9b71244e55..b0fa4e0fc2 100644 --- a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx @@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details. import React, { ChangeEvent, SyntheticEvent } from "react"; import { logger } from "matrix-js-sdk/src/logger"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../../../languageHandler"; import SdkConfig from "../../../../../SdkConfig"; @@ -30,8 +31,8 @@ interface IState { newList: string; } -export default class MjolnirUserSettingsTab extends React.Component<{}, IState> { - public constructor(props: {}) { +export default class MjolnirUserSettingsTab extends React.Component { + public constructor(props: EmptyObject) { super(props); this.state = { diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx index a52a232cd5..739bf3dea1 100644 --- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx @@ -10,6 +10,7 @@ Please see LICENSE files in the repository root for full details. import React, { ReactNode } from "react"; import { logger } from "matrix-js-sdk/src/logger"; import { FALLBACK_ICE_SERVER } from "matrix-js-sdk/src/webrtc/call"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../../../languageHandler"; import MediaDeviceHandler, { IMediaDevices, MediaDeviceKindEnum } from "../../../../../MediaDeviceHandler"; @@ -49,11 +50,11 @@ const mapDeviceKindToHandlerValue = (deviceKind: MediaDeviceKindEnum): string | } }; -export default class VoiceUserSettingsTab extends React.Component<{}, IState> { +export default class VoiceUserSettingsTab extends React.Component { public static contextType = MatrixClientContext; declare public context: React.ContextType; - public constructor(props: {}, context: React.ContextType) { + public constructor(props: EmptyObject, context: React.ContextType) { super(props, context); this.state = { diff --git a/src/contexts/MatrixClientContext.tsx b/src/contexts/MatrixClientContext.tsx index 79ce5e5009..3401330379 100644 --- a/src/contexts/MatrixClientContext.tsx +++ b/src/contexts/MatrixClientContext.tsx @@ -24,7 +24,7 @@ export function useMatrixClientContext(): MatrixClient { return useContext(MatrixClientContext); } -const matrixHOC = ( +const matrixHOC = ( ComposedComponent: ComponentClass, ): (( props: Omit & React.RefAttributes>, diff --git a/src/editor/autocomplete.ts b/src/editor/autocomplete.ts index ff1e89b1f1..abbea0254e 100644 --- a/src/editor/autocomplete.ts +++ b/src/editor/autocomplete.ts @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { KeyboardEvent } from "react"; +import React from "react"; import { Part, CommandPartCreator, PartCreator } from "./parts"; import DocumentPosition from "./position"; @@ -33,7 +33,7 @@ export default class AutocompleteWrapperModel { private partCreator: PartCreator | CommandPartCreator, ) {} - public onEscape(e: KeyboardEvent): void { + public onEscape(e: KeyboardEvent | React.KeyboardEvent): void { this.getAutocompleterComponent()?.onEscape(e); } diff --git a/src/hooks/useAccountData.ts b/src/hooks/useAccountData.ts index 7cbc77d525..a86f8765fe 100644 --- a/src/hooks/useAccountData.ts +++ b/src/hooks/useAccountData.ts @@ -11,10 +11,10 @@ import { AccountDataEvents, ClientEvent, MatrixClient, MatrixEvent } from "matri import { useTypedEventEmitter } from "./useEventEmitter"; -const tryGetContent = (ev?: MatrixEvent): T | undefined => ev?.getContent(); +const tryGetContent = (ev?: MatrixEvent): T | undefined => ev?.getContent(); // Hook to simplify listening to Matrix account data -export const useAccountData = (cli: MatrixClient, eventType: keyof AccountDataEvents): T => { +export const useAccountData = (cli: MatrixClient, eventType: keyof AccountDataEvents): T => { const [value, setValue] = useState(() => tryGetContent(cli.getAccountData(eventType))); const handler = useCallback( diff --git a/src/stores/CallStore.ts b/src/stores/CallStore.ts index d667e0b811..0d950eecce 100644 --- a/src/stores/CallStore.ts +++ b/src/stores/CallStore.ts @@ -10,7 +10,7 @@ import { logger } from "matrix-js-sdk/src/logger"; import { GroupCallEventHandlerEvent } from "matrix-js-sdk/src/webrtc/groupCallEventHandler"; import { MatrixRTCSession, MatrixRTCSessionManagerEvents } from "matrix-js-sdk/src/matrixrtc"; -import type { GroupCall, Room } from "matrix-js-sdk/src/matrix"; +import type { EmptyObject, GroupCall, Room } from "matrix-js-sdk/src/matrix"; import defaultDispatcher from "../dispatcher/dispatcher"; import { UPDATE_EVENT } from "./AsyncStore"; import { AsyncStoreWithClient } from "./AsyncStoreWithClient"; @@ -26,7 +26,7 @@ export enum CallStoreEvent { ConnectedCalls = "connected_calls", } -export class CallStore extends AsyncStoreWithClient<{}> { +export class CallStore extends AsyncStoreWithClient { private static _instance: CallStore; public static get instance(): CallStore { if (!this._instance) { diff --git a/src/stores/WidgetStore.ts b/src/stores/WidgetStore.ts index 8c69770930..a715a97c1e 100644 --- a/src/stores/WidgetStore.ts +++ b/src/stores/WidgetStore.ts @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { Room, RoomStateEvent, MatrixEvent, ClientEvent } from "matrix-js-sdk/src/matrix"; +import { Room, RoomStateEvent, MatrixEvent, ClientEvent, EmptyObject } from "matrix-js-sdk/src/matrix"; import { IWidget } from "matrix-widget-api"; import { logger } from "matrix-js-sdk/src/logger"; @@ -19,8 +19,6 @@ import WidgetUtils from "../utils/WidgetUtils"; import { UPDATE_EVENT } from "./AsyncStore"; import { IApp } from "../utils/WidgetUtils-types"; -interface IState {} - export type { IApp }; export function isAppWidget(widget: IWidget | IApp): widget is IApp { @@ -36,7 +34,7 @@ interface IRoomWidgets { // TODO consolidate WidgetEchoStore into this // TODO consolidate ActiveWidgetStore into this -export default class WidgetStore extends AsyncStoreWithClient { +export default class WidgetStore extends AsyncStoreWithClient { private static readonly internalInstance = (() => { const instance = new WidgetStore(); instance.start(); diff --git a/src/stores/notifications/RoomNotificationStateStore.ts b/src/stores/notifications/RoomNotificationStateStore.ts index c58125b0ba..4fa51128be 100644 --- a/src/stores/notifications/RoomNotificationStateStore.ts +++ b/src/stores/notifications/RoomNotificationStateStore.ts @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { Room, ClientEvent, SyncState } from "matrix-js-sdk/src/matrix"; +import { Room, ClientEvent, SyncState, EmptyObject } from "matrix-js-sdk/src/matrix"; import { ActionPayload } from "../../dispatcher/payloads"; import { AsyncStoreWithClient } from "../AsyncStoreWithClient"; @@ -19,11 +19,9 @@ import { VisibilityProvider } from "../room-list/filters/VisibilityProvider"; import { PosthogAnalytics } from "../../PosthogAnalytics"; import SettingsStore from "../../settings/SettingsStore"; -interface IState {} - export const UPDATE_STATUS_INDICATOR = Symbol("update-status-indicator"); -export class RoomNotificationStateStore extends AsyncStoreWithClient { +export class RoomNotificationStateStore extends AsyncStoreWithClient { private static readonly internalInstance = (() => { const instance = new RoomNotificationStateStore(); instance.start(); diff --git a/src/stores/room-list/MessagePreviewStore.ts b/src/stores/room-list/MessagePreviewStore.ts index 3f1614df70..fe2d56871d 100644 --- a/src/stores/room-list/MessagePreviewStore.ts +++ b/src/stores/room-list/MessagePreviewStore.ts @@ -6,7 +6,15 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { Room, RelationType, MatrixEvent, Thread, M_POLL_START, RoomEvent } from "matrix-js-sdk/src/matrix"; +import { + Room, + RelationType, + MatrixEvent, + Thread, + M_POLL_START, + RoomEvent, + EmptyObject, +} from "matrix-js-sdk/src/matrix"; import { isNullOrUndefined } from "matrix-js-sdk/src/utils"; import { ActionPayload } from "../../dispatcher/payloads"; @@ -76,10 +84,6 @@ const MAX_EVENTS_BACKWARDS = 50; type TAG_ANY = "im.vector.any"; // eslint-disable-line @typescript-eslint/naming-convention const TAG_ANY: TAG_ANY = "im.vector.any"; -interface IState { - // Empty because we don't actually use the state -} - export interface MessagePreview { event: MatrixEvent; isThreadReply: boolean; @@ -117,7 +121,7 @@ const mkMessagePreview = (text: string, event: MatrixEvent): MessagePreview => { }; }; -export class MessagePreviewStore extends AsyncStoreWithClient { +export class MessagePreviewStore extends AsyncStoreWithClient { private static readonly internalInstance = (() => { const instance = new MessagePreviewStore(); instance.start(); diff --git a/src/stores/room-list/RoomListLayoutStore.ts b/src/stores/room-list/RoomListLayoutStore.ts index 90461a581c..f739554b82 100644 --- a/src/stores/room-list/RoomListLayoutStore.ts +++ b/src/stores/room-list/RoomListLayoutStore.ts @@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details. */ import { logger } from "matrix-js-sdk/src/logger"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import { TagID } from "./models"; import { ListLayout } from "./ListLayout"; @@ -14,9 +15,7 @@ import { AsyncStoreWithClient } from "../AsyncStoreWithClient"; import defaultDispatcher from "../../dispatcher/dispatcher"; import { ActionPayload } from "../../dispatcher/payloads"; -interface IState {} - -export default class RoomListLayoutStore extends AsyncStoreWithClient { +export default class RoomListLayoutStore extends AsyncStoreWithClient { private static internalInstance: RoomListLayoutStore; private readonly layoutMap = new Map(); diff --git a/src/stores/room-list/RoomListStore.ts b/src/stores/room-list/RoomListStore.ts index 0b179f7db5..bb48ec5e18 100644 --- a/src/stores/room-list/RoomListStore.ts +++ b/src/stores/room-list/RoomListStore.ts @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { MatrixClient, Room, RoomState, EventType } from "matrix-js-sdk/src/matrix"; +import { MatrixClient, Room, RoomState, EventType, EmptyObject } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; import { logger } from "matrix-js-sdk/src/logger"; @@ -32,14 +32,10 @@ import { UPDATE_EVENT } from "../AsyncStore"; import { SdkContextClass } from "../../contexts/SDKContext"; import { getChangedOverrideRoomMutePushRules } from "./utils/roomMute"; -interface IState { - // state is tracked in underlying classes -} - export const LISTS_UPDATE_EVENT = RoomListStoreEvent.ListsUpdate; export const LISTS_LOADING_EVENT = RoomListStoreEvent.ListsLoading; // unused; used by SlidingRoomListStore -export class RoomListStoreClass extends AsyncStoreWithClient implements Interface { +export class RoomListStoreClass extends AsyncStoreWithClient implements Interface { /** * Set to true if you're running tests on the store. Should not be touched in * any other environment. diff --git a/src/stores/room-list/SlidingRoomListStore.ts b/src/stores/room-list/SlidingRoomListStore.ts index ba585f3218..626ac5dc6a 100644 --- a/src/stores/room-list/SlidingRoomListStore.ts +++ b/src/stores/room-list/SlidingRoomListStore.ts @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { Room } from "matrix-js-sdk/src/matrix"; +import { EmptyObject, Room } from "matrix-js-sdk/src/matrix"; import { logger } from "matrix-js-sdk/src/logger"; import { MSC3575Filter, SlidingSyncEvent } from "matrix-js-sdk/src/sliding-sync"; import { Optional } from "matrix-events-sdk"; @@ -23,10 +23,6 @@ import { LISTS_LOADING_EVENT } from "./RoomListStore"; import { UPDATE_EVENT } from "../AsyncStore"; import { SdkContextClass } from "../../contexts/SDKContext"; -interface IState { - // state is tracked in underlying classes -} - export const SlidingSyncSortToFilter: Record = { [SortAlgorithm.Alphabetic]: ["by_name", "by_recency"], [SortAlgorithm.Recent]: ["by_notification_level", "by_recency"], @@ -66,7 +62,7 @@ const filterConditions: Record = { export const LISTS_UPDATE_EVENT = RoomListStoreEvent.ListsUpdate; -export class SlidingRoomListStoreClass extends AsyncStoreWithClient implements Interface { +export class SlidingRoomListStoreClass extends AsyncStoreWithClient implements Interface { private tagIdToSortAlgo: Record = {}; private tagMap: ITagMap = {}; private counts: Record = {}; diff --git a/src/stores/spaces/SpaceStore.ts b/src/stores/spaces/SpaceStore.ts index 50aa7748a5..9ee877ec3f 100644 --- a/src/stores/spaces/SpaceStore.ts +++ b/src/stores/spaces/SpaceStore.ts @@ -17,6 +17,7 @@ import { MatrixEvent, ClientEvent, ISendEventResponse, + EmptyObject, } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; import { logger } from "matrix-js-sdk/src/logger"; @@ -63,8 +64,6 @@ import { SwitchSpacePayload } from "../../dispatcher/payloads/SwitchSpacePayload import { AfterLeaveRoomPayload } from "../../dispatcher/payloads/AfterLeaveRoomPayload"; import { SdkContextClass } from "../../contexts/SDKContext"; -interface IState {} - const ACTIVE_SPACE_LS_KEY = "mx_active_space"; const metaSpaceOrder: MetaSpace[] = [ @@ -123,7 +122,7 @@ type SpaceStoreActions = | SwitchSpacePayload | AfterLeaveRoomPayload; -export class SpaceStoreClass extends AsyncStoreWithClient { +export class SpaceStoreClass extends AsyncStoreWithClient { // The spaces representing the roots of the various tree-like hierarchies private rootSpaces: Room[] = []; // Map from room/space ID to set of spaces which list it as a child diff --git a/src/stores/widgets/WidgetMessagingStore.ts b/src/stores/widgets/WidgetMessagingStore.ts index f73fd15c51..d42c499226 100644 --- a/src/stores/widgets/WidgetMessagingStore.ts +++ b/src/stores/widgets/WidgetMessagingStore.ts @@ -7,6 +7,7 @@ */ import { ClientWidgetApi, Widget } from "matrix-widget-api"; +import { EmptyObject } from "matrix-js-sdk/src/matrix"; import { AsyncStoreWithClient } from "../AsyncStoreWithClient"; import defaultDispatcher from "../../dispatcher/dispatcher"; @@ -24,7 +25,7 @@ export enum WidgetMessagingStoreEvent { * going to be merged with a more complete WidgetStore, but for now it's * easiest to split this into a single place. */ -export class WidgetMessagingStore extends AsyncStoreWithClient<{}> { +export class WidgetMessagingStore extends AsyncStoreWithClient { private static readonly internalInstance = (() => { const instance = new WidgetMessagingStore(); instance.start(); diff --git a/src/utils/MultiInviter.ts b/src/utils/MultiInviter.ts index 1350eb94a4..c42284db45 100644 --- a/src/utils/MultiInviter.ts +++ b/src/utils/MultiInviter.ts @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { MatrixError, MatrixClient, EventType } from "matrix-js-sdk/src/matrix"; +import { MatrixError, MatrixClient, EventType, EmptyObject } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; import { defer, IDeferred } from "matrix-js-sdk/src/utils"; import { logger } from "matrix-js-sdk/src/logger"; @@ -117,7 +117,7 @@ export default class MultiInviter { return this.errors[addr]?.errorText ?? null; } - private async inviteToRoom(roomId: string, addr: string, ignoreProfile = false): Promise<{}> { + private async inviteToRoom(roomId: string, addr: string, ignoreProfile = false): Promise { const addrType = getAddressType(addr); if (addrType === AddressType.Email) { diff --git a/src/utils/PinningUtils.ts b/src/utils/PinningUtils.ts index a1304598f7..40ab66160d 100644 --- a/src/utils/PinningUtils.ts +++ b/src/utils/PinningUtils.ts @@ -6,7 +6,15 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { MatrixEvent, EventType, M_POLL_START, MatrixClient, EventTimeline, Room } from "matrix-js-sdk/src/matrix"; +import { + MatrixEvent, + EventType, + M_POLL_START, + MatrixClient, + EventTimeline, + Room, + EmptyObject, +} from "matrix-js-sdk/src/matrix"; import { isContentActionable } from "./EventUtils"; import { ReadPinsEventId } from "../components/views/right_panel/types"; @@ -123,7 +131,7 @@ export default class PinningUtils { ?.getStateEvents(EventType.RoomPinnedEvents, "") ?.getContent().pinned || []; - let roomAccountDataPromise: Promise<{} | void> = Promise.resolve(); + let roomAccountDataPromise: Promise = Promise.resolve(); // If the event is already pinned, unpin it if (pinnedIds.includes(eventId)) { pinnedIds.splice(pinnedIds.indexOf(eventId), 1); diff --git a/src/utils/notifications.ts b/src/utils/notifications.ts index 9119ef9bcb..d0dfa8ffa6 100644 --- a/src/utils/notifications.ts +++ b/src/utils/notifications.ts @@ -14,6 +14,7 @@ import { LocalNotificationSettings, ReceiptType, IMarkedUnreadEvent, + EmptyObject, } from "matrix-js-sdk/src/matrix"; import { IndicatorIcon } from "@vector-im/compound-web"; @@ -80,7 +81,7 @@ export function localNotificationsAreSilenced(cli: MatrixClient): boolean { * @param client * @returns a promise that resolves when the room has been marked as read */ -export async function clearRoomNotification(room: Room, client: MatrixClient): Promise<{} | undefined> { +export async function clearRoomNotification(room: Room, client: MatrixClient): Promise { const lastEvent = room.getLastLiveEvent(); await setMarkedUnreadState(room, client, false); @@ -115,15 +116,17 @@ export async function clearRoomNotification(room: Room, client: MatrixClient): P * @param client The matrix client * @returns a promise that resolves when all rooms have been marked as read */ -export function clearAllNotifications(client: MatrixClient): Promise> { - const receiptPromises = client.getRooms().reduce((promises: Array>, room: Room) => { - if (doesRoomHaveUnreadMessages(room, true)) { - const promise = clearRoomNotification(room, client); - promises.push(promise); - } +export function clearAllNotifications(client: MatrixClient): Promise> { + const receiptPromises = client + .getRooms() + .reduce((promises: Array>, room: Room) => { + if (doesRoomHaveUnreadMessages(room, true)) { + const promise = clearRoomNotification(room, client); + promises.push(promise); + } - return promises; - }, []); + return promises; + }, []); return Promise.all(receiptPromises); } diff --git a/src/utils/objects.ts b/src/utils/objects.ts index a919699eac..60bf702404 100644 --- a/src/utils/objects.ts +++ b/src/utils/objects.ts @@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details. import { arrayDiff, arrayUnion, arrayIntersection } from "./arrays"; -type ObjectExcluding = { [k in Exclude]: O[k] }; +type ObjectExcluding = { [k in Exclude]: O[k] }; /** * Gets a new object which represents the provided object, excluding some properties. @@ -16,7 +16,7 @@ type ObjectExcluding = { [k in Exclude>(a: O, props: P): ObjectExcluding { +export function objectExcluding>(a: O, props: P): ObjectExcluding { // We use a Map to avoid hammering the `delete` keyword, which is slow and painful. const tempMap = new Map(Object.entries(a) as [keyof O, any][]); for (const prop of props) { @@ -37,7 +37,7 @@ export function objectExcluding>(a: O, pr * @param props The property names to keep. * @returns The new object with only the provided properties. */ -export function objectWithOnly>(a: O, props: P): { [k in P[number]]: O[k] } { +export function objectWithOnly>(a: O, props: P): { [k in P[number]]: O[k] } { const existingProps = Object.keys(a) as (keyof O)[]; const diff = arrayDiff(existingProps, props); if (diff.removed.length === 0) { @@ -58,7 +58,7 @@ export function objectWithOnly>(a: O, pro * First argument is the property key with the second being the current value. * @returns A cloned object. */ -export function objectShallowClone(a: O, propertyCloner?: (k: keyof O, v: O[keyof O]) => any): O { +export function objectShallowClone(a: O, propertyCloner?: (k: keyof O, v: O[keyof O]) => any): O { const newObj = {} as O; for (const [k, v] of Object.entries(a) as [keyof O, O[keyof O]][]) { newObj[k] = v; @@ -77,7 +77,7 @@ export function objectShallowClone(a: O, propertyCloner?: (k: keyo * @param b The second object. Must be defined. * @returns True if there's a difference between the objects, false otherwise */ -export function objectHasDiff(a: O, b: O): boolean { +export function objectHasDiff(a: O, b: O): boolean { if (a === b) return false; const aKeys = Object.keys(a); const bKeys = Object.keys(b); @@ -99,7 +99,7 @@ type Diff = { changed: K[]; added: K[]; removed: K[] }; * @param b The second object. Must be defined. * @returns The difference between the keys of each object. */ -export function objectDiff(a: O, b: O): Diff { +export function objectDiff(a: O, b: O): Diff { const aKeys = Object.keys(a) as (keyof O)[]; const bKeys = Object.keys(b) as (keyof O)[]; const keyDiff = arrayDiff(aKeys, bKeys); @@ -118,7 +118,7 @@ export function objectDiff(a: O, b: O): Diff { * @returns The keys which have been added, removed, or changed between the * two objects. */ -export function objectKeyChanges(a: O, b: O): (keyof O)[] { +export function objectKeyChanges(a: O, b: O): (keyof O)[] { const diff = objectDiff(a, b); return arrayUnion(diff.removed, diff.added, diff.changed); } @@ -130,7 +130,7 @@ export function objectKeyChanges(a: O, b: O): (keyof O)[] { * @param obj The object to clone. * @returns The cloned object */ -export function objectClone(obj: O): O { +export function objectClone(obj: O): O { return JSON.parse(JSON.stringify(obj)); } diff --git a/src/vector/app.tsx b/src/vector/app.tsx index 2ae9e6fa03..12d8173d5f 100644 --- a/src/vector/app.tsx +++ b/src/vector/app.tsx @@ -17,6 +17,7 @@ import { logger } from "matrix-js-sdk/src/logger"; import { createClient, AutoDiscovery, ClientConfig } from "matrix-js-sdk/src/matrix"; import { WrapperLifecycle, WrapperOpts } from "@matrix-org/react-sdk-module-api/lib/lifecycles/WrapperLifecycle"; +import type { QueryDict } from "matrix-js-sdk/src/utils"; import PlatformPeg from "../PlatformPeg"; import AutoDiscoveryUtils from "../utils/AutoDiscoveryUtils"; import * as Lifecycle from "../Lifecycle"; @@ -54,7 +55,7 @@ function onTokenLoginCompleted(): void { window.history.replaceState(null, "", url.href); } -export async function loadApp(fragParams: {}, matrixChatRef: React.Ref): Promise { +export async function loadApp(fragParams: QueryDict, matrixChatRef: React.Ref): Promise { initRouting(); const platform = PlatformPeg.get(); diff --git a/src/vector/init.tsx b/src/vector/init.tsx index bb4a128d80..9a2f1c1196 100644 --- a/src/vector/init.tsx +++ b/src/vector/init.tsx @@ -12,6 +12,7 @@ import { createRoot } from "react-dom/client"; import React, { StrictMode } from "react"; import { logger } from "matrix-js-sdk/src/logger"; +import type { QueryDict } from "matrix-js-sdk/src/utils"; import * as languageHandler from "../languageHandler"; import SettingsStore from "../settings/SettingsStore"; import PlatformPeg from "../PlatformPeg"; @@ -83,7 +84,7 @@ export async function loadTheme(): Promise { return setTheme(); } -export async function loadApp(fragParams: {}): Promise { +export async function loadApp(fragParams: QueryDict): Promise { // load app.js async so that its code is not executed immediately and we can catch any exceptions const module = await import( /* webpackChunkName: "element-web-app" */ diff --git a/src/vector/platform/IPCManager.ts b/src/vector/platform/IPCManager.ts index 7d329b8b2c..5b8af55df8 100644 --- a/src/vector/platform/IPCManager.ts +++ b/src/vector/platform/IPCManager.ts @@ -40,7 +40,7 @@ export class IPCManager { return deferred.promise; } - private onIpcReply = (_ev: {}, payload: IPCPayload): void => { + private onIpcReply = (_ev: Event, payload: IPCPayload): void => { if (payload.id === undefined) { logger.warn("Ignoring IPC reply with no ID"); return; diff --git a/test/unit-tests/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx index d9d7cb48b1..17bc426a40 100644 --- a/test/unit-tests/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx +++ b/test/unit-tests/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx @@ -14,10 +14,7 @@ import SettingsStore from "../../../../../../../src/settings/SettingsStore"; import SdkConfig from "../../../../../../../src/SdkConfig"; describe("", () => { - const defaultProps = { - closeSettingsFn: jest.fn(), - }; - const getComponent = () => ; + const getComponent = () => ; const settingsValueSpy = jest.spyOn(SettingsStore, "getValue"); diff --git a/test/unit-tests/components/views/settings/tabs/user/SessionManagerTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/SessionManagerTab-test.tsx index f334c6b28f..193c77448d 100644 --- a/test/unit-tests/components/views/settings/tabs/user/SessionManagerTab-test.tsx +++ b/test/unit-tests/components/views/settings/tabs/user/SessionManagerTab-test.tsx @@ -1104,8 +1104,9 @@ describe("", () => { // because promise flushing after the confirm modal is resolving this too // and we want to test the loading state here const resolveDeleteRequest = defer(); - mockClient.deleteMultipleDevices.mockImplementation(() => { - return resolveDeleteRequest.promise; + mockClient.deleteMultipleDevices.mockImplementation(async () => { + await resolveDeleteRequest.promise; + return {}; }); const { getByTestId } = render(getComponent()); diff --git a/test/unit-tests/hooks/useProfileInfo-test.tsx b/test/unit-tests/hooks/useProfileInfo-test.tsx index e42dcb1858..1b3c4b5980 100644 --- a/test/unit-tests/hooks/useProfileInfo-test.tsx +++ b/test/unit-tests/hooks/useProfileInfo-test.tsx @@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details. */ import { waitFor, renderHook, act } from "jest-matrix-react"; -import { MatrixClient } from "matrix-js-sdk/src/matrix"; +import { EmptyObject, MatrixClient } from "matrix-js-sdk/src/matrix"; import { useProfileInfo } from "../../../src/hooks/useProfileInfo"; import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; @@ -93,7 +93,7 @@ describe("useProfileInfo", () => { }); it("should be able to handle an empty result", async () => { - cli.getProfileInfo = () => null as unknown as Promise<{}>; + cli.getProfileInfo = () => null as unknown as Promise; const query = "@user:home.server"; const { result } = render(); From d9001d177c2d23c09e3d6d0f8dda6787fde29fbc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 14:27:20 +0000 Subject: [PATCH 5/5] Update docker/build-push-action digest to ca877d9 (#29172) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/dockerhub.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dockerhub.yaml b/.github/workflows/dockerhub.yaml index 90a892ed8b..28ed6a6304 100644 --- a/.github/workflows/dockerhub.yaml +++ b/.github/workflows/dockerhub.yaml @@ -51,7 +51,7 @@ jobs: - name: Build and push id: build-and-push - uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6 + uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6 with: context: . push: true