Implement customisations & login component Module API 1.11.0 (#32687)
* Update to Module API v1.11.0 Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove stale state field to make CQL happy Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Bump npm dep Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Improve coverage Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Improve coverage Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update comment Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
committed by
GitHub
parent
78b40a6fed
commit
35afc2fdf8
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type JSX, type ReactNode } from "react";
|
||||
import React, { type JSX, memo, type ReactNode } from "react";
|
||||
import classNames from "classnames";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { type SSOFlow, SSOAction } from "matrix-js-sdk/src/matrix";
|
||||
@@ -32,6 +32,7 @@ import AccessibleButton, { type ButtonEvent } from "../../views/elements/Accessi
|
||||
import { type ValidatedServerConfig } from "../../../utils/ValidatedServerConfig";
|
||||
import { filterBoolean } from "../../../utils/arrays";
|
||||
import { startOidcLogin } from "../../../utils/oidc/authorize";
|
||||
import { ModuleApi } from "../../../modules/Api.ts";
|
||||
|
||||
interface IProps {
|
||||
serverConfig: ValidatedServerConfig;
|
||||
@@ -45,13 +46,15 @@ interface IProps {
|
||||
defaultDeviceDisplayName?: string;
|
||||
fragmentAfterLogin?: string;
|
||||
defaultUsername?: string;
|
||||
// Any additional content to show, will be rendered between main actions & footer actions
|
||||
children?: ReactNode;
|
||||
|
||||
// Called when the user has logged in. Params:
|
||||
// - The object returned by the login API
|
||||
onLoggedIn(data: IMatrixClientCreds): void;
|
||||
|
||||
// login shouldn't know or care how registration, password recovery, etc is done.
|
||||
onRegisterClick(): void;
|
||||
onRegisterClick?(): void;
|
||||
onForgotPasswordClick?(): void;
|
||||
onServerConfigChange(config: ValidatedServerConfig): void;
|
||||
}
|
||||
@@ -61,8 +64,6 @@ interface IState {
|
||||
busyLoggingIn?: boolean;
|
||||
errorText?: ReactNode;
|
||||
loginIncorrect: boolean;
|
||||
// can we attempt to log in or are there validation errors?
|
||||
canTryLogin: boolean;
|
||||
|
||||
flows?: ClientLoginFlow[];
|
||||
|
||||
@@ -88,7 +89,7 @@ type OnPasswordLogin = {
|
||||
/*
|
||||
* A wire component which glues together login UI components and Login logic
|
||||
*/
|
||||
export default class LoginComponent extends React.PureComponent<IProps, IState> {
|
||||
class LoginComponent extends React.PureComponent<IProps, IState> {
|
||||
private unmounted = false;
|
||||
private loginLogic!: Login;
|
||||
|
||||
@@ -101,7 +102,6 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||
busy: false,
|
||||
errorText: null,
|
||||
loginIncorrect: false,
|
||||
canTryLogin: true,
|
||||
|
||||
username: props.defaultUsername ? props.defaultUsername : "",
|
||||
phoneCountry: "",
|
||||
@@ -229,7 +229,6 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||
username: username,
|
||||
busy: doWellknownLookup,
|
||||
errorText: null,
|
||||
canTryLogin: true,
|
||||
});
|
||||
if (doWellknownLookup) {
|
||||
const serverName = username.split(":").slice(1).join(":");
|
||||
@@ -281,7 +280,7 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||
public onRegisterClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.props.onRegisterClick();
|
||||
this.props.onRegisterClick?.();
|
||||
};
|
||||
|
||||
public onTryRegisterClick = (ev: ButtonEvent): void => {
|
||||
@@ -379,7 +378,6 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||
this.setState({
|
||||
errorText: messageForConnectionError(err, this.props.serverConfig),
|
||||
loginIncorrect: false,
|
||||
canTryLogin: false,
|
||||
});
|
||||
},
|
||||
)
|
||||
@@ -512,7 +510,7 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
} else if (SettingsStore.getValue(UIFeature.Registration)) {
|
||||
} else if (this.props.onRegisterClick && SettingsStore.getValue(UIFeature.Registration)) {
|
||||
footer = (
|
||||
<span className="mx_AuthBody_changeFlow">
|
||||
{_t(
|
||||
@@ -546,9 +544,21 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||
disabled={this.isBusy()}
|
||||
/>
|
||||
{this.renderLoginComponentForFlows()}
|
||||
{this.props.children}
|
||||
{footer}
|
||||
</AuthBody>
|
||||
</AuthPage>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const WrappedLoginComponent = memo((props: IProps): JSX.Element => {
|
||||
const moduleRenderer = ModuleApi.instance.customComponents.loginComponentRenderer;
|
||||
if (moduleRenderer) {
|
||||
return moduleRenderer(props, (props) => <LoginComponent {...props} />);
|
||||
}
|
||||
|
||||
return <LoginComponent {...props} />;
|
||||
});
|
||||
|
||||
export default WrappedLoginComponent;
|
||||
|
||||
@@ -8,7 +8,12 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
import { type UIComponent } from "../../settings/UIFeature";
|
||||
import { ComponentVisibilityCustomisations } from "../ComponentVisibility";
|
||||
import { ModuleApi } from "../../modules/Api.ts";
|
||||
|
||||
export function shouldShowComponent(component: UIComponent): boolean {
|
||||
return ComponentVisibilityCustomisations.shouldShowComponent?.(component) ?? true;
|
||||
return (
|
||||
ModuleApi.instance.customisations.shouldShowComponent(component) ??
|
||||
ComponentVisibilityCustomisations.shouldShowComponent?.(component) ??
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import { ElementWebBuiltinsApi } from "./BuiltinsApi.tsx";
|
||||
import { ClientApi } from "./ClientApi.ts";
|
||||
import { StoresApi } from "./StoresApi.ts";
|
||||
import { WidgetLifecycleApi } from "./WidgetLifecycleApi.ts";
|
||||
import { CustomisationsApi } from "./customisationsApi.ts";
|
||||
|
||||
const legacyCustomisationsFactory = <T extends object>(baseCustomisations: T) => {
|
||||
let used = false;
|
||||
@@ -84,6 +85,7 @@ export class ModuleApi implements Api {
|
||||
public readonly config = new ConfigApi();
|
||||
public readonly i18n = new I18nApi();
|
||||
public readonly customComponents = new CustomComponentsApi();
|
||||
public readonly customisations = new CustomisationsApi();
|
||||
public readonly extras = new ElementWebExtrasApi();
|
||||
public readonly builtins = new ElementWebBuiltinsApi();
|
||||
public readonly widgetLifecycle = new WidgetLifecycleApi();
|
||||
|
||||
@@ -16,6 +16,7 @@ import type {
|
||||
CustomMessageRenderHints as ModuleCustomCustomMessageRenderHints,
|
||||
MatrixEvent as ModuleMatrixEvent,
|
||||
CustomRoomPreviewBarRenderFunction,
|
||||
CustomLoginRenderFunction,
|
||||
} from "@element-hq/element-web-module-api";
|
||||
import type React from "react";
|
||||
|
||||
@@ -153,4 +154,21 @@ export class CustomComponentsApi implements ICustomComponentsApi {
|
||||
public registerRoomPreviewBar(renderer: CustomRoomPreviewBarRenderFunction): void {
|
||||
this._roomPreviewBarRenderer = renderer;
|
||||
}
|
||||
|
||||
private _loginRenderer?: CustomLoginRenderFunction;
|
||||
|
||||
/**
|
||||
* Get the custom login component renderer, if any has been registered.
|
||||
*/
|
||||
public get loginComponentRenderer(): CustomLoginRenderFunction | undefined {
|
||||
return this._loginRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom login component renderer.
|
||||
* @param renderer - the function that will render the login component.
|
||||
*/
|
||||
public registerLoginComponent(renderer: CustomLoginRenderFunction): void {
|
||||
this._loginRenderer = renderer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations 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 { UIComponent, CustomisationsApi as ICustomisationsApi } from "@element-hq/element-web-module-api";
|
||||
|
||||
export class CustomisationsApi implements ICustomisationsApi {
|
||||
private shouldShowComponentFunctions = new Set<(component: UIComponent) => boolean | void>();
|
||||
|
||||
/**
|
||||
* Method to register a callback which can affect whether a given component is drawn or not.
|
||||
* @param fn - the callback, if it returns true the component will be rendered, if false it will not be.
|
||||
* If undefined will defer to the next callback, ultimately falling through to `true` if none return false.
|
||||
* The next callback is decided in FIFO call order to this register function.
|
||||
*/
|
||||
public registerShouldShowComponent(fn: (this: void, component: UIComponent) => boolean | void): void {
|
||||
this.shouldShowComponentFunctions.add(fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to check whether, according to any registered modules, a given component should be rendered.
|
||||
* @param component - the component to check
|
||||
*/
|
||||
public shouldShowComponent(component: UIComponent): boolean | void {
|
||||
for (const fn of this.shouldShowComponentFunctions) {
|
||||
const v = fn(component);
|
||||
if (typeof v === "boolean") {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,44 +28,4 @@ export const enum UIFeature {
|
||||
AllowCreatingPublicSpaces = "UIFeature.allowCreatingPublicSpaces",
|
||||
}
|
||||
|
||||
export enum UIComponent {
|
||||
/**
|
||||
* Components that lead to a user being invited.
|
||||
*/
|
||||
InviteUsers = "UIComponent.sendInvites",
|
||||
|
||||
/**
|
||||
* Components that lead to a room being created that aren't already
|
||||
* guarded by some other condition (ie: "only if you can edit this
|
||||
* space" is *not* guarded by this component, but "start DM" is).
|
||||
*/
|
||||
CreateRooms = "UIComponent.roomCreation",
|
||||
|
||||
/**
|
||||
* Components that lead to a Space being created that aren't already
|
||||
* guarded by some other condition (ie: "only if you can add subspaces"
|
||||
* is *not* guarded by this component, but "create new space" is).
|
||||
*/
|
||||
CreateSpaces = "UIComponent.spaceCreation",
|
||||
|
||||
/**
|
||||
* Components that lead to the public room directory.
|
||||
*/
|
||||
ExploreRooms = "UIComponent.exploreRooms",
|
||||
|
||||
/**
|
||||
* Components that lead to the user being able to easily add widgets
|
||||
* and integrations to the room, such as from the room information card.
|
||||
*/
|
||||
AddIntegrations = "UIComponent.addIntegrations",
|
||||
|
||||
/**
|
||||
* Component that lead to the user being able to search, dial, explore rooms
|
||||
*/
|
||||
FilterContainer = "UIComponent.filterContainer",
|
||||
|
||||
/**
|
||||
* Components that lead the user to room options menu.
|
||||
*/
|
||||
RoomOptionsMenu = "UIComponent.roomOptionsMenu",
|
||||
}
|
||||
export { UIComponent } from "@element-hq/element-web-module-api";
|
||||
|
||||
@@ -20,6 +20,7 @@ import Login from "../../../../../src/components/structures/auth/Login";
|
||||
import type BasePlatform from "../../../../../src/BasePlatform";
|
||||
import * as registerClientUtils from "../../../../../src/utils/oidc/registerClient";
|
||||
import { makeDelegatedAuthConfig } from "../../../../test-utils/oidc";
|
||||
import { ModuleApi } from "../../../../../src/modules/Api.ts";
|
||||
|
||||
jest.useRealTimers();
|
||||
|
||||
@@ -100,6 +101,35 @@ describe("Login", function () {
|
||||
expect(container.querySelector(".mx_ServerPicker_change")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should show register button", async () => {
|
||||
const onRegisterClick = jest.fn();
|
||||
const { getByText } = render(
|
||||
<Login
|
||||
serverConfig={mkServerConfig("https://matrix.org", "https://vector.im")}
|
||||
onLoggedIn={() => {}}
|
||||
onRegisterClick={onRegisterClick}
|
||||
onServerConfigChange={() => {}}
|
||||
/>,
|
||||
);
|
||||
await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
|
||||
|
||||
fireEvent.click(getByText("Create an account"));
|
||||
expect(onRegisterClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should hide register button", async () => {
|
||||
const { queryByText } = render(
|
||||
<Login
|
||||
serverConfig={mkServerConfig("https://matrix.org", "https://vector.im")}
|
||||
onLoggedIn={() => {}}
|
||||
onServerConfigChange={() => {}}
|
||||
/>,
|
||||
);
|
||||
await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
|
||||
|
||||
expect(queryByText("Create an account")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should show form without change server link when custom URLs disabled", async () => {
|
||||
const { container } = getComponent();
|
||||
await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading…"));
|
||||
@@ -417,4 +447,16 @@ describe("Login", function () {
|
||||
expect(screen.getByText("Continue")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Module API", () => {
|
||||
afterEach(() => {
|
||||
ModuleApi.instance.customComponents.registerLoginComponent(undefined as any);
|
||||
});
|
||||
|
||||
it("should use registered module renderer", async () => {
|
||||
ModuleApi.instance.customComponents.registerLoginComponent(() => <>Test component</>);
|
||||
const { getByText } = getComponent();
|
||||
expect(getByText("Test component")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations 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 { CustomisationsApi } from "../../../src/modules/customisationsApi";
|
||||
import { UIComponent } from "../../../src/settings/UIFeature.ts";
|
||||
|
||||
describe("CustomisationsApi", () => {
|
||||
let api: CustomisationsApi;
|
||||
|
||||
beforeEach(() => {
|
||||
api = new CustomisationsApi();
|
||||
});
|
||||
|
||||
it("should register a shouldShowComponent callback", () => {
|
||||
const shouldShowComponent = jest.fn().mockReturnValue(true);
|
||||
api.registerShouldShowComponent(shouldShowComponent);
|
||||
expect(api.shouldShowComponent(UIComponent.CreateRooms)).toBe(true);
|
||||
expect(shouldShowComponent).toHaveBeenCalledWith("UIComponent.roomCreation");
|
||||
});
|
||||
});
|
||||
Generated
+10
-10
@@ -7,8 +7,8 @@ settings:
|
||||
catalogs:
|
||||
default:
|
||||
'@element-hq/element-web-module-api':
|
||||
specifier: 1.10.0
|
||||
version: 1.10.0
|
||||
specifier: 1.11.0
|
||||
version: 1.11.0
|
||||
'@element-hq/element-web-playwright-common':
|
||||
specifier: 2.2.7
|
||||
version: 2.2.7
|
||||
@@ -149,7 +149,7 @@ importers:
|
||||
version: 7.28.6
|
||||
'@element-hq/element-web-module-api':
|
||||
specifier: 'catalog:'
|
||||
version: 1.10.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)
|
||||
version: 1.11.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)
|
||||
'@element-hq/web-shared-components':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/shared-components
|
||||
@@ -423,7 +423,7 @@ importers:
|
||||
version: 0.16.3
|
||||
'@element-hq/element-web-playwright-common':
|
||||
specifier: 'catalog:'
|
||||
version: 2.2.7(@element-hq/element-web-module-api@1.10.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4))(@playwright/test@1.58.2)(playwright-core@1.58.2)
|
||||
version: 2.2.7(@element-hq/element-web-module-api@1.11.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4))(@playwright/test@1.58.2)(playwright-core@1.58.2)
|
||||
'@element-hq/element-web-playwright-common-local':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/playwright-common
|
||||
@@ -762,7 +762,7 @@ importers:
|
||||
dependencies:
|
||||
'@element-hq/element-web-module-api':
|
||||
specifier: 'catalog:'
|
||||
version: 1.10.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)
|
||||
version: 1.11.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)
|
||||
'@matrix-org/spec':
|
||||
specifier: ^1.7.0
|
||||
version: 1.16.0
|
||||
@@ -2016,8 +2016,8 @@ packages:
|
||||
'@element-hq/element-call-embedded@0.16.3':
|
||||
resolution: {integrity: sha512-OViKJonDaDNVBUW9WdV9mk78/Ruh34C7XsEgt3O8D9z+64C39elbIgllHSoH5S12IRlv9RYrrV37FZLo6QWsDQ==}
|
||||
|
||||
'@element-hq/element-web-module-api@1.10.0':
|
||||
resolution: {integrity: sha512-XIl6E73dn0cmR/03TRCpq7epyFQAa93GUz1j7EBP2pv5Erh59gq788ajFM2XYl7W2afRU0aasvJoI3iZIHbRig==}
|
||||
'@element-hq/element-web-module-api@1.11.0':
|
||||
resolution: {integrity: sha512-RBkvt+Z32CGLkiPtYcQTryQBjG01ZrSVV98CS1cPz/kTeBtxEbVBpqDoOLdGvpmVe0dWo4DLaFcldw2iK39TPA==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
peerDependencies:
|
||||
'@matrix-org/react-sdk-module-api': '*'
|
||||
@@ -11980,7 +11980,7 @@ snapshots:
|
||||
|
||||
'@element-hq/element-call-embedded@0.16.3': {}
|
||||
|
||||
'@element-hq/element-web-module-api@1.10.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)':
|
||||
'@element-hq/element-web-module-api@1.11.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)':
|
||||
dependencies:
|
||||
'@types/react': 19.2.10
|
||||
'@types/react-dom': 19.2.3(@types/react@19.2.10)
|
||||
@@ -11989,10 +11989,10 @@ snapshots:
|
||||
'@matrix-org/react-sdk-module-api': 2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4)
|
||||
matrix-web-i18n: 3.6.0
|
||||
|
||||
'@element-hq/element-web-playwright-common@2.2.7(@element-hq/element-web-module-api@1.10.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4))(@playwright/test@1.58.2)(playwright-core@1.58.2)':
|
||||
'@element-hq/element-web-playwright-common@2.2.7(@element-hq/element-web-module-api@1.11.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4))(@playwright/test@1.58.2)(playwright-core@1.58.2)':
|
||||
dependencies:
|
||||
'@axe-core/playwright': 4.11.1(playwright-core@1.58.2)
|
||||
'@element-hq/element-web-module-api': 1.10.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)
|
||||
'@element-hq/element-web-module-api': 1.11.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4)
|
||||
'@playwright/test': 1.58.2
|
||||
'@testcontainers/postgresql': 11.11.0
|
||||
glob: 13.0.6
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ catalog:
|
||||
"@playwright/test": 1.58.2
|
||||
"playwright-core": 1.58.2
|
||||
# Module API
|
||||
"@element-hq/element-web-module-api": 1.10.0
|
||||
"@element-hq/element-web-module-api": 1.11.0
|
||||
# Compound
|
||||
"@vector-im/compound-design-tokens": 6.10.1
|
||||
"@vector-im/compound-web": 8.4.0
|
||||
|
||||
Reference in New Issue
Block a user