mirror of
https://github.com/element-hq/element-web
synced 2024-11-21 08:45:40 +03:00
Flatten Vector-override components (#28346)
* Flatten Vector-override components Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Improve coverage Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Ie Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * delint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
a355292a7f
commit
9d79a934bf
23 changed files with 395 additions and 409 deletions
|
@ -1,5 +1 @@
|
|||
{
|
||||
"src/components/views/auth/AuthFooter.tsx": "src/components/views/auth/VectorAuthFooter.tsx",
|
||||
"src/components/views/auth/AuthHeaderLogo.tsx": "src/components/views/auth/VectorAuthHeaderLogo.tsx",
|
||||
"src/components/views/auth/AuthPage.tsx": "src/components/views/auth/VectorAuthPage.tsx"
|
||||
}
|
||||
{}
|
||||
|
|
|
@ -31,6 +31,8 @@ import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
|
|||
import { IConfigOptions } from "./IConfigOptions";
|
||||
import SdkConfig from "./SdkConfig";
|
||||
import { buildAndEncodePickleKey, encryptPickleKey } from "./utils/tokens/pickling";
|
||||
import Favicon from "./favicon.ts";
|
||||
import { getVectorConfig } from "./vector/getconfig.ts";
|
||||
|
||||
export const SSO_HOMESERVER_URL_KEY = "mx_sso_hs_url";
|
||||
export const SSO_ID_SERVER_URL_KEY = "mx_sso_is_url";
|
||||
|
@ -66,14 +68,20 @@ const UPDATE_DEFER_KEY = "mx_defer_update";
|
|||
export default abstract class BasePlatform {
|
||||
protected notificationCount = 0;
|
||||
protected errorDidOccur = false;
|
||||
protected _favicon?: Favicon;
|
||||
|
||||
protected constructor() {
|
||||
dis.register(this.onAction);
|
||||
this.startUpdateCheck = this.startUpdateCheck.bind(this);
|
||||
}
|
||||
|
||||
public abstract getConfig(): Promise<IConfigOptions | undefined>;
|
||||
public async getConfig(): Promise<IConfigOptions | undefined> {
|
||||
return getVectorConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sensible default display name for the device Element is running on
|
||||
*/
|
||||
public abstract getDefaultDeviceDisplayName(): string;
|
||||
|
||||
protected onAction = (payload: ActionPayload): void => {
|
||||
|
@ -89,11 +97,15 @@ export default abstract class BasePlatform {
|
|||
public abstract getHumanReadableName(): string;
|
||||
|
||||
public setNotificationCount(count: number): void {
|
||||
if (this.notificationCount === count) return;
|
||||
this.notificationCount = count;
|
||||
this.updateFavicon();
|
||||
}
|
||||
|
||||
public setErrorStatus(errorDidOccur: boolean): void {
|
||||
if (this.errorDidOccur === errorDidOccur) return;
|
||||
this.errorDidOccur = errorDidOccur;
|
||||
this.updateFavicon();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -456,4 +468,34 @@ export default abstract class BasePlatform {
|
|||
url.hash = "";
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delay creating the `Favicon` instance until first use (on the first notification) as
|
||||
* it uses canvas, which can trigger a permission prompt in Firefox's resist fingerprinting mode.
|
||||
* See https://github.com/element-hq/element-web/issues/9605.
|
||||
*/
|
||||
public get favicon(): Favicon {
|
||||
if (this._favicon) {
|
||||
return this._favicon;
|
||||
}
|
||||
this._favicon = new Favicon();
|
||||
return this._favicon;
|
||||
}
|
||||
|
||||
private updateFavicon(): void {
|
||||
let bgColor = "#d00";
|
||||
let notif: string | number = this.notificationCount;
|
||||
|
||||
if (this.errorDidOccur) {
|
||||
notif = notif || "×";
|
||||
bgColor = "#f00";
|
||||
}
|
||||
|
||||
this.favicon.badge(notif, { bgColor });
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin update polling, if applicable
|
||||
*/
|
||||
public startUpdater(): void {}
|
||||
}
|
||||
|
|
|
@ -7,18 +7,36 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
|||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { ReactElement } from "react";
|
||||
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
||||
export default class AuthFooter extends React.Component {
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<footer className="mx_AuthFooter" role="contentinfo">
|
||||
<a href="https://matrix.org" target="_blank" rel="noreferrer noopener">
|
||||
{_t("auth|footer_powered_by_matrix")}
|
||||
</a>
|
||||
</footer>
|
||||
const AuthFooter = (): ReactElement => {
|
||||
const brandingConfig = SdkConfig.getObject("branding");
|
||||
const links = brandingConfig?.get("auth_footer_links") ?? [
|
||||
{ text: "Blog", url: "https://element.io/blog" },
|
||||
{ text: "Twitter", url: "https://twitter.com/element_hq" },
|
||||
{ text: "GitHub", url: "https://github.com/element-hq/element-web" },
|
||||
];
|
||||
|
||||
const authFooterLinks: JSX.Element[] = [];
|
||||
for (const linkEntry of links) {
|
||||
authFooterLinks.push(
|
||||
<a href={linkEntry.url} key={linkEntry.text} target="_blank" rel="noreferrer noopener">
|
||||
{linkEntry.text}
|
||||
</a>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<footer className="mx_AuthFooter" role="contentinfo">
|
||||
{authFooterLinks}
|
||||
<a href="https://matrix.org" target="_blank" rel="noreferrer noopener">
|
||||
{_t("powered_by_matrix")}
|
||||
</a>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthFooter;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
Copyright 2019-2024 New Vector Ltd.
|
||||
Copyright 2015, 2016 OpenMarket Ltd
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
|
@ -7,8 +8,17 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import React from "react";
|
||||
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
|
||||
export default class AuthHeaderLogo extends React.PureComponent {
|
||||
public render(): React.ReactNode {
|
||||
return <aside className="mx_AuthHeaderLogo">Matrix</aside>;
|
||||
public render(): React.ReactElement {
|
||||
const brandingConfig = SdkConfig.getObject("branding");
|
||||
const logoUrl = brandingConfig?.get("auth_header_logo_url") ?? "themes/element/img/logos/element-logo.svg";
|
||||
|
||||
return (
|
||||
<aside className="mx_AuthHeaderLogo">
|
||||
<img src={logoUrl} alt="Element" />
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,15 +7,69 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
|||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { ReactNode } from "react";
|
||||
import React from "react";
|
||||
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
import AuthFooter from "./AuthFooter";
|
||||
|
||||
export default class AuthPage extends React.PureComponent<{ children: ReactNode }> {
|
||||
public render(): React.ReactNode {
|
||||
export default class AuthPage extends React.PureComponent<React.PropsWithChildren> {
|
||||
private static welcomeBackgroundUrl?: string;
|
||||
|
||||
// cache the url as a static to prevent it changing without refreshing
|
||||
private static getWelcomeBackgroundUrl(): string {
|
||||
if (AuthPage.welcomeBackgroundUrl) return AuthPage.welcomeBackgroundUrl;
|
||||
|
||||
const brandingConfig = SdkConfig.getObject("branding");
|
||||
AuthPage.welcomeBackgroundUrl = "themes/element/img/backgrounds/lake.jpg";
|
||||
|
||||
const configuredUrl = brandingConfig?.get("welcome_background_url");
|
||||
if (configuredUrl) {
|
||||
if (Array.isArray(configuredUrl)) {
|
||||
const index = Math.floor(Math.random() * configuredUrl.length);
|
||||
AuthPage.welcomeBackgroundUrl = configuredUrl[index];
|
||||
} else {
|
||||
AuthPage.welcomeBackgroundUrl = configuredUrl;
|
||||
}
|
||||
}
|
||||
|
||||
return AuthPage.welcomeBackgroundUrl;
|
||||
}
|
||||
|
||||
public render(): React.ReactElement {
|
||||
const pageStyle = {
|
||||
background: `center/cover fixed url(${AuthPage.getWelcomeBackgroundUrl()})`,
|
||||
};
|
||||
|
||||
const modalStyle: React.CSSProperties = {
|
||||
position: "relative",
|
||||
background: "initial",
|
||||
};
|
||||
|
||||
const blurStyle: React.CSSProperties = {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
filter: "blur(40px)",
|
||||
background: pageStyle.background,
|
||||
};
|
||||
|
||||
const modalContentStyle: React.CSSProperties = {
|
||||
display: "flex",
|
||||
zIndex: 1,
|
||||
background: "rgba(255, 255, 255, 0.59)",
|
||||
borderRadius: "8px",
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx_AuthPage">
|
||||
<div className="mx_AuthPage_modal">{this.props.children}</div>
|
||||
<div className="mx_AuthPage" style={pageStyle}>
|
||||
<div className="mx_AuthPage_modal" style={modalStyle}>
|
||||
<div className="mx_AuthPage_modalBlur" style={blurStyle} />
|
||||
<div className="mx_AuthPage_modalContent" style={modalContentStyle}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
<AuthFooter />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
Copyright 2019-2024 New Vector Ltd.
|
||||
Copyright 2015, 2016 OpenMarket Ltd
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { ReactElement } from "react";
|
||||
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
||||
const VectorAuthFooter = (): ReactElement => {
|
||||
const brandingConfig = SdkConfig.getObject("branding");
|
||||
const links = brandingConfig?.get("auth_footer_links") ?? [
|
||||
{ text: "Blog", url: "https://element.io/blog" },
|
||||
{ text: "Twitter", url: "https://twitter.com/element_hq" },
|
||||
{ text: "GitHub", url: "https://github.com/element-hq/element-web" },
|
||||
];
|
||||
|
||||
const authFooterLinks: JSX.Element[] = [];
|
||||
for (const linkEntry of links) {
|
||||
authFooterLinks.push(
|
||||
<a href={linkEntry.url} key={linkEntry.text} target="_blank" rel="noreferrer noopener">
|
||||
{linkEntry.text}
|
||||
</a>,
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<footer className="mx_AuthFooter" role="contentinfo">
|
||||
{authFooterLinks}
|
||||
<a href="https://matrix.org" target="_blank" rel="noreferrer noopener">
|
||||
{_t("powered_by_matrix")}
|
||||
</a>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
export default VectorAuthFooter;
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
Copyright 2019-2024 New Vector Ltd.
|
||||
Copyright 2015, 2016 OpenMarket Ltd
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
|
||||
export default class VectorAuthHeaderLogo extends React.PureComponent {
|
||||
public render(): React.ReactElement {
|
||||
const brandingConfig = SdkConfig.getObject("branding");
|
||||
const logoUrl = brandingConfig?.get("auth_header_logo_url") ?? "themes/element/img/logos/element-logo.svg";
|
||||
|
||||
return (
|
||||
<aside className="mx_AuthHeaderLogo">
|
||||
<img src={logoUrl} alt="Element" />
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
Copyright 2019-2024 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
import VectorAuthFooter from "./VectorAuthFooter";
|
||||
|
||||
export default class VectorAuthPage extends React.PureComponent<React.PropsWithChildren> {
|
||||
private static welcomeBackgroundUrl?: string;
|
||||
|
||||
// cache the url as a static to prevent it changing without refreshing
|
||||
private static getWelcomeBackgroundUrl(): string {
|
||||
if (VectorAuthPage.welcomeBackgroundUrl) return VectorAuthPage.welcomeBackgroundUrl;
|
||||
|
||||
const brandingConfig = SdkConfig.getObject("branding");
|
||||
VectorAuthPage.welcomeBackgroundUrl = "themes/element/img/backgrounds/lake.jpg";
|
||||
|
||||
const configuredUrl = brandingConfig?.get("welcome_background_url");
|
||||
if (configuredUrl) {
|
||||
if (Array.isArray(configuredUrl)) {
|
||||
const index = Math.floor(Math.random() * configuredUrl.length);
|
||||
VectorAuthPage.welcomeBackgroundUrl = configuredUrl[index];
|
||||
} else {
|
||||
VectorAuthPage.welcomeBackgroundUrl = configuredUrl;
|
||||
}
|
||||
}
|
||||
|
||||
return VectorAuthPage.welcomeBackgroundUrl;
|
||||
}
|
||||
|
||||
public render(): React.ReactElement {
|
||||
const pageStyle = {
|
||||
background: `center/cover fixed url(${VectorAuthPage.getWelcomeBackgroundUrl()})`,
|
||||
};
|
||||
|
||||
const modalStyle: React.CSSProperties = {
|
||||
position: "relative",
|
||||
background: "initial",
|
||||
};
|
||||
|
||||
const blurStyle: React.CSSProperties = {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
filter: "blur(40px)",
|
||||
background: pageStyle.background,
|
||||
};
|
||||
|
||||
const modalContentStyle: React.CSSProperties = {
|
||||
display: "flex",
|
||||
zIndex: 1,
|
||||
background: "rgba(255, 255, 255, 0.59)",
|
||||
borderRadius: "8px",
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx_AuthPage" style={pageStyle}>
|
||||
<div className="mx_AuthPage_modal" style={modalStyle}>
|
||||
<div className="mx_AuthPage_modalBlur" style={blurStyle} />
|
||||
<div className="mx_AuthPage_modalContent" style={modalContentStyle}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
<VectorAuthFooter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -209,7 +209,6 @@
|
|||
"failed_query_registration_methods": "Unable to query for supported registration methods.",
|
||||
"failed_soft_logout_auth": "Failed to re-authenticate",
|
||||
"failed_soft_logout_homeserver": "Failed to re-authenticate due to a homeserver problem",
|
||||
"footer_powered_by_matrix": "powered by Matrix",
|
||||
"forgot_password_email_invalid": "The email address doesn't appear to be valid.",
|
||||
"forgot_password_email_required": "The email address linked to your account must be entered.",
|
||||
"forgot_password_prompt": "Forgotten your password?",
|
||||
|
@ -3706,7 +3705,6 @@
|
|||
"truncated_list_n_more": {
|
||||
"other": "And %(count)s more..."
|
||||
},
|
||||
"unknown_device": "Unknown device",
|
||||
"unsupported_browser": {
|
||||
"description": "If you continue, some features may stop working and there is a risk that you may lose data in the future. Update your browser to continue using %(brand)s.",
|
||||
"title": "%(brand)s does not support this browser"
|
||||
|
|
|
@ -27,7 +27,6 @@ import MatrixChat from "../components/structures/MatrixChat";
|
|||
import { ValidatedServerConfig } from "../utils/ValidatedServerConfig";
|
||||
import { ModuleRunner } from "../modules/ModuleRunner";
|
||||
import { parseQs } from "./url_utils";
|
||||
import VectorBasePlatform from "./platform/VectorBasePlatform";
|
||||
import { getInitialScreenAfterLogin, getScreenFromLocation, init as initRouting, onNewScreen } from "./routing";
|
||||
import { UserFriendlyError } from "../languageHandler";
|
||||
|
||||
|
@ -64,7 +63,7 @@ export async function loadApp(fragParams: {}, matrixChatRef: React.Ref<MatrixCha
|
|||
const urlWithoutQuery = window.location.protocol + "//" + window.location.host + window.location.pathname;
|
||||
logger.log("Vector starting at " + urlWithoutQuery);
|
||||
|
||||
(platform as VectorBasePlatform).startUpdater();
|
||||
platform?.startUpdater();
|
||||
|
||||
// Don't bother loading the app until the config is verified
|
||||
const config = await verifyServerConfig();
|
||||
|
|
|
@ -15,7 +15,7 @@ import React from "react";
|
|||
import { randomString } from "matrix-js-sdk/src/randomstring";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import { UpdateCheckStatus, UpdateStatus } from "../../BasePlatform";
|
||||
import BasePlatform, { UpdateCheckStatus, UpdateStatus } from "../../BasePlatform";
|
||||
import BaseEventIndexManager from "../../indexing/BaseEventIndexManager";
|
||||
import dis from "../../dispatcher/dispatcher";
|
||||
import SdkConfig from "../../SdkConfig";
|
||||
|
@ -35,7 +35,6 @@ import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
|||
import { avatarUrlForRoom, getInitialLetter } from "../../Avatar";
|
||||
import DesktopCapturerSourcePicker from "../../components/views/elements/DesktopCapturerSourcePicker";
|
||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||
import VectorBasePlatform from "./VectorBasePlatform";
|
||||
import { SeshatIndexManager } from "./SeshatIndexManager";
|
||||
import { IPCManager } from "./IPCManager";
|
||||
import { _t } from "../../languageHandler";
|
||||
|
@ -90,7 +89,7 @@ function getUpdateCheckStatus(status: boolean | string): UpdateStatus {
|
|||
}
|
||||
}
|
||||
|
||||
export default class ElectronPlatform extends VectorBasePlatform {
|
||||
export default class ElectronPlatform extends BasePlatform {
|
||||
private readonly ipc = new IPCManager("ipcCall", "ipcReply");
|
||||
private readonly eventIndexManager: BaseEventIndexManager = new SeshatIndexManager();
|
||||
// this is the opaque token we pass to the HS which when we get it in our callback we can resolve to a profile
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
Copyright 2018-2024 New Vector Ltd.
|
||||
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
||||
Copyright 2016 Aviral Dasgupta
|
||||
Copyright 2016 OpenMarket Ltd
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import type { IConfigOptions } from "../../IConfigOptions";
|
||||
import BasePlatform from "../../BasePlatform";
|
||||
import { getVectorConfig } from "../getconfig";
|
||||
import Favicon from "../../favicon";
|
||||
import { _t } from "../../languageHandler";
|
||||
|
||||
/**
|
||||
* Vector-specific extensions to the BasePlatform template
|
||||
*/
|
||||
export default abstract class VectorBasePlatform extends BasePlatform {
|
||||
protected _favicon?: Favicon;
|
||||
|
||||
public async getConfig(): Promise<IConfigOptions | undefined> {
|
||||
return getVectorConfig();
|
||||
}
|
||||
|
||||
public getHumanReadableName(): string {
|
||||
return "Vector Base Platform"; // no translation required: only used for analytics
|
||||
}
|
||||
|
||||
/**
|
||||
* Delay creating the `Favicon` instance until first use (on the first notification) as
|
||||
* it uses canvas, which can trigger a permission prompt in Firefox's resist fingerprinting mode.
|
||||
* See https://github.com/element-hq/element-web/issues/9605.
|
||||
*/
|
||||
public get favicon(): Favicon {
|
||||
if (this._favicon) {
|
||||
return this._favicon;
|
||||
}
|
||||
this._favicon = new Favicon();
|
||||
return this._favicon;
|
||||
}
|
||||
|
||||
private updateFavicon(): void {
|
||||
let bgColor = "#d00";
|
||||
let notif: string | number = this.notificationCount;
|
||||
|
||||
if (this.errorDidOccur) {
|
||||
notif = notif || "×";
|
||||
bgColor = "#f00";
|
||||
}
|
||||
|
||||
this.favicon.badge(notif, { bgColor });
|
||||
}
|
||||
|
||||
public setNotificationCount(count: number): void {
|
||||
if (this.notificationCount === count) return;
|
||||
super.setNotificationCount(count);
|
||||
this.updateFavicon();
|
||||
}
|
||||
|
||||
public setErrorStatus(errorDidOccur: boolean): void {
|
||||
if (this.errorDidOccur === errorDidOccur) return;
|
||||
super.setErrorStatus(errorDidOccur);
|
||||
this.updateFavicon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin update polling, if applicable
|
||||
*/
|
||||
public startUpdater(): void {}
|
||||
|
||||
/**
|
||||
* Get a sensible default display name for the
|
||||
* device Vector is running on
|
||||
*/
|
||||
public getDefaultDeviceDisplayName(): string {
|
||||
return _t("unknown_device");
|
||||
}
|
||||
}
|
|
@ -11,12 +11,11 @@ import UAParser from "ua-parser-js";
|
|||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||
import { UpdateCheckStatus, UpdateStatus } from "../../BasePlatform";
|
||||
import BasePlatform, { UpdateCheckStatus, UpdateStatus } from "../../BasePlatform";
|
||||
import dis from "../../dispatcher/dispatcher";
|
||||
import { hideToast as hideUpdateToast, showToast as showUpdateToast } from "../../toasts/UpdateToast";
|
||||
import { Action } from "../../dispatcher/actions";
|
||||
import { CheckUpdatesPayload } from "../../dispatcher/payloads/CheckUpdatesPayload";
|
||||
import VectorBasePlatform from "./VectorBasePlatform";
|
||||
import { parseQs } from "../url_utils";
|
||||
import { _t } from "../../languageHandler";
|
||||
|
||||
|
@ -31,7 +30,7 @@ function getNormalizedAppVersion(version: string): string {
|
|||
return version;
|
||||
}
|
||||
|
||||
export default class WebPlatform extends VectorBasePlatform {
|
||||
export default class WebPlatform extends BasePlatform {
|
||||
private static readonly VERSION = process.env.VERSION!; // baked in by Webpack
|
||||
|
||||
public constructor() {
|
||||
|
|
|
@ -953,7 +953,7 @@ describe("<MatrixChat />", () => {
|
|||
const getComponentAndWaitForReady = async (): Promise<RenderResult> => {
|
||||
const renderResult = getComponent();
|
||||
// wait for welcome page chrome render
|
||||
await screen.findByText("powered by Matrix");
|
||||
await screen.findByText("Powered by Matrix");
|
||||
|
||||
// go to login page
|
||||
defaultDispatcher.dispatch({
|
||||
|
@ -1480,7 +1480,7 @@ describe("<MatrixChat />", () => {
|
|||
const getComponentAndWaitForReady = async (): Promise<RenderResult> => {
|
||||
const renderResult = getComponent();
|
||||
// wait for welcome page chrome render
|
||||
await screen.findByText("powered by Matrix");
|
||||
await screen.findByText("Powered by Matrix");
|
||||
|
||||
// go to mobile_register page
|
||||
defaultDispatcher.dispatch({
|
||||
|
@ -1500,7 +1500,7 @@ describe("<MatrixChat />", () => {
|
|||
it("should render welcome screen if mobile registration is not enabled in settings", async () => {
|
||||
await getComponentAndWaitForReady();
|
||||
|
||||
await screen.findByText("powered by Matrix");
|
||||
await screen.findByText("Powered by Matrix");
|
||||
});
|
||||
|
||||
it("should render mobile registration", async () => {
|
||||
|
|
|
@ -114,46 +114,56 @@ exports[`<MatrixChat /> Multi-tab lockout waits for other tab to stop during sta
|
|||
>
|
||||
<div
|
||||
class="mx_AuthPage_modal"
|
||||
style="position: relative;"
|
||||
>
|
||||
<div
|
||||
class="mx_Welcome"
|
||||
data-testid="mx_welcome_screen"
|
||||
class="mx_AuthPage_modalBlur"
|
||||
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px; filter: blur(40px);"
|
||||
/>
|
||||
<div
|
||||
class="mx_AuthPage_modalContent"
|
||||
style="display: flex; z-index: 1; background: rgba(255, 255, 255, 0.59); border-radius: 8px;"
|
||||
>
|
||||
<div
|
||||
class="mx_WelcomePage mx_WelcomePage_loggedIn"
|
||||
class="mx_Welcome"
|
||||
data-testid="mx_welcome_screen"
|
||||
>
|
||||
<div
|
||||
class="mx_WelcomePage_body"
|
||||
>
|
||||
<h1>
|
||||
Hello
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Dropdown mx_LanguageDropdown mx_AuthBody_language"
|
||||
>
|
||||
<div
|
||||
aria-describedby="mx_LanguageDropdown_value"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-label="Language Dropdown"
|
||||
aria-owns="mx_LanguageDropdown_input"
|
||||
class="mx_AccessibleButton mx_Dropdown_input mx_no_textinput"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="mx_WelcomePage mx_WelcomePage_loggedIn"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown_option"
|
||||
id="mx_LanguageDropdown_value"
|
||||
class="mx_WelcomePage_body"
|
||||
>
|
||||
<div>
|
||||
English
|
||||
</div>
|
||||
<h1>
|
||||
Hello
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Dropdown mx_LanguageDropdown mx_AuthBody_language"
|
||||
>
|
||||
<div
|
||||
aria-describedby="mx_LanguageDropdown_value"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-label="Language Dropdown"
|
||||
aria-owns="mx_LanguageDropdown_input"
|
||||
class="mx_AccessibleButton mx_Dropdown_input mx_no_textinput"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown_option"
|
||||
id="mx_LanguageDropdown_value"
|
||||
>
|
||||
<div>
|
||||
English
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="mx_Dropdown_arrow"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="mx_Dropdown_arrow"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -162,12 +172,33 @@ exports[`<MatrixChat /> Multi-tab lockout waits for other tab to stop during sta
|
|||
class="mx_AuthFooter"
|
||||
role="contentinfo"
|
||||
>
|
||||
<a
|
||||
href="https://element.io/blog"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Blog
|
||||
</a>
|
||||
<a
|
||||
href="https://twitter.com/element_hq"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Twitter
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/element-hq/element-web"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
<a
|
||||
href="https://matrix.org"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
powered by Matrix
|
||||
Powered by Matrix
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -201,116 +232,150 @@ exports[`<MatrixChat /> with a soft-logged-out session should show the soft-logo
|
|||
>
|
||||
<div
|
||||
class="mx_AuthPage_modal"
|
||||
style="position: relative;"
|
||||
>
|
||||
<div
|
||||
class="mx_AuthHeader"
|
||||
class="mx_AuthPage_modalBlur"
|
||||
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px; filter: blur(40px);"
|
||||
/>
|
||||
<div
|
||||
class="mx_AuthPage_modalContent"
|
||||
style="display: flex; z-index: 1; background: rgba(255, 255, 255, 0.59); border-radius: 8px;"
|
||||
>
|
||||
<aside
|
||||
class="mx_AuthHeaderLogo"
|
||||
>
|
||||
Matrix
|
||||
</aside>
|
||||
<div
|
||||
class="mx_Dropdown mx_LanguageDropdown mx_AuthBody_language"
|
||||
class="mx_AuthHeader"
|
||||
>
|
||||
<div
|
||||
aria-describedby="mx_LanguageDropdown_value"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-label="Language Dropdown"
|
||||
aria-owns="mx_LanguageDropdown_input"
|
||||
class="mx_AccessibleButton mx_Dropdown_input mx_no_textinput"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
<aside
|
||||
class="mx_AuthHeaderLogo"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown_option"
|
||||
id="mx_LanguageDropdown_value"
|
||||
>
|
||||
<div>
|
||||
English
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="mx_Dropdown_arrow"
|
||||
<img
|
||||
alt="Element"
|
||||
src="themes/element/img/logos/element-logo.svg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<main
|
||||
class="mx_AuthBody"
|
||||
>
|
||||
<h1>
|
||||
You're signed out
|
||||
</h1>
|
||||
<h2>
|
||||
Sign in
|
||||
</h2>
|
||||
<div>
|
||||
<form>
|
||||
<p>
|
||||
Enter your password to sign in and regain access to your account.
|
||||
</p>
|
||||
<div
|
||||
class="mx_Field mx_Field_input"
|
||||
>
|
||||
<input
|
||||
id="mx_Field_1"
|
||||
label="Password"
|
||||
placeholder="Password"
|
||||
type="password"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="mx_Field_1"
|
||||
>
|
||||
Password
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="submit"
|
||||
>
|
||||
Sign in
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Forgotten your password?
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<h2>
|
||||
Clear personal data
|
||||
</h2>
|
||||
<p>
|
||||
Warning: your personal data (including encryption keys) is still stored in this session. Clear it if you're finished using this session, or want to sign in to another account.
|
||||
</p>
|
||||
<div>
|
||||
</aside>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="mx_Dropdown mx_LanguageDropdown mx_AuthBody_language"
|
||||
>
|
||||
Clear all data
|
||||
<div
|
||||
aria-describedby="mx_LanguageDropdown_value"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-label="Language Dropdown"
|
||||
aria-owns="mx_LanguageDropdown_input"
|
||||
class="mx_AccessibleButton mx_Dropdown_input mx_no_textinput"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown_option"
|
||||
id="mx_LanguageDropdown_value"
|
||||
>
|
||||
<div>
|
||||
English
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="mx_Dropdown_arrow"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<main
|
||||
class="mx_AuthBody"
|
||||
>
|
||||
<h1>
|
||||
You're signed out
|
||||
</h1>
|
||||
<h2>
|
||||
Sign in
|
||||
</h2>
|
||||
<div>
|
||||
<form>
|
||||
<p>
|
||||
Enter your password to sign in and regain access to your account.
|
||||
</p>
|
||||
<div
|
||||
class="mx_Field mx_Field_input"
|
||||
>
|
||||
<input
|
||||
id="mx_Field_1"
|
||||
label="Password"
|
||||
placeholder="Password"
|
||||
type="password"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="mx_Field_1"
|
||||
>
|
||||
Password
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="submit"
|
||||
>
|
||||
Sign in
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Forgotten your password?
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<h2>
|
||||
Clear personal data
|
||||
</h2>
|
||||
<p>
|
||||
Warning: your personal data (including encryption keys) is still stored in this session. Clear it if you're finished using this session, or want to sign in to another account.
|
||||
</p>
|
||||
<div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Clear all data
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<footer
|
||||
class="mx_AuthFooter"
|
||||
role="contentinfo"
|
||||
>
|
||||
<a
|
||||
href="https://element.io/blog"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Blog
|
||||
</a>
|
||||
<a
|
||||
href="https://twitter.com/element_hq"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Twitter
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/element-hq/element-web"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
<a
|
||||
href="https://matrix.org"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
powered by Matrix
|
||||
Powered by Matrix
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
|
|
@ -9,16 +9,16 @@ Please see LICENSE files in the repository root for full details.
|
|||
import * as React from "react";
|
||||
import { render } from "jest-matrix-react";
|
||||
|
||||
import VectorAuthPage from "../../../../../src/components/views/auth/VectorAuthPage";
|
||||
import AuthFooter from "../../../../../src/components/views/auth/AuthFooter";
|
||||
import { setupLanguageMock } from "../../../../setup/setupLanguage";
|
||||
|
||||
describe("<VectorAuthPage />", () => {
|
||||
describe("<AuthFooter />", () => {
|
||||
beforeEach(() => {
|
||||
setupLanguageMock();
|
||||
});
|
||||
|
||||
it("should match snapshot", () => {
|
||||
const { asFragment } = render(<VectorAuthPage />);
|
||||
const { asFragment } = render(<AuthFooter />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -9,11 +9,11 @@ Please see LICENSE files in the repository root for full details.
|
|||
import * as React from "react";
|
||||
import { render } from "jest-matrix-react";
|
||||
|
||||
import VectorAuthHeaderLogo from "../../../../../src/components/views/auth/VectorAuthHeaderLogo";
|
||||
import AuthHeaderLogo from "../../../../../src/components/views/auth/AuthHeaderLogo";
|
||||
|
||||
describe("<VectorAuthHeaderLogo />", () => {
|
||||
describe("<AuthHeaderLogo />", () => {
|
||||
it("should match snapshot", () => {
|
||||
const { asFragment } = render(<VectorAuthHeaderLogo />);
|
||||
const { asFragment } = render(<AuthHeaderLogo />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
36
test/unit-tests/components/views/auth/AuthPage-test.tsx
Normal file
36
test/unit-tests/components/views/auth/AuthPage-test.tsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { render } from "jest-matrix-react";
|
||||
|
||||
import AuthPage from "../../../../../src/components/views/auth/AuthPage";
|
||||
import { setupLanguageMock } from "../../../../setup/setupLanguage";
|
||||
import SdkConfig from "../../../../../src/SdkConfig.ts";
|
||||
|
||||
describe("<AuthPage />", () => {
|
||||
beforeEach(() => {
|
||||
setupLanguageMock();
|
||||
SdkConfig.reset();
|
||||
// @ts-ignore private access
|
||||
AuthPage.welcomeBackgroundUrl = undefined;
|
||||
});
|
||||
|
||||
it("should match snapshot", () => {
|
||||
const { asFragment } = render(<AuthPage />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should use configured background url", () => {
|
||||
SdkConfig.add({ branding: { welcome_background_url: ["https://example.com/image.png"] } });
|
||||
const { container } = render(<AuthPage />);
|
||||
expect(container.querySelector(".mx_AuthPage")).toHaveStyle({
|
||||
background: "center/cover fixed url(https://example.com/image.png)",
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { render } from "jest-matrix-react";
|
||||
|
||||
import VectorAuthFooter from "../../../../../src/components/views/auth/VectorAuthFooter";
|
||||
import { setupLanguageMock } from "../../../../setup/setupLanguage";
|
||||
|
||||
describe("<VectorAuthFooter />", () => {
|
||||
beforeEach(() => {
|
||||
setupLanguageMock();
|
||||
});
|
||||
|
||||
it("should match snapshot", () => {
|
||||
const { asFragment } = render(<VectorAuthFooter />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<VectorAuthFooter /> should match snapshot 1`] = `
|
||||
exports[`<AuthFooter /> should match snapshot 1`] = `
|
||||
<DocumentFragment>
|
||||
<footer
|
||||
class="mx_AuthFooter"
|
|
@ -1,6 +1,6 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<VectorAuthHeaderLogo /> should match snapshot 1`] = `
|
||||
exports[`<AuthHeaderLogo /> should match snapshot 1`] = `
|
||||
<DocumentFragment>
|
||||
<aside
|
||||
class="mx_AuthHeaderLogo"
|
|
@ -1,6 +1,6 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<VectorAuthPage /> should match snapshot 1`] = `
|
||||
exports[`<AuthPage /> should match snapshot 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="mx_AuthPage"
|
|
@ -229,4 +229,18 @@ describe("WebPlatform", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should return config from config.json", async () => {
|
||||
window.location.hostname = "domain.com";
|
||||
fetchMock.get(/config\.json.*/, { brand: "test" });
|
||||
const platform = new WebPlatform();
|
||||
await expect(platform.getConfig()).resolves.toEqual(expect.objectContaining({ brand: "test" }));
|
||||
});
|
||||
|
||||
it("should re-render favicon when setting error status", () => {
|
||||
const platform = new WebPlatform();
|
||||
const spy = jest.spyOn(platform.favicon, "badge");
|
||||
platform.setErrorStatus(true);
|
||||
expect(spy).toHaveBeenCalledWith(expect.anything(), { bgColor: "#f00" });
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue