Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion playwright/testcontainers/mas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
type StartedPostgreSqlContainer,
} from "@element-hq/element-web-playwright-common/lib/testcontainers";

const TAG = "main@sha256:0a72a3ecb38e961e45062de91a9afa6d8f7319ddba460b8141b4e6a1bab45ea1";
const TAG = "main@sha256:a1a5cf8820660c7bd160e6244791105b832b2c2cfda55bd38569304c0dffc1ba";

/**
* MatrixAuthenticationServiceContainer which freezes the docker digest to
Expand Down
3 changes: 1 addition & 2 deletions src/components/structures/ScrollPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Timer from "../../utils/Timer";
import AutoHideScrollbar from "./AutoHideScrollbar";
import { getKeyBindingsManager } from "../../KeyBindingsManager";
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
import { SDKContext } from "../../contexts/SDKContext";
import type { SDKContext } from "../../contexts/SDKContext";

// The amount of extra scroll distance to allow prior to unfilling.
// See getExcessHeight.
Expand Down Expand Up @@ -184,7 +184,6 @@ export default class ScrollPanel extends React.Component<IProps> {
private heightUpdateInProgress = false;
public divScroll: HTMLDivElement | null = null;

public static contextType = SDKContext;
declare public context: React.ContextType<typeof SDKContext>;

public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) {
Expand Down
4 changes: 4 additions & 0 deletions src/i18n/strings/et.json
Original file line number Diff line number Diff line change
Expand Up @@ -2891,6 +2891,7 @@
"room_list_heading": "Jututubade loend",
"show_avatars_pills": "Näita tunnuspilte kasutajate, jututubade ja sündmuste mainimistes",
"show_polls_button": "Näita küsitluste nuppu",
"startup_window_behaviour_label": "Käivitamine ja akna käitumine",
"surround_text": "Erimärkide sisestamisel märgista valitud tekst",
"time_heading": "Aegade kuvamine",
"user_timezone": "Seadista ajavöönd"
Expand Down Expand Up @@ -3065,6 +3066,9 @@
"title": "Külgpaan"
},
"start_automatically": {
"disabled": "Ei",
"enabled": "Jah",
"label": "Oma arvutisse logimisel ava %(brand)s",
"minimised": "Minimeeritud"
},
"tac_only_notifications": "Näita teavitusi vaid jutulõngade ülevaates",
Expand Down
20 changes: 20 additions & 0 deletions src/modules/ActionsApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
Copyright 2025 New Vector Ltd.

SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import type { ActionsApi } from "@element-hq/element-web-module-api";

Check failure on line 7 in src/modules/ActionsApi.ts

View workflow job for this annotation

GitHub Actions / Typescript Syntax Check

Module '"@element-hq/element-web-module-api"' has no exported member 'ActionsApi'.
import type { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload";
import dispatcher from "../dispatcher/dispatcher";
import { Action } from "../dispatcher/actions";

export class Actions implements ActionsApi {
public openRoom(roomId: string): void {
dispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: roomId,
metricsTrigger: undefined, // other
});
}
}
8 changes: 7 additions & 1 deletion src/modules/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ import { NavigationApi } from "./Navigation.ts";
import { openDialog } from "./Dialog.tsx";
import { overwriteAccountAuth } from "./Auth.ts";
import { ElementWebExtrasApi } from "./ExtrasApi.ts";
import { ElementWebBuiltinsApi } from "./BuiltinsApi.ts";
import { ElementWebBuiltinsApi } from "./BuiltinsApi.tsx";
import { StoreApi } from "./Stores.ts";
import { Client } from "./ClientApi.ts";
import { Actions } from "./ActionsApi.ts";

const legacyCustomisationsFactory = <T extends object>(baseCustomisations: T) => {
let used = false;
Expand Down Expand Up @@ -84,6 +87,9 @@ export class ModuleApi implements Api {
public readonly extras = new ElementWebExtrasApi();
public readonly builtins = new ElementWebBuiltinsApi();
public readonly rootNode = document.getElementById("matrixchat")!;
public readonly stores = new StoreApi();
public readonly client = new Client();
public readonly actions = new Actions();

public createRoot(element: Element): Root {
return createRoot(element);
Expand Down
26 changes: 26 additions & 0 deletions src/modules/BuiltinsApi.ts → src/modules/BuiltinsApi.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,21 @@
Please see LICENSE files in the repository root for full details.
*/

import React from "react";
import { type RoomViewProps, type BuiltinsApi } from "@element-hq/element-web-module-api";

Check failure on line 9 in src/modules/BuiltinsApi.tsx

View workflow job for this annotation

GitHub Actions / Typescript Syntax Check

Module '"@element-hq/element-web-module-api"' has no exported member 'BuiltinsApi'.

Check failure on line 9 in src/modules/BuiltinsApi.tsx

View workflow job for this annotation

GitHub Actions / Typescript Syntax Check

Module '"@element-hq/element-web-module-api"' has no exported member 'RoomViewProps'.
import { type MatrixClient } from "matrix-js-sdk/src/matrix";

import { RoomView } from "../components/structures/RoomView";
import { SdkContextClass } from "../contexts/SDKContext";
import RoomAvatar from "../components/views/avatars/RoomAvatar";

function getSafeCli(): MatrixClient {
const cli = SdkContextClass.instance.client;
if (!cli) {
throw new Error("Could not get MatrixClient from SdkContextClass");
}
return cli;
}

export class ElementWebBuiltinsApi implements BuiltinsApi {
private _roomView?: React.ComponentType<RoomViewProps>;
Expand All @@ -30,4 +44,16 @@

return this._roomView;
}

public renderRoomView(roomId: string): React.ReactNode {
return <RoomView roomId={roomId} />;
}

public renderRoomAvatar(roomId: string, size?: string): React.ReactNode {
const room = getSafeCli().getRoom(roomId);
if (!room) {
throw new Error(`No room such room: ${roomId}`);
}
return <RoomAvatar room={room} size={size} />;
}
}
49 changes: 49 additions & 0 deletions src/modules/ClientApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
Copyright 2025 New Vector Ltd.

SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import type { Client as ClientApi, AccountDataApi } from "@element-hq/element-web-module-api";
import type { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
import { SdkContextClass } from "../contexts/SDKContext";

function getSafeCli(): MatrixClient {
const cli = SdkContextClass.instance.client;
if (!cli) {
throw new Error("Could not get MatrixClient from SdkContextClass");
}
return cli;
}

class AccountData implements AccountDataApi {
public get(eventType: string): unknown {
//@ts-expect-error
return getSafeCli().getAccountData(eventType)?.getContent();
}

public async set(eventType: string, content: any): Promise<void> {
//@ts-expect-error
await getSafeCli().setAccountData(eventType, content);
}

public async delete(eventType: string): Promise<void> {
//@ts-expect-error
getSafeCli().deleteAccountData(eventType);
}
}

export class Client implements ClientApi {
private accountDataApi?: AccountData;

public getRoom(roomId: string): Room | null {
return getSafeCli().getRoom(roomId);
}

public getAccountDataApi(): AccountDataApi {
if (!this.accountDataApi) {
this.accountDataApi = new AccountData();
}
return this.accountDataApi;
}
}
64 changes: 64 additions & 0 deletions src/modules/Stores.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import type {
Stores,
RoomListStore as IRoomListStore,
MultiRoomViewStore as IMultiRoomViewStore,
} from "@element-hq/element-web-module-api";
import type { Room } from "matrix-js-sdk/src/matrix";
import RoomListStoreV3, { LISTS_LOADED_EVENT } from "../stores/room-list-v3/RoomListStoreV3";
import { SdkContextClass } from "../contexts/SDKContext";

class RoomListStoreApi implements IRoomListStore {
public getRooms(): Room[] {
return RoomListStoreV3.instance.getSortedRooms();
}

public async waitForRoomListLoad(): Promise<void> {
// Check if RLS is already loaded
if (!RoomListStoreV3.instance.isLoadingRooms) return;

// Return a promise that resolves when RLS has loaded
let resolve: () => void;
const promise: Promise<void> = new Promise((_resolve) => {
resolve = _resolve;
});
RoomListStoreV3.instance.once(LISTS_LOADED_EVENT, () => {
resolve();
});
return promise;
}
}

class MultiRoomViewStore implements IMultiRoomViewStore {
public getRoomViewStoreForRoom(roomId: string): unknown {
return SdkContextClass.instance.multiRoomViewStore.getRoomViewStoreForRoom(roomId);
}

public removeRoomViewStore(roomId: string): void {
SdkContextClass.instance.multiRoomViewStore.removeRoomViewStore(roomId);
}
}

export class StoreApi implements Stores {
private roomListStore?: IRoomListStore;
private multiRoomViewStore?: IMultiRoomViewStore;

public getRoomListStore(): IRoomListStore {
if (!this.roomListStore) {
this.roomListStore = new RoomListStoreApi();
}
return this.roomListStore;
}

public getMultiRoomViewStore(): IMultiRoomViewStore {
if (!this.multiRoomViewStore) {
this.multiRoomViewStore = new MultiRoomViewStore();
}
return this.multiRoomViewStore;
}
}
2 changes: 2 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ module.exports = (env, argv) => {

// Define a variable so the i18n stuff can load
"$webapp": path.resolve(__dirname, "webapp"),

"counterpart": path.resolve(__dirname, "packages/shared-components/node_modules/counterpart"),
},
fallback: {
// Mock out the NodeFS module: The opus decoder imports this wrongly.
Expand Down
3 changes: 2 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3991,8 +3991,9 @@
classnames "^2.5.1"
vaul "^1.0.0"

"@vector-im/matrix-wysiwyg-wasm@link:../../Library/Caches/Yarn/v6/npm-@vector-im-matrix-wysiwyg-2.40.0-53c9ca5ea907d91e4515da64f20a82e5586b882c-integrity/node_modules/bindings/wysiwyg-wasm":
"@vector-im/matrix-wysiwyg-wasm@link:../../.cache/yarn/v6/npm-@vector-im-matrix-wysiwyg-2.40.0-53c9ca5ea907d91e4515da64f20a82e5586b882c-integrity/node_modules/bindings/wysiwyg-wasm":
version "0.0.0"
uid ""

"@vector-im/[email protected]":
version "2.40.0"
Expand Down
Loading