mirror of https://github.com/vector-im/riot-web
Use mapped types around account data events (#28752)
* Use mapped types around account data events --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>pull/28776/head
parent
baaed75c4b
commit
be181d2c79
|
@ -81,7 +81,7 @@ test.describe("Cryptography", function () {
|
||||||
* Verify that the `m.cross_signing.${keyType}` key is available on the account data on the server
|
* Verify that the `m.cross_signing.${keyType}` key is available on the account data on the server
|
||||||
* @param keyType
|
* @param keyType
|
||||||
*/
|
*/
|
||||||
async function verifyKey(app: ElementAppPage, keyType: string) {
|
async function verifyKey(app: ElementAppPage, keyType: "master" | "self_signing" | "user_signing") {
|
||||||
const accountData: { encrypted: Record<string, Record<string, string>> } = await app.client.evaluate(
|
const accountData: { encrypted: Record<string, Record<string, string>> } = await app.client.evaluate(
|
||||||
(cli, keyType) => cli.getAccountDataFromServer(`m.cross_signing.${keyType}`),
|
(cli, keyType) => cli.getAccountDataFromServer(`m.cross_signing.${keyType}`),
|
||||||
keyType,
|
keyType,
|
||||||
|
|
|
@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details.
|
||||||
import type { Page } from "@playwright/test";
|
import type { Page } from "@playwright/test";
|
||||||
import { test, expect } from "../../element-web-test";
|
import { test, expect } from "../../element-web-test";
|
||||||
import { openIntegrationManager } from "./utils";
|
import { openIntegrationManager } from "./utils";
|
||||||
|
import type { UserWidget } from "../../../src/utils/WidgetUtils-types.ts";
|
||||||
|
|
||||||
const ROOM_NAME = "Integration Manager Test";
|
const ROOM_NAME = "Integration Manager Test";
|
||||||
|
|
||||||
|
@ -92,7 +93,7 @@ test.describe("Integration Manager: Get OpenID Token", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
id: "integration-manager",
|
id: "integration-manager",
|
||||||
},
|
} as unknown as UserWidget,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Succeed when checking the token is valid
|
// Succeed when checking the token is valid
|
||||||
|
|
|
@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details.
|
||||||
import type { Page } from "@playwright/test";
|
import type { Page } from "@playwright/test";
|
||||||
import { test, expect } from "../../element-web-test";
|
import { test, expect } from "../../element-web-test";
|
||||||
import { openIntegrationManager } from "./utils";
|
import { openIntegrationManager } from "./utils";
|
||||||
|
import type { UserWidget } from "../../../src/utils/WidgetUtils-types.ts";
|
||||||
|
|
||||||
const ROOM_NAME = "Integration Manager Test";
|
const ROOM_NAME = "Integration Manager Test";
|
||||||
const USER_DISPLAY_NAME = "Alice";
|
const USER_DISPLAY_NAME = "Alice";
|
||||||
|
@ -136,7 +137,7 @@ test.describe("Integration Manager: Kick", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
id: "integration-manager",
|
id: "integration-manager",
|
||||||
},
|
} as unknown as UserWidget,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Succeed when checking the token is valid
|
// Succeed when checking the token is valid
|
||||||
|
|
|
@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details.
|
||||||
import type { Page } from "@playwright/test";
|
import type { Page } from "@playwright/test";
|
||||||
import { test, expect } from "../../element-web-test";
|
import { test, expect } from "../../element-web-test";
|
||||||
import { openIntegrationManager } from "./utils";
|
import { openIntegrationManager } from "./utils";
|
||||||
|
import type { UserWidget } from "../../../src/utils/WidgetUtils-types.ts";
|
||||||
|
|
||||||
const ROOM_NAME = "Integration Manager Test";
|
const ROOM_NAME = "Integration Manager Test";
|
||||||
|
|
||||||
|
@ -107,7 +108,7 @@ test.describe("Integration Manager: Read Events", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
id: "integration-manager",
|
id: "integration-manager",
|
||||||
},
|
} as unknown as UserWidget,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Succeed when checking the token is valid
|
// Succeed when checking the token is valid
|
||||||
|
|
|
@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details.
|
||||||
import type { Page } from "@playwright/test";
|
import type { Page } from "@playwright/test";
|
||||||
import { test, expect } from "../../element-web-test";
|
import { test, expect } from "../../element-web-test";
|
||||||
import { openIntegrationManager } from "./utils";
|
import { openIntegrationManager } from "./utils";
|
||||||
|
import type { UserWidget } from "../../../src/utils/WidgetUtils-types.ts";
|
||||||
|
|
||||||
const ROOM_NAME = "Integration Manager Test";
|
const ROOM_NAME = "Integration Manager Test";
|
||||||
|
|
||||||
|
@ -113,7 +114,7 @@ test.describe("Integration Manager: Send Event", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
id: "integration-manager",
|
id: "integration-manager",
|
||||||
},
|
} as unknown as UserWidget,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Succeed when checking the token is valid
|
// Succeed when checking the token is valid
|
||||||
|
|
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||||
Please see LICENSE files in the repository root for full details.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { EventType } from "matrix-js-sdk/src/matrix";
|
import type { AccountDataEvents } from "matrix-js-sdk/src/matrix";
|
||||||
import { test, expect } from "../../element-web-test";
|
import { test, expect } from "../../element-web-test";
|
||||||
import { Bot } from "../../pages/bot";
|
import { Bot } from "../../pages/bot";
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ test.describe("Room Directory", () => {
|
||||||
const charlieRoom = await cli.createRoom({ is_direct: true });
|
const charlieRoom = await cli.createRoom({ is_direct: true });
|
||||||
await cli.invite(bobRoom.room_id, bob);
|
await cli.invite(bobRoom.room_id, bob);
|
||||||
await cli.invite(charlieRoom.room_id, charlie);
|
await cli.invite(charlieRoom.room_id, charlie);
|
||||||
await cli.setAccountData("m.direct" as EventType, {
|
await cli.setAccountData("m.direct" as keyof AccountDataEvents, {
|
||||||
[bob]: [bobRoom.room_id],
|
[bob]: [bobRoom.room_id],
|
||||||
[charlie]: [charlieRoom.room_id],
|
[charlie]: [charlieRoom.room_id],
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||||
Please see LICENSE files in the repository root for full details.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type { AccountDataEvents } from "matrix-js-sdk/src/matrix";
|
||||||
import { test, expect } from "../../element-web-test";
|
import { test, expect } from "../../element-web-test";
|
||||||
import { Filter } from "../../pages/Spotlight";
|
import { Filter } from "../../pages/Spotlight";
|
||||||
import { Bot } from "../../pages/bot";
|
import { Bot } from "../../pages/bot";
|
||||||
|
@ -255,7 +256,9 @@ test.describe("Spotlight", () => {
|
||||||
|
|
||||||
// Invite BotBob into existing DM with ByteBot
|
// Invite BotBob into existing DM with ByteBot
|
||||||
const dmRooms = await app.client.evaluate((client, userId) => {
|
const dmRooms = await app.client.evaluate((client, userId) => {
|
||||||
const map = client.getAccountData("m.direct")?.getContent<Record<string, string[]>>();
|
const map = client
|
||||||
|
.getAccountData("m.direct" as keyof AccountDataEvents)
|
||||||
|
?.getContent<Record<string, string[]>>();
|
||||||
return map[userId] ?? [];
|
return map[userId] ?? [];
|
||||||
}, bot2UserId);
|
}, bot2UserId);
|
||||||
expect(dmRooms).toHaveLength(1);
|
expect(dmRooms).toHaveLength(1);
|
||||||
|
|
|
@ -12,6 +12,7 @@ import type { Page } from "@playwright/test";
|
||||||
import { test, expect } from "../../element-web-test";
|
import { test, expect } from "../../element-web-test";
|
||||||
import { ElementAppPage } from "../../pages/ElementAppPage";
|
import { ElementAppPage } from "../../pages/ElementAppPage";
|
||||||
import { Credentials } from "../../plugins/homeserver";
|
import { Credentials } from "../../plugins/homeserver";
|
||||||
|
import type { UserWidget } from "../../../src/utils/WidgetUtils-types.ts";
|
||||||
|
|
||||||
const STICKER_PICKER_WIDGET_ID = "fake-sticker-picker";
|
const STICKER_PICKER_WIDGET_ID = "fake-sticker-picker";
|
||||||
const STICKER_PICKER_WIDGET_NAME = "Fake Stickers";
|
const STICKER_PICKER_WIDGET_NAME = "Fake Stickers";
|
||||||
|
@ -123,7 +124,7 @@ async function setWidgetAccountData(
|
||||||
state_key: STICKER_PICKER_WIDGET_ID,
|
state_key: STICKER_PICKER_WIDGET_ID,
|
||||||
type: "m.widget",
|
type: "m.widget",
|
||||||
id: STICKER_PICKER_WIDGET_ID,
|
id: STICKER_PICKER_WIDGET_ID,
|
||||||
},
|
} as unknown as UserWidget,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import type {
|
||||||
Upload,
|
Upload,
|
||||||
StateEvents,
|
StateEvents,
|
||||||
TimelineEvents,
|
TimelineEvents,
|
||||||
|
AccountDataEvents,
|
||||||
} from "matrix-js-sdk/src/matrix";
|
} from "matrix-js-sdk/src/matrix";
|
||||||
import type { RoomMessageEventContent } from "matrix-js-sdk/src/types";
|
import type { RoomMessageEventContent } from "matrix-js-sdk/src/types";
|
||||||
import { Credentials } from "../plugins/homeserver";
|
import { Credentials } from "../plugins/homeserver";
|
||||||
|
@ -439,11 +440,14 @@ export class Client {
|
||||||
* @param type The type of account data to set
|
* @param type The type of account data to set
|
||||||
* @param content The content to set
|
* @param content The content to set
|
||||||
*/
|
*/
|
||||||
public async setAccountData(type: string, content: IContent): Promise<void> {
|
public async setAccountData<T extends keyof AccountDataEvents>(
|
||||||
|
type: T,
|
||||||
|
content: AccountDataEvents[T],
|
||||||
|
): Promise<void> {
|
||||||
const client = await this.prepareClient();
|
const client = await this.prepareClient();
|
||||||
return client.evaluate(
|
return client.evaluate(
|
||||||
async (client, { type, content }) => {
|
async (client, { type, content }) => {
|
||||||
await client.setAccountData(type, content);
|
await client.setAccountData(type as T, content as AccountDataEvents[T]);
|
||||||
},
|
},
|
||||||
{ type, content },
|
{ type, content },
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,6 +11,8 @@ import type { BLURHASH_FIELD } from "../utils/image-media";
|
||||||
import type { JitsiCallMemberEventType, JitsiCallMemberContent } from "../call-types";
|
import type { JitsiCallMemberEventType, JitsiCallMemberContent } from "../call-types";
|
||||||
import type { ILayoutStateEvent, WIDGET_LAYOUT_EVENT_TYPE } from "../stores/widgets/types";
|
import type { ILayoutStateEvent, WIDGET_LAYOUT_EVENT_TYPE } from "../stores/widgets/types";
|
||||||
import type { EncryptedFile } from "matrix-js-sdk/src/types";
|
import type { EncryptedFile } from "matrix-js-sdk/src/types";
|
||||||
|
import type { DeviceClientInformation } from "../utils/device/types.ts";
|
||||||
|
import type { UserWidget } from "../utils/WidgetUtils-types.ts";
|
||||||
|
|
||||||
// Extend Matrix JS SDK types via Typescript declaration merging to support unspecced event fields and types
|
// Extend Matrix JS SDK types via Typescript declaration merging to support unspecced event fields and types
|
||||||
declare module "matrix-js-sdk/src/types" {
|
declare module "matrix-js-sdk/src/types" {
|
||||||
|
@ -57,6 +59,35 @@ declare module "matrix-js-sdk/src/types" {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AccountDataEvents {
|
||||||
|
// Analytics account data event
|
||||||
|
"im.vector.analytics": {
|
||||||
|
id: string;
|
||||||
|
pseudonymousAnalyticsOptIn?: boolean;
|
||||||
|
};
|
||||||
|
// Device client information account data event
|
||||||
|
[key: `io.element.matrix_client_information.${string}`]: DeviceClientInformation;
|
||||||
|
// Element settings account data events
|
||||||
|
"im.vector.setting.breadcrumbs": { recent_rooms: string[] };
|
||||||
|
"io.element.recent_emoji": { recent_emoji: string[] };
|
||||||
|
"im.vector.setting.integration_provisioning": { enabled: boolean };
|
||||||
|
"im.vector.riot.breadcrumb_rooms": { recent_rooms: string[] };
|
||||||
|
"im.vector.web.settings": Record<string, any>;
|
||||||
|
|
||||||
|
// URL preview account data event
|
||||||
|
"org.matrix.preview_urls": { disable: boolean };
|
||||||
|
|
||||||
|
// This is not yet in the Matrix spec yet is being used as if it was
|
||||||
|
"m.widgets": {
|
||||||
|
[widgetId: string]: UserWidget;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is not in the Matrix spec yet seems to use an `m.` prefix
|
||||||
|
"m.accepted_terms": {
|
||||||
|
accepted: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export interface AudioContent {
|
export interface AudioContent {
|
||||||
// MSC1767 + Ideals of MSC2516 as MSC3245
|
// MSC1767 + Ideals of MSC2516 as MSC3245
|
||||||
// https://github.com/matrix-org/matrix-doc/pull/3245
|
// https://github.com/matrix-org/matrix-doc/pull/3245
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
IUsageLimit,
|
IUsageLimit,
|
||||||
SyncStateData,
|
SyncStateData,
|
||||||
SyncState,
|
SyncState,
|
||||||
|
EventType,
|
||||||
} from "matrix-js-sdk/src/matrix";
|
} from "matrix-js-sdk/src/matrix";
|
||||||
import { MatrixCall } from "matrix-js-sdk/src/webrtc/call";
|
import { MatrixCall } from "matrix-js-sdk/src/webrtc/call";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
@ -161,7 +162,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
this._matrixClient.on(ClientEvent.AccountData, this.onAccountData);
|
this._matrixClient.on(ClientEvent.AccountData, this.onAccountData);
|
||||||
// check push rules on start up as well
|
// check push rules on start up as well
|
||||||
monitorSyncedPushRules(this._matrixClient.getAccountData("m.push_rules"), this._matrixClient);
|
monitorSyncedPushRules(this._matrixClient.getAccountData(EventType.PushRules), this._matrixClient);
|
||||||
this._matrixClient.on(ClientEvent.Sync, this.onSync);
|
this._matrixClient.on(ClientEvent.Sync, this.onSync);
|
||||||
// Call `onSync` with the current state as well
|
// Call `onSync` with the current state as well
|
||||||
this.onSync(this._matrixClient.getSyncState(), null, this._matrixClient.getSyncStateData() ?? undefined);
|
this.onSync(this._matrixClient.getSyncState(), null, this._matrixClient.getSyncStateData() ?? undefined);
|
||||||
|
|
|
@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useContext, useMemo, useState } from "react";
|
import React, { useContext, useMemo, useState } from "react";
|
||||||
import { IContent, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
import { AccountDataEvents, IContent, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
|
import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
|
||||||
import MatrixClientContext from "../../../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../../../contexts/MatrixClientContext";
|
||||||
|
@ -21,7 +21,7 @@ export const AccountDataEventEditor: React.FC<IEditorProps> = ({ mxEvent, onBack
|
||||||
|
|
||||||
const fields = useMemo(() => [eventTypeField(mxEvent?.getType())], [mxEvent]);
|
const fields = useMemo(() => [eventTypeField(mxEvent?.getType())], [mxEvent]);
|
||||||
|
|
||||||
const onSend = async ([eventType]: string[], content?: IContent): Promise<void> => {
|
const onSend = async ([eventType]: Array<keyof AccountDataEvents>, content?: IContent): Promise<void> => {
|
||||||
await cli.setAccountData(eventType, content || {});
|
await cli.setAccountData(eventType, content || {});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ export const useOwnDevices = (): DevicesState => {
|
||||||
|
|
||||||
const notificationSettings = new Map<string, LocalNotificationSettings>();
|
const notificationSettings = new Map<string, LocalNotificationSettings>();
|
||||||
Object.keys(devices).forEach((deviceId) => {
|
Object.keys(devices).forEach((deviceId) => {
|
||||||
const eventType = `${LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${deviceId}`;
|
const eventType = `${LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${deviceId}` as const;
|
||||||
const event = matrixClient.getAccountData(eventType);
|
const event = matrixClient.getAccountData(eventType);
|
||||||
if (event) {
|
if (event) {
|
||||||
notificationSettings.set(deviceId, event.getContent());
|
notificationSettings.set(deviceId, event.getContent());
|
||||||
|
|
|
@ -7,14 +7,14 @@ Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { ClientEvent, MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
import { AccountDataEvents, ClientEvent, MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { useTypedEventEmitter } from "./useEventEmitter";
|
import { useTypedEventEmitter } from "./useEventEmitter";
|
||||||
|
|
||||||
const tryGetContent = <T extends {}>(ev?: MatrixEvent): T | undefined => ev?.getContent<T>();
|
const tryGetContent = <T extends {}>(ev?: MatrixEvent): T | undefined => ev?.getContent<T>();
|
||||||
|
|
||||||
// Hook to simplify listening to Matrix account data
|
// Hook to simplify listening to Matrix account data
|
||||||
export const useAccountData = <T extends {}>(cli: MatrixClient, eventType: string): T => {
|
export const useAccountData = <T extends {}>(cli: MatrixClient, eventType: keyof AccountDataEvents): T => {
|
||||||
const [value, setValue] = useState<T | undefined>(() => tryGetContent<T>(cli.getAccountData(eventType)));
|
const [value, setValue] = useState<T | undefined>(() => tryGetContent<T>(cli.getAccountData(eventType)));
|
||||||
|
|
||||||
const handler = useCallback(
|
const handler = useCallback(
|
||||||
|
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||||
Please see LICENSE files in the repository root for full details.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ClientEvent, MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
import { AccountDataEvents, ClientEvent, MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||||
import { defer } from "matrix-js-sdk/src/utils";
|
import { defer } from "matrix-js-sdk/src/utils";
|
||||||
import { isEqual } from "lodash";
|
import { isEqual } from "lodash";
|
||||||
|
|
||||||
|
@ -140,11 +140,11 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function to set account data then await it being echoed back
|
// helper function to set account data then await it being echoed back
|
||||||
private async setAccountData(
|
private async setAccountData<K extends keyof AccountDataEvents, F extends keyof AccountDataEvents[K]>(
|
||||||
eventType: string,
|
eventType: K,
|
||||||
field: string,
|
field: F,
|
||||||
value: any,
|
value: AccountDataEvents[K][F],
|
||||||
legacyEventType?: string,
|
legacyEventType?: keyof AccountDataEvents,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let content = this.getSettings(eventType);
|
let content = this.getSettings(eventType);
|
||||||
if (legacyEventType && !content?.[field]) {
|
if (legacyEventType && !content?.[field]) {
|
||||||
|
@ -161,7 +161,8 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
|
||||||
// which race between different lines.
|
// which race between different lines.
|
||||||
const deferred = defer<void>();
|
const deferred = defer<void>();
|
||||||
const handler = (event: MatrixEvent): void => {
|
const handler = (event: MatrixEvent): void => {
|
||||||
if (event.getType() !== eventType || !isEqual(event.getContent()[field], value)) return;
|
if (event.getType() !== eventType || !isEqual(event.getContent<AccountDataEvents[K]>()[field], value))
|
||||||
|
return;
|
||||||
this.client.off(ClientEvent.AccountData, handler);
|
this.client.off(ClientEvent.AccountData, handler);
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
};
|
};
|
||||||
|
@ -212,7 +213,7 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
|
||||||
return this.client && !this.client.isGuest();
|
return this.client && !this.client.isGuest();
|
||||||
}
|
}
|
||||||
|
|
||||||
private getSettings(eventType = "im.vector.web.settings"): any {
|
private getSettings(eventType: keyof AccountDataEvents = "im.vector.web.settings"): any {
|
||||||
// TODO: [TS] Types on return
|
// TODO: [TS] Types on return
|
||||||
if (!this.client) return null;
|
if (!this.client) return null;
|
||||||
|
|
||||||
|
|
|
@ -17,17 +17,11 @@ import WidgetEchoStore from "../stores/WidgetEchoStore";
|
||||||
import ActiveWidgetStore from "../stores/ActiveWidgetStore";
|
import ActiveWidgetStore from "../stores/ActiveWidgetStore";
|
||||||
import WidgetUtils from "../utils/WidgetUtils";
|
import WidgetUtils from "../utils/WidgetUtils";
|
||||||
import { UPDATE_EVENT } from "./AsyncStore";
|
import { UPDATE_EVENT } from "./AsyncStore";
|
||||||
|
import { IApp } from "../utils/WidgetUtils-types";
|
||||||
|
|
||||||
interface IState {}
|
interface IState {}
|
||||||
|
|
||||||
export interface IApp extends IWidget {
|
export type { IApp };
|
||||||
"roomId": string;
|
|
||||||
"eventId"?: string; // not present on virtual widgets
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
"avatar_url"?: string; // MSC2765 https://github.com/matrix-org/matrix-doc/pull/2765
|
|
||||||
// Whether the widget was created from `widget_build_url` and thus is a call widget of some kind
|
|
||||||
"io.element.managed_hybrid"?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isAppWidget(widget: IWidget | IApp): widget is IApp {
|
export function isAppWidget(widget: IWidget | IApp): widget is IApp {
|
||||||
return "roomId" in widget && typeof widget.roomId === "string";
|
return "roomId" in widget && typeof widget.roomId === "string";
|
||||||
|
|
|
@ -20,7 +20,7 @@ export function setToDefaultIdentityServer(matrixClient: MatrixClient): void {
|
||||||
const url = getDefaultIdentityServerUrl();
|
const url = getDefaultIdentityServerUrl();
|
||||||
// Account data change will update localstorage, client, etc through dispatcher
|
// Account data change will update localstorage, client, etc through dispatcher
|
||||||
matrixClient.setAccountData("m.identity_server", {
|
matrixClient.setAccountData("m.identity_server", {
|
||||||
base_url: url,
|
base_url: url ?? null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
Copyright 2024 New Vector Ltd.
|
||||||
|
Copyright 2017-2020 The Matrix.org Foundation C.I.C.
|
||||||
|
Copyright 2019 Travis Ralston
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||||
|
Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { IWidget } from "matrix-widget-api";
|
||||||
|
|
||||||
|
export interface IApp extends IWidget {
|
||||||
|
"roomId": string;
|
||||||
|
"eventId"?: string; // not present on virtual widgets
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
"avatar_url"?: string; // MSC2765 https://github.com/matrix-org/matrix-doc/pull/2765
|
||||||
|
// Whether the widget was created from `widget_build_url` and thus is a call widget of some kind
|
||||||
|
"io.element.managed_hybrid"?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IWidgetEvent {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
sender: string;
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
state_key: string;
|
||||||
|
content: IApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserWidget extends Omit<IWidgetEvent, "content"> {
|
||||||
|
content: IWidget & Partial<IApp>;
|
||||||
|
}
|
|
@ -29,23 +29,13 @@ import WidgetStore, { IApp, isAppWidget } from "../stores/WidgetStore";
|
||||||
import { parseUrl } from "./UrlUtils";
|
import { parseUrl } from "./UrlUtils";
|
||||||
import { useEventEmitter } from "../hooks/useEventEmitter";
|
import { useEventEmitter } from "../hooks/useEventEmitter";
|
||||||
import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
|
import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
|
||||||
|
import { IWidgetEvent, UserWidget } from "./WidgetUtils-types";
|
||||||
|
|
||||||
// How long we wait for the state event echo to come back from the server
|
// How long we wait for the state event echo to come back from the server
|
||||||
// before waitFor[Room/User]Widget rejects its promise
|
// before waitFor[Room/User]Widget rejects its promise
|
||||||
const WIDGET_WAIT_TIME = 20000;
|
const WIDGET_WAIT_TIME = 20000;
|
||||||
|
|
||||||
export interface IWidgetEvent {
|
export type { IWidgetEvent, UserWidget };
|
||||||
id: string;
|
|
||||||
type: string;
|
|
||||||
sender: string;
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
state_key: string;
|
|
||||||
content: IApp;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserWidget extends Omit<IWidgetEvent, "content"> {
|
|
||||||
content: IWidget & Partial<IApp>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class WidgetUtils {
|
export default class WidgetUtils {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,17 +6,14 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||||
Please see LICENSE files in the repository root for full details.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
import { AccountDataEvents, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import BasePlatform from "../../BasePlatform";
|
import BasePlatform from "../../BasePlatform";
|
||||||
import { IConfigOptions } from "../../IConfigOptions";
|
import { IConfigOptions } from "../../IConfigOptions";
|
||||||
import { DeepReadonly } from "../../@types/common";
|
import { DeepReadonly } from "../../@types/common";
|
||||||
|
import { DeviceClientInformation } from "./types";
|
||||||
|
|
||||||
export type DeviceClientInformation = {
|
export type { DeviceClientInformation };
|
||||||
name?: string;
|
|
||||||
version?: string;
|
|
||||||
url?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const formatUrl = (): string | undefined => {
|
const formatUrl = (): string | undefined => {
|
||||||
// don't record url for electron clients
|
// don't record url for electron clients
|
||||||
|
@ -34,7 +31,8 @@ const formatUrl = (): string | undefined => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const clientInformationEventPrefix = "io.element.matrix_client_information.";
|
const clientInformationEventPrefix = "io.element.matrix_client_information.";
|
||||||
export const getClientInformationEventType = (deviceId: string): string => `${clientInformationEventPrefix}${deviceId}`;
|
export const getClientInformationEventType = (deviceId: string): `${typeof clientInformationEventPrefix}${string}` =>
|
||||||
|
`${clientInformationEventPrefix}${deviceId}`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Record extra client information for the current device
|
* Record extra client information for the current device
|
||||||
|
@ -70,7 +68,7 @@ export const pruneClientInformation = (validDeviceIds: string[], matrixClient: M
|
||||||
}
|
}
|
||||||
const [, deviceId] = event.getType().split(clientInformationEventPrefix);
|
const [, deviceId] = event.getType().split(clientInformationEventPrefix);
|
||||||
if (deviceId && !validDeviceIds.includes(deviceId)) {
|
if (deviceId && !validDeviceIds.includes(deviceId)) {
|
||||||
matrixClient.deleteAccountData(event.getType());
|
matrixClient.deleteAccountData(event.getType() as keyof AccountDataEvents);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
/*
|
||||||
|
Copyright 2024 New Vector Ltd.
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||||
|
Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type DeviceClientInformation = {
|
||||||
|
name?: string;
|
||||||
|
version?: string;
|
||||||
|
url?: string;
|
||||||
|
};
|
|
@ -40,7 +40,9 @@ export const deviceNotificationSettingsKeys = [
|
||||||
"audioNotificationsEnabled",
|
"audioNotificationsEnabled",
|
||||||
];
|
];
|
||||||
|
|
||||||
export function getLocalNotificationAccountDataEventType(deviceId: string | null): string {
|
export function getLocalNotificationAccountDataEventType(
|
||||||
|
deviceId: string | null,
|
||||||
|
): `${typeof LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${string}` {
|
||||||
return `${LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${deviceId}`;
|
return `${LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${deviceId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
IContent,
|
IContent,
|
||||||
MatrixEvent,
|
MatrixEvent,
|
||||||
SyncState,
|
SyncState,
|
||||||
|
AccountDataEvents,
|
||||||
} from "matrix-js-sdk/src/matrix";
|
} from "matrix-js-sdk/src/matrix";
|
||||||
import { waitFor } from "jest-matrix-react";
|
import { waitFor } from "jest-matrix-react";
|
||||||
import { CallMembership, MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
|
import { CallMembership, MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
|
||||||
|
@ -69,7 +70,7 @@ describe("Notifier", () => {
|
||||||
let MockPlatform: MockedObject<BasePlatform>;
|
let MockPlatform: MockedObject<BasePlatform>;
|
||||||
let mockClient: MockedObject<MatrixClient>;
|
let mockClient: MockedObject<MatrixClient>;
|
||||||
let testRoom: Room;
|
let testRoom: Room;
|
||||||
let accountDataEventKey: string;
|
let accountDataEventKey: keyof AccountDataEvents;
|
||||||
let accountDataStore: Record<string, MatrixEvent | undefined> = {};
|
let accountDataStore: Record<string, MatrixEvent | undefined> = {};
|
||||||
|
|
||||||
let mockSettings: Record<string, boolean> = {};
|
let mockSettings: Record<string, boolean> = {};
|
||||||
|
|
|
@ -338,19 +338,18 @@ describe("<RoomSummaryCard />", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not show public room label for a DM", async () => {
|
it("does not show public room label for a DM", async () => {
|
||||||
mockClient.getAccountData.mockImplementation(
|
mockClient.getAccountData.mockImplementation((eventType) => {
|
||||||
(eventType) =>
|
if (eventType === EventType.Direct) {
|
||||||
({
|
return new MatrixEvent({
|
||||||
[EventType.Direct]: new MatrixEvent({
|
type: EventType.Direct,
|
||||||
type: EventType.Direct,
|
content: {
|
||||||
content: {
|
"@bob:sesame.st": ["some-room-id"],
|
||||||
"@bob:sesame.st": ["some-room-id"],
|
// this room is a DM with ernie
|
||||||
// this room is a DM with ernie
|
"@ernie:sesame.st": ["some-other-room-id", room.roomId],
|
||||||
"@ernie:sesame.st": ["some-other-room-id", room.roomId],
|
},
|
||||||
},
|
});
|
||||||
}),
|
}
|
||||||
})[eventType],
|
});
|
||||||
);
|
|
||||||
getComponent();
|
getComponent();
|
||||||
|
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
|
|
|
@ -6,7 +6,14 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||||
Please see LICENSE files in the repository root for full details.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { MatrixEvent, NotificationCountType, Room, MatrixClient, ReceiptType } from "matrix-js-sdk/src/matrix";
|
import {
|
||||||
|
MatrixEvent,
|
||||||
|
NotificationCountType,
|
||||||
|
Room,
|
||||||
|
MatrixClient,
|
||||||
|
ReceiptType,
|
||||||
|
AccountDataEvents,
|
||||||
|
} from "matrix-js-sdk/src/matrix";
|
||||||
import { Mocked, mocked } from "jest-mock";
|
import { Mocked, mocked } from "jest-mock";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -32,7 +39,7 @@ jest.mock("../../../src/settings/SettingsStore");
|
||||||
describe("notifications", () => {
|
describe("notifications", () => {
|
||||||
let accountDataStore: Record<string, MatrixEvent> = {};
|
let accountDataStore: Record<string, MatrixEvent> = {};
|
||||||
let mockClient: Mocked<MatrixClient>;
|
let mockClient: Mocked<MatrixClient>;
|
||||||
let accountDataEventKey: string;
|
let accountDataEventKey: keyof AccountDataEvents;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
|
|
Loading…
Reference in New Issue