mv element.io @types __mocks__/ debian docker module_system/ playwright res src test webapp Dockerfile .dockerignore .eslintignore .stylelintrc.cjs babel.config.cjs recorder-worklet-loader.cjs .modernizr.json components.json config.json config.sample.json package.json project.json tsconfig.json tsconfig.module_system.json jest.config.ts playwright.config.ts webpack.config.ts build_config.sample.yaml apps/web/

mkdir apps/web/scripts
mv scripts/{cleanup.sh,ci_package.sh,copy-res.ts,deploy.py,package.sh} apps/web/scripts

And a couple of gitignore tweaks

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski
2026-02-24 15:43:58 +00:00
parent e7509c92a1
commit 91a3cb03c1
3408 changed files with 28 additions and 32 deletions
+13
View File
@@ -0,0 +1,13 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2021 The Matrix.org Foundation C.I.C.
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 { AliasCustomisations } from "@element-hq/element-web-module-api";
// A real customisation module will define and export one or more of the
// customisation points that make up `AliasCustomisations`.
export default {} as AliasCustomisations;
+30
View File
@@ -0,0 +1,30 @@
/*
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 OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { type ChatExportCustomisations } from "@element-hq/element-web-module-api";
import { type ExportFormat, type ExportType } from "../utils/exportUtils/exportUtils";
export type ForceChatExportParameters = ReturnType<
ChatExportCustomisations<ExportFormat, ExportType>["getForceChatExportParameters"]
>;
/**
* Force parameters in room chat export
* fields returned here are forced
* and not allowed to be edited in the chat export form
*/
const getForceChatExportParameters = (): ForceChatExportParameters => {
return {};
};
// A real customisation module will define and export one or more of the
// customisation points that make up `IChatExportCustomisations`.
export default {
getForceChatExportParameters,
} as ChatExportCustomisations<ExportFormat, ExportType>;
@@ -0,0 +1,22 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2021 The Matrix.org Foundation C.I.C.
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.
*/
// Dev note: this customisation point is heavily inspired by UIFeature flags, though
// with an intention of being used for more complex switching on whether or not a feature
// should be shown.
// Populate this class with the details of your customisations when copying it.
import { type ComponentVisibilityCustomisations as IComponentVisibilityCustomisations } from "@element-hq/element-web-module-api";
// A real customisation module will define and export one or more of the
// customisation points that make up the interface above.
export const ComponentVisibilityCustomisations: IComponentVisibilityCustomisations = {
// while we don't specify the functions here, their defaults are described
// in their pseudo-implementations above.
};
+13
View File
@@ -0,0 +1,13 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2021 The Matrix.org Foundation C.I.C.
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 { DirectoryCustomisations } from "@element-hq/element-web-module-api";
// A real customisation module will define and export one or more of the
// customisation points that make up `IDirectoryCustomisations`.
export default {} as DirectoryCustomisations;
+13
View File
@@ -0,0 +1,13 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
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 { LifecycleCustomisations } from "@element-hq/element-web-module-api";
// A real customisation module will define and export one or more of the
// customisation points that make up `ILifecycleCustomisations`.
export default {} as LifecycleCustomisations;
+175
View File
@@ -0,0 +1,175 @@
/*
* Copyright 2024 New Vector Ltd.
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* 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 MatrixClient, parseErrorResponse, type ResizeMethod } from "matrix-js-sdk/src/matrix";
import { type MediaEventContent } from "matrix-js-sdk/src/types";
import type { MediaCustomisations, Media } from "@element-hq/element-web-module-api";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { type IPreparedMedia, prepEventContentAsMedia } from "./models/IMediaEventContent";
import { UserFriendlyError } from "../languageHandler";
// Populate this class with the details of your customisations when copying it.
// Implementation note: The Media class must complete the contract as shown here, though
// the constructor can be whatever is relevant to your implementation. The mediaForX
// functions below create an instance of the Media class and are used throughout the
// project.
/**
* A media object is a representation of a "source media" and an optional
* "thumbnail media", derived from event contents or external sources.
*/
class MediaImplementation implements Media {
private client: MatrixClient;
// Per above, this constructor signature can be whatever is helpful for you.
public constructor(
private prepared: IPreparedMedia,
client?: MatrixClient,
) {
this.client = client ?? MatrixClientPeg.safeGet();
if (!this.client) {
throw new Error("No possible MatrixClient for media resolution. Please provide one or log in.");
}
}
/**
* True if the media appears to be encrypted. Actual file contents may vary.
*/
public get isEncrypted(): boolean {
return !!this.prepared.file;
}
/**
* The MXC URI of the source media.
*/
public get srcMxc(): string {
return this.prepared.mxc;
}
/**
* The MXC URI of the thumbnail media, if a thumbnail is recorded. Null/undefined
* otherwise.
*/
public get thumbnailMxc(): string | undefined {
return this.prepared.thumbnail?.mxc;
}
/**
* Whether or not a thumbnail is recorded for this media.
*/
public get hasThumbnail(): boolean {
return !!this.thumbnailMxc;
}
/**
* The HTTP URL for the source media.
*/
public get srcHttp(): string | null {
// eslint-disable-next-line no-restricted-properties
return this.client.mxcUrlToHttp(this.srcMxc, undefined, undefined, undefined, false, true) || null;
}
/**
* The HTTP URL for the thumbnail media (without any specified width, height, etc). Null/undefined
* if no thumbnail media recorded.
*/
public get thumbnailHttp(): string | null {
if (!this.hasThumbnail) return null;
// eslint-disable-next-line no-restricted-properties
return this.client.mxcUrlToHttp(this.thumbnailMxc!, undefined, undefined, undefined, false, true);
}
/**
* Gets the HTTP URL for the thumbnail media with the requested characteristics, if a thumbnail
* is recorded for this media. Returns null/undefined otherwise.
* @param {number} width The desired width of the thumbnail.
* @param {number} height The desired height of the thumbnail.
* @param {"scale"|"crop"} mode The desired thumbnailing mode. Defaults to scale.
* @returns {string} The HTTP URL which points to the thumbnail.
*/
public getThumbnailHttp(width: number, height: number, mode: ResizeMethod = "scale"): string | null {
if (!this.hasThumbnail) return null;
// scale using the device pixel ratio to keep images clear
width = Math.floor(width * window.devicePixelRatio);
height = Math.floor(height * window.devicePixelRatio);
// eslint-disable-next-line no-restricted-properties
return this.client.mxcUrlToHttp(this.thumbnailMxc!, width, height, mode, false, true);
}
/**
* Gets the HTTP URL for a thumbnail of the source media with the requested characteristics.
* @param {number} width The desired width of the thumbnail.
* @param {number} height The desired height of the thumbnail.
* @param {"scale"|"crop"} mode The desired thumbnailing mode. Defaults to scale.
* @returns {string} The HTTP URL which points to the thumbnail.
*/
public getThumbnailOfSourceHttp(width: number, height: number, mode: ResizeMethod = "scale"): string | null {
// scale using the device pixel ratio to keep images clear
width = Math.floor(width * window.devicePixelRatio);
height = Math.floor(height * window.devicePixelRatio);
// eslint-disable-next-line no-restricted-properties
return this.client.mxcUrlToHttp(this.srcMxc, width, height, mode, false, true);
}
/**
* Creates a square thumbnail of the media. If the media has a thumbnail recorded, that MXC will
* be used, otherwise the source media will be used.
* @param {number} dim The desired width and height.
* @returns {string} An HTTP URL for the thumbnail.
*/
public getSquareThumbnailHttp(dim: number): string | null {
dim = Math.floor(dim * window.devicePixelRatio); // scale using the device pixel ratio to keep images clear
if (this.hasThumbnail) {
return this.getThumbnailHttp(dim, dim, "crop");
}
return this.getThumbnailOfSourceHttp(dim, dim, "crop");
}
/**
* Downloads the source media.
* @returns {Promise<Response>} Resolves to the server's response for chaining.
*/
public async downloadSource(): Promise<Response> {
const src = this.srcHttp;
if (!src) {
throw new UserFriendlyError("error|download_media");
}
const res = await fetch(src);
if (!res.ok) {
throw parseErrorResponse(res, await res.text());
}
return res;
}
}
export type { Media };
type BaseMedia = MediaCustomisations<Partial<MediaEventContent>, MatrixClient, IPreparedMedia>;
/**
* Creates a media object from event content.
* @param {MediaEventContent} content The event content.
* @param {MatrixClient} client Optional client to use.
* @returns {MediaImplementation} The media object.
*/
export const mediaFromContent: BaseMedia["mediaFromContent"] = (
content: Partial<MediaEventContent>,
client?: MatrixClient,
): Media => new MediaImplementation(prepEventContentAsMedia(content), client);
/**
* Creates a media object from an MXC URI.
* @param {string} mxc The MXC URI.
* @param {MatrixClient} client Optional client to use.
* @returns {MediaImplementation} The media object.
*/
export const mediaFromMxc: BaseMedia["mediaFromMxc"] = (mxc?: string, client?: MatrixClient): Media => {
return mediaFromContent({ url: mxc }, client);
};
+1
View File
@@ -0,0 +1 @@
../../docs/customisations.md
+17
View File
@@ -0,0 +1,17 @@
/*
* Copyright 2024 New Vector Ltd.
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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 Room } from "matrix-js-sdk/src/matrix";
import type { RoomListCustomisations as IRoomListCustomisations } from "@element-hq/element-web-module-api";
// Populate this file with the details of your customisations when copying it.
// A real customisation module will define and export one or more of the
// customisation points that make up the interface above.
export const RoomListCustomisations: IRoomListCustomisations<Room> = {};
@@ -0,0 +1,28 @@
/*
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 OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import type { UserIdentifierCustomisations } from "@element-hq/element-web-module-api";
/**
* Customise display of the user identifier
* hide userId for guests, display 3pid
*
* Set withDisplayName to true when user identifier will be displayed alongside user name
*/
function getDisplayUserIdentifier(
userId: string,
{ roomId, withDisplayName }: { roomId?: string; withDisplayName?: boolean },
): string | null {
return userId;
}
// A real customisation module will define and export one or more of the
// customisation points that make up `IUserIdentifierCustomisations`.
export default {
getDisplayUserIdentifier,
} as UserIdentifierCustomisations;
@@ -0,0 +1,16 @@
/*
* Copyright 2024 New Vector Ltd.
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* 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.
*/
// Populate this class with the details of your customisations when copying it.
import { type Capability, type Widget } from "matrix-widget-api";
import type { WidgetPermissionsCustomisations } from "@element-hq/element-web-module-api";
// A real customisation module will define and export one or more of the
// customisation points that make up the interface above.
export const WidgetPermissionCustomisations: WidgetPermissionsCustomisations<Widget, Capability> = {};
@@ -0,0 +1,14 @@
/*
* Copyright 2024 New Vector Ltd.
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* 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.
*/
// Populate this class with the details of your customisations when copying it.
import { type WidgetVariablesCustomisations } from "@element-hq/element-web-module-api";
// A real customisation module will define and export one or more of the
// customisation points that make up the interface above.
export const WidgetVariableCustomisations: WidgetVariablesCustomisations = {};
@@ -0,0 +1,14 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2021 The Matrix.org Foundation C.I.C.
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 UIComponent } from "../../settings/UIFeature";
import { ComponentVisibilityCustomisations } from "../ComponentVisibility";
export function shouldShowComponent(component: UIComponent): boolean {
return ComponentVisibilityCustomisations.shouldShowComponent?.(component) ?? true;
}
@@ -0,0 +1,61 @@
/*
* Copyright 2024 New Vector Ltd.
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* 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 EncryptedFile, type MediaEventContent } from "matrix-js-sdk/src/types";
export interface IPreparedMedia extends IMediaObject {
thumbnail?: IMediaObject;
}
export interface IMediaObject {
mxc: string;
file?: EncryptedFile;
}
/**
* Parses an event content body into a prepared media object. This prepared media object
* can be used with other functions to manipulate the media.
* @param {MediaEventContent} content Unredacted media event content. See interface.
* @returns {IPreparedMedia} A prepared media object.
* @throws Throws if the given content cannot be packaged into a prepared media object.
*/
export function prepEventContentAsMedia(content: Partial<MediaEventContent>): IPreparedMedia {
let thumbnail: IMediaObject | undefined;
if (typeof content?.info === "object" && "thumbnail_url" in content.info && content.info.thumbnail_url) {
thumbnail = {
mxc: content.info.thumbnail_url,
file: content.info.thumbnail_file,
};
} else if (
typeof content?.info === "object" &&
"thumbnail_file" in content.info &&
typeof content?.info?.thumbnail_file === "object" &&
content?.info?.thumbnail_file?.url
) {
thumbnail = {
mxc: content.info.thumbnail_file.url,
file: content.info.thumbnail_file,
};
}
if (content?.url) {
return {
thumbnail,
mxc: content.url,
file: content.file,
};
} else if (content?.file?.url) {
return {
thumbnail,
mxc: content.file.url,
file: content.file,
};
}
throw new Error("Invalid file provided: cannot determine MXC URI. Has it been redacted?");
}