Compare commits
10 commits
develop
...
t3chguy/re
Author | SHA1 | Date | |
---|---|---|---|
|
6946b90b11 | ||
|
c3f3c9364f | ||
|
72f155640d | ||
|
b597abf567 | ||
|
9443426edb | ||
|
6c2334c029 | ||
|
eb1a09a912 | ||
|
e730074e1b | ||
|
c8c5ef5e6e | ||
|
b61a2225b7 |
|
@ -1,5 +1,5 @@
|
|||
module.exports = {
|
||||
plugins: ["matrix-org"],
|
||||
plugins: ["matrix-org", "eslint-plugin-react-compiler"],
|
||||
extends: ["plugin:matrix-org/babel", "plugin:matrix-org/react", "plugin:matrix-org/a11y"],
|
||||
parserOptions: {
|
||||
project: ["./tsconfig.json"],
|
||||
|
@ -170,6 +170,8 @@ module.exports = {
|
|||
"jsx-a11y/role-supports-aria-props": "off",
|
||||
|
||||
"matrix-org/require-copyright-header": "error",
|
||||
|
||||
"react-compiler/react-compiler": "error",
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
|
@ -262,6 +264,7 @@ module.exports = {
|
|||
|
||||
// These are fine in tests
|
||||
"no-restricted-globals": "off",
|
||||
"react-compiler/react-compiler": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
1
.github/CODEOWNERS
vendored
|
@ -13,7 +13,6 @@
|
|||
|
||||
# Ignore translations as those will be updated by GHA for Localazy download
|
||||
/src/i18n/strings
|
||||
/src/i18n/strings/en_EN.json @element-hq/element-web-reviewers
|
||||
# Ignore the synapse plugin as this is updated by GHA for docker image updating
|
||||
/playwright/plugins/homeserver/synapse/index.ts
|
||||
|
||||
|
|
6
.github/workflows/end-to-end-tests.yaml
vendored
|
@ -130,12 +130,8 @@ jobs:
|
|||
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||
run: yarn playwright install --with-deps --no-shell chromium
|
||||
|
||||
# We skip tests tagged with @mergequeue when running on PRs, but run them in MQ and everywhere else
|
||||
- name: Run Playwright tests
|
||||
run: |
|
||||
yarn playwright test \
|
||||
--shard "${{ matrix.runner }}/${{ strategy.job-total }}" \
|
||||
${{ github.event_name == 'pull_request' && '--grep-invert @mergequeue' || '' }}
|
||||
run: yarn playwright test --shard ${{ matrix.runner }}/${{ strategy.job-total }}
|
||||
|
||||
- name: Upload blob report to GitHub Actions Artifacts
|
||||
if: always()
|
||||
|
|
2
.github/workflows/tests.yml
vendored
|
@ -104,7 +104,7 @@ jobs:
|
|||
|
||||
- name: Skip SonarCloud in merge queue
|
||||
if: github.event_name == 'merge_group' || inputs.disable_coverage == 'true'
|
||||
uses: guibranco/github-status-action-v2@d469d49426f5a7b8a1fbcac20ad274d3e4892321
|
||||
uses: guibranco/github-status-action-v2@66088c44e212a906c32a047529a213d81809ec1c
|
||||
with:
|
||||
authToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
state: success
|
||||
|
|
|
@ -17,6 +17,7 @@ class MockMap extends EventEmitter {
|
|||
setCenter = jest.fn();
|
||||
setStyle = jest.fn();
|
||||
fitBounds = jest.fn();
|
||||
remove = jest.fn();
|
||||
}
|
||||
const MockMapInstance = new MockMap();
|
||||
|
||||
|
|
|
@ -217,10 +217,3 @@ instead of the native `toHaveScreenshot`.
|
|||
|
||||
If you are running Linux and are unfortunate that the screenshots are not rendering identically,
|
||||
you may wish to specify `--ignore-snapshots` and rely on Docker to render them for you.
|
||||
|
||||
## Test Tags
|
||||
|
||||
We use test tags to categorise tests for running subsets more efficiently.
|
||||
|
||||
- `@mergequeue`: Tests that are slow or flaky and cover areas of the app we update seldom, should not be run on every PR commit but will be run in the Merge Queue.
|
||||
- `@screenshot`: Tests that use `toMatchScreenshot` to speed up a run of `test:playwright:screenshots`. A test with this tag must not also have the `@mergequeue` tag as this would cause false positives in the stale screenshot detection.
|
||||
|
|
13
package.json
|
@ -88,7 +88,7 @@
|
|||
"@matrix-org/spec": "^1.7.0",
|
||||
"@sentry/browser": "^8.0.0",
|
||||
"@vector-im/compound-design-tokens": "^2.0.1",
|
||||
"@vector-im/compound-web": "^7.5.0",
|
||||
"@vector-im/compound-web": "^7.4.0",
|
||||
"@vector-im/matrix-wysiwyg": "2.37.13",
|
||||
"@zxcvbn-ts/core": "^3.0.4",
|
||||
"@zxcvbn-ts/language-common": "^3.0.4",
|
||||
|
@ -116,10 +116,10 @@
|
|||
"jsrsasign": "^11.0.0",
|
||||
"jszip": "^3.7.0",
|
||||
"katex": "^0.16.0",
|
||||
"linkify-element": "4.2.0",
|
||||
"linkify-react": "4.2.0",
|
||||
"linkify-string": "4.2.0",
|
||||
"linkifyjs": "4.2.0",
|
||||
"linkify-element": "4.1.4",
|
||||
"linkify-react": "4.1.4",
|
||||
"linkify-string": "4.1.4",
|
||||
"linkifyjs": "4.1.4",
|
||||
"lodash": "^4.17.21",
|
||||
"maplibre-gl": "^4.0.0",
|
||||
"matrix-encrypt-attachment": "^1.0.3",
|
||||
|
@ -233,6 +233,7 @@
|
|||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-matrix-org": "^2.0.2",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-compiler": "^19.0.0-beta-df7b47d-20241124",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"eslint-plugin-unicorn": "^56.0.0",
|
||||
"express": "^4.18.2",
|
||||
|
@ -269,7 +270,7 @@
|
|||
"postcss-preset-env": "^10.0.0",
|
||||
"postcss-scss": "^4.0.4",
|
||||
"postcss-simple-vars": "^7.0.1",
|
||||
"prettier": "3.4.2",
|
||||
"prettier": "3.4.1",
|
||||
"process": "^0.11.10",
|
||||
"raw-loader": "^4.0.2",
|
||||
"rimraf": "^6.0.0",
|
||||
|
|
|
@ -8,7 +8,6 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { type Preset, type Visibility } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import type { Page } from "@playwright/test";
|
||||
import { test, expect } from "../../element-web-test";
|
||||
import { doTwoWaySasVerification, awaitVerifier } from "./utils";
|
||||
import { Client } from "../../pages/client";
|
||||
|
@ -39,8 +38,6 @@ test.describe("User verification", () => {
|
|||
toasts,
|
||||
room: { roomId: dmRoomId },
|
||||
}) => {
|
||||
await waitForDeviceKeys(page);
|
||||
|
||||
// once Alice has joined, Bob starts the verification
|
||||
const bobVerificationRequest = await bob.evaluateHandle(
|
||||
async (client, { dmRoomId, aliceCredentials }) => {
|
||||
|
@ -90,8 +87,6 @@ test.describe("User verification", () => {
|
|||
toasts,
|
||||
room: { roomId: dmRoomId },
|
||||
}) => {
|
||||
await waitForDeviceKeys(page);
|
||||
|
||||
// once Alice has joined, Bob starts the verification
|
||||
const bobVerificationRequest = await bob.evaluateHandle(
|
||||
async (client, { dmRoomId, aliceCredentials }) => {
|
||||
|
@ -154,15 +149,3 @@ async function createDMRoom(client: Client, userId: string): Promise<string> {
|
|||
],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until we get the other user's device keys.
|
||||
* In newer rust-crypto versions, the verification request will be ignored if we
|
||||
* don't have the sender's device keys.
|
||||
*/
|
||||
async function waitForDeviceKeys(page: Page): Promise<void> {
|
||||
await expect(page.getByRole("button", { name: "Avatar" })).toBeVisible();
|
||||
const avatar = await page.getByRole("button", { name: "Avatar" });
|
||||
await avatar.click();
|
||||
await expect(page.getByText("1 session")).toBeVisible();
|
||||
}
|
||||
|
|
|
@ -129,7 +129,6 @@ export class Helpers {
|
|||
const timelineMessage = this.page.locator(".mx_MTextBody", { hasText: message });
|
||||
await timelineMessage.click({ button: "right" });
|
||||
await this.page.getByRole("menuitem", { name: "Pin", exact: true }).click();
|
||||
await this.assertMessageInBanner(message);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("editing messages", () => {
|
||||
test.describe("in threads", () => {
|
||||
test("An edit of a threaded message makes the room unread", async ({
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("editing messages", () => {
|
||||
test.describe("in the main timeline", () => {
|
||||
test("Editing a message leaves a room read", async ({ roomAlpha: room1, roomBeta: room2, util, msg }) => {
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("editing messages", () => {
|
||||
test.describe("thread roots", () => {
|
||||
test("An edit of a thread root leaves the room read", async ({
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { customEvent, many, test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("Ignored events", () => {
|
||||
test("If all events after receipt are unimportant, the room is read", async ({
|
||||
roomAlpha: room1,
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("Message ordering", () => {
|
||||
test.describe("in the main timeline", () => {
|
||||
test.fixme(
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("messages with missing referents", () => {
|
||||
test.fixme(
|
||||
"A message in an unknown thread is not visible and the room is read",
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { many, test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("new messages", () => {
|
||||
test.describe("in threads", () => {
|
||||
test("Receiving a message makes a room unread", async ({
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { many, test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("new messages", () => {
|
||||
test.describe("in the main timeline", () => {
|
||||
test("Receiving a message makes a room unread", async ({
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { many, test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("new messages", () => {
|
||||
test.describe("thread roots", () => {
|
||||
test("Reading a thread root does not mark the thread as read", async ({
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("Notifications", () => {
|
||||
test.describe("in the main timeline", () => {
|
||||
test.fixme("A new message that mentions me shows a notification", () => {});
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test, expect } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("reactions", () => {
|
||||
test.describe("in threads", () => {
|
||||
test("A reaction to a threaded message does not make the room unread", async ({
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("reactions", () => {
|
||||
test.describe("in the main timeline", () => {
|
||||
test("Receiving a reaction to a message does not make a room unread", async ({
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("reactions", () => {
|
||||
test.describe("thread roots", () => {
|
||||
test("A reaction to a thread root does not make the room unread", async ({
|
||||
|
|
|
@ -13,7 +13,7 @@ import { ElementAppPage } from "../../pages/ElementAppPage";
|
|||
import { Bot } from "../../pages/bot";
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.use({
|
||||
displayName: "Mae",
|
||||
botCreateOpts: { displayName: "Other User" },
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("redactions", () => {
|
||||
test.describe("in threads", () => {
|
||||
test("Redacting the threaded message pointed to by my receipt leaves the room read", async ({
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("redactions", () => {
|
||||
test.describe("in the main timeline", () => {
|
||||
test("Redacting the message pointed to by my receipt leaves the room read", async ({
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("redactions", () => {
|
||||
test.describe("thread roots", () => {
|
||||
test("Redacting a thread root after it was read leaves the room read", async ({
|
||||
|
|
|
@ -10,7 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import { test } from ".";
|
||||
|
||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
test.describe("Read receipts", () => {
|
||||
test.describe("Room list order", () => {
|
||||
test("Rooms with unread messages appear at the top of room list if 'unread first' is selected", async ({
|
||||
roomAlpha: room1,
|
||||
|
|
|
@ -20,7 +20,7 @@ import { randB64Bytes } from "../../utils/rand";
|
|||
// Docker tag to use for synapse docker image.
|
||||
// We target a specific digest as every now and then a Synapse update will break our CI.
|
||||
// This digest is updated by the playwright-image-updates.yaml workflow periodically.
|
||||
const DOCKER_TAG = "develop@sha256:6b82dba715fa7ae641010b4cc5e71edaeb9cc05a50ac5b9e4ff09afa9cd2a80d";
|
||||
const DOCKER_TAG = "develop@sha256:48308e18c5b3ad20bc0d090119618f45b6be4ba727522e37fbf7827d1a109531";
|
||||
|
||||
async function cfgDirFromTemplate(opts: StartHomeserverOpts): Promise<Omit<HomeserverConfig, "dockerUrl">> {
|
||||
const templateDir = path.join(__dirname, "templates", opts.template);
|
||||
|
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.1 KiB |
2
src/@types/global.d.ts
vendored
|
@ -44,7 +44,6 @@ import { IConfigOptions } from "../IConfigOptions";
|
|||
import { MatrixDispatcher } from "../dispatcher/dispatcher";
|
||||
import { DeepReadonly } from "./common";
|
||||
import MatrixChat from "../components/structures/MatrixChat";
|
||||
import { InitialCryptoSetupStore } from "../stores/InitialCryptoSetupStore";
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
|
@ -118,7 +117,6 @@ declare global {
|
|||
mxPerformanceEntryNames: any;
|
||||
mxUIStore: UIStore;
|
||||
mxSetupEncryptionStore?: SetupEncryptionStore;
|
||||
mxInitialCryptoStore?: InitialCryptoSetupStore;
|
||||
mxRoomScrollStateStore?: RoomScrollStateStore;
|
||||
mxActiveWidgetStore?: ActiveWidgetStore;
|
||||
mxOnRecaptchaLoaded?: () => void;
|
||||
|
|
|
@ -8,24 +8,25 @@ 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, { forwardRef, Ref } from "react";
|
||||
import React, { ComponentProps, forwardRef, Ref } from "react";
|
||||
|
||||
import AccessibleButton, { ButtonProps } from "../../components/views/elements/AccessibleButton";
|
||||
import AccessibleButton from "../../components/views/elements/AccessibleButton";
|
||||
|
||||
type Props<T extends keyof HTMLElementTagNameMap> = ButtonProps<T> & {
|
||||
type Props<T extends keyof JSX.IntrinsicElements> = ComponentProps<typeof AccessibleButton<T>> & {
|
||||
label?: string;
|
||||
// whether the context menu is currently open
|
||||
isExpanded: boolean;
|
||||
};
|
||||
|
||||
// Semantic component for representing the AccessibleButton which launches a <ContextMenu />
|
||||
export const ContextMenuButton = forwardRef(function <T extends keyof HTMLElementTagNameMap>(
|
||||
{ label, isExpanded, children, onClick, onContextMenu, ...props }: Props<T>,
|
||||
ref: Ref<HTMLElementTagNameMap[T]>,
|
||||
export const ContextMenuButton = forwardRef(function <T extends keyof JSX.IntrinsicElements>(
|
||||
{ label, isExpanded, children, onClick, onContextMenu, element, ...props }: Props<T>,
|
||||
ref: Ref<HTMLElement>,
|
||||
) {
|
||||
return (
|
||||
<AccessibleButton
|
||||
{...props}
|
||||
element={element as keyof JSX.IntrinsicElements}
|
||||
onClick={onClick}
|
||||
onContextMenu={onContextMenu ?? onClick ?? undefined}
|
||||
aria-label={label}
|
||||
|
|
|
@ -8,23 +8,24 @@ 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, { forwardRef, Ref } from "react";
|
||||
import React, { ComponentProps, forwardRef, Ref } from "react";
|
||||
|
||||
import AccessibleButton, { ButtonProps } from "../../components/views/elements/AccessibleButton";
|
||||
import AccessibleButton from "../../components/views/elements/AccessibleButton";
|
||||
|
||||
type Props<T extends keyof HTMLElementTagNameMap> = ButtonProps<T> & {
|
||||
type Props<T extends keyof JSX.IntrinsicElements> = ComponentProps<typeof AccessibleButton<T>> & {
|
||||
// whether the context menu is currently open
|
||||
isExpanded: boolean;
|
||||
};
|
||||
|
||||
// Semantic component for representing the AccessibleButton which launches a <ContextMenu />
|
||||
export const ContextMenuTooltipButton = forwardRef(function <T extends keyof HTMLElementTagNameMap>(
|
||||
{ isExpanded, children, onClick, onContextMenu, ...props }: Props<T>,
|
||||
ref: Ref<HTMLElementTagNameMap[T]>,
|
||||
export const ContextMenuTooltipButton = forwardRef(function <T extends keyof JSX.IntrinsicElements>(
|
||||
{ isExpanded, children, onClick, onContextMenu, element, ...props }: Props<T>,
|
||||
ref: Ref<HTMLElement>,
|
||||
) {
|
||||
return (
|
||||
<AccessibleButton
|
||||
{...props}
|
||||
element={element as keyof JSX.IntrinsicElements}
|
||||
onClick={onClick}
|
||||
onContextMenu={onContextMenu ?? onClick ?? undefined}
|
||||
aria-haspopup={true}
|
||||
|
|
|
@ -6,33 +6,39 @@ 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, { RefObject } from "react";
|
||||
import React, { ComponentProps } from "react";
|
||||
|
||||
import AccessibleButton, { ButtonProps } from "../../components/views/elements/AccessibleButton";
|
||||
import AccessibleButton from "../../components/views/elements/AccessibleButton";
|
||||
import { useRovingTabIndex } from "../RovingTabIndex";
|
||||
import { Ref } from "./types";
|
||||
|
||||
type Props<T extends keyof HTMLElementTagNameMap> = Omit<ButtonProps<T>, "tabIndex"> & {
|
||||
inputRef?: RefObject<HTMLElementTagNameMap[T]>;
|
||||
type Props<T extends keyof JSX.IntrinsicElements> = Omit<
|
||||
ComponentProps<typeof AccessibleButton<T>>,
|
||||
"inputRef" | "tabIndex"
|
||||
> & {
|
||||
inputRef?: Ref;
|
||||
focusOnMouseOver?: boolean;
|
||||
};
|
||||
|
||||
// Wrapper to allow use of useRovingTabIndex for simple AccessibleButtons outside of React Functional Components.
|
||||
export const RovingAccessibleButton = <T extends keyof HTMLElementTagNameMap>({
|
||||
export const RovingAccessibleButton = <T extends keyof JSX.IntrinsicElements>({
|
||||
inputRef,
|
||||
onFocus,
|
||||
onMouseOver,
|
||||
focusOnMouseOver,
|
||||
element,
|
||||
...props
|
||||
}: Props<T>): JSX.Element => {
|
||||
const [onFocusInternal, isActive, ref] = useRovingTabIndex<HTMLElementTagNameMap[T]>(inputRef);
|
||||
const [onFocusInternal, isActive, ref] = useRovingTabIndex(inputRef);
|
||||
return (
|
||||
<AccessibleButton
|
||||
{...props}
|
||||
onFocus={(event: React.FocusEvent<never, never>) => {
|
||||
element={element as keyof JSX.IntrinsicElements}
|
||||
onFocus={(event: React.FocusEvent) => {
|
||||
onFocusInternal();
|
||||
onFocus?.(event);
|
||||
}}
|
||||
onMouseOver={(event: React.MouseEvent<never, never>) => {
|
||||
onMouseOver={(event: React.MouseEvent) => {
|
||||
if (focusOnMouseOver) onFocusInternal();
|
||||
onMouseOver?.(event);
|
||||
}}
|
||||
|
|
|
@ -132,7 +132,6 @@ import { SessionLockStolenView } from "./auth/SessionLockStolenView";
|
|||
import { ConfirmSessionLockTheftView } from "./auth/ConfirmSessionLockTheftView";
|
||||
import { LoginSplashView } from "./auth/LoginSplashView";
|
||||
import { cleanUpDraftsIfRequired } from "../../DraftCleaner";
|
||||
import { InitialCryptoSetupStore } from "../../stores/InitialCryptoSetupStore";
|
||||
|
||||
// legacy export
|
||||
export { default as Views } from "../../Views";
|
||||
|
@ -429,12 +428,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
!(await shouldSkipSetupEncryption(cli))
|
||||
) {
|
||||
// if cross-signing is not yet set up, do so now if possible.
|
||||
InitialCryptoSetupStore.sharedInstance().startInitialCryptoSetup(
|
||||
cli,
|
||||
Boolean(this.tokenLogin),
|
||||
this.stores,
|
||||
this.onCompleteSecurityE2eSetupFinished,
|
||||
);
|
||||
this.setStateForNewView({ view: Views.E2E_SETUP });
|
||||
} else {
|
||||
this.onLoggedIn();
|
||||
|
@ -2080,7 +2073,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
} else if (this.state.view === Views.COMPLETE_SECURITY) {
|
||||
view = <CompleteSecurity onFinished={this.onCompleteSecurityE2eSetupFinished} />;
|
||||
} else if (this.state.view === Views.E2E_SETUP) {
|
||||
view = <E2eSetup onFinished={this.onCompleteSecurityE2eSetupFinished} />;
|
||||
view = (
|
||||
<E2eSetup
|
||||
matrixClient={MatrixClientPeg.safeGet()}
|
||||
onFinished={this.onCompleteSecurityE2eSetupFinished}
|
||||
accountPassword={this.stores.accountPasswordStore.getPassword()}
|
||||
tokenLogin={!!this.tokenLogin}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.view === Views.LOGGED_IN) {
|
||||
// `ready` and `view==LOGGED_IN` may be set before `page_type` (because the
|
||||
// latter is set via the dispatcher). If we don't yet have a `page_type`,
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
import React, { forwardRef, useCallback, useContext, useEffect, useRef, useState } from "react";
|
||||
import React, { forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
ISearchResults,
|
||||
IThreadBundledRelationship,
|
||||
|
@ -58,7 +58,7 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
|
|||
const [results, setResults] = useState<ISearchResults | null>(null);
|
||||
const aborted = useRef(false);
|
||||
// A map from room ID to permalink creator
|
||||
const permalinkCreators = useRef(new Map<string, RoomPermalinkCreator>()).current;
|
||||
const permalinkCreators = useMemo(() => new Map<string, RoomPermalinkCreator>(), []);
|
||||
const innerRef = useRef<ScrollPanel | null>();
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -2372,11 +2372,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
);
|
||||
|
||||
const pinnedMessageBanner = (
|
||||
<PinnedMessageBanner
|
||||
room={this.state.room}
|
||||
permalinkCreator={this.permalinkCreator}
|
||||
resizeNotifier={this.props.resizeNotifier}
|
||||
/>
|
||||
<PinnedMessageBanner room={this.state.room} permalinkCreator={this.permalinkCreator} />
|
||||
);
|
||||
|
||||
let messageComposer;
|
||||
|
|
|
@ -7,13 +7,17 @@ Please see LICENSE files in the repository root for full details.
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import AuthPage from "../../views/auth/AuthPage";
|
||||
import CompleteSecurityBody from "../../views/auth/CompleteSecurityBody";
|
||||
import { InitialCryptoSetupDialog } from "../../views/dialogs/security/InitialCryptoSetupDialog";
|
||||
import CreateCrossSigningDialog from "../../views/dialogs/security/CreateCrossSigningDialog";
|
||||
|
||||
interface IProps {
|
||||
matrixClient: MatrixClient;
|
||||
onFinished: () => void;
|
||||
accountPassword?: string;
|
||||
tokenLogin: boolean;
|
||||
}
|
||||
|
||||
export default class E2eSetup extends React.Component<IProps> {
|
||||
|
@ -21,7 +25,12 @@ export default class E2eSetup extends React.Component<IProps> {
|
|||
return (
|
||||
<AuthPage>
|
||||
<CompleteSecurityBody>
|
||||
<InitialCryptoSetupDialog onFinished={this.props.onFinished} />
|
||||
<CreateCrossSigningDialog
|
||||
matrixClient={this.props.matrixClient}
|
||||
onFinished={this.props.onFinished}
|
||||
accountPassword={this.props.accountPassword}
|
||||
tokenLogin={this.props.tokenLogin}
|
||||
/>
|
||||
</CompleteSecurityBody>
|
||||
</AuthPage>
|
||||
);
|
||||
|
|
|
@ -235,7 +235,12 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
|||
value={this.state.password}
|
||||
disabled={this.state.busy}
|
||||
/>
|
||||
<AccessibleButton onClick={this.onPasswordLogin} kind="primary" disabled={this.state.busy}>
|
||||
<AccessibleButton
|
||||
onClick={this.onPasswordLogin}
|
||||
kind="primary"
|
||||
type="submit"
|
||||
disabled={this.state.busy}
|
||||
>
|
||||
{_t("action|sign_in")}
|
||||
</AccessibleButton>
|
||||
<AccessibleButton onClick={this.onForgotPassword} kind="link">
|
||||
|
|
|
@ -910,7 +910,7 @@ export class SSOAuthEntry extends React.Component<ISSOAuthEntryProps, ISSOAuthEn
|
|||
|
||||
export class FallbackAuthEntry<T = {}> extends React.Component<IAuthEntryProps & T> {
|
||||
protected popupWindow: Window | null;
|
||||
protected fallbackButton = createRef<HTMLDivElement>();
|
||||
protected fallbackButton = createRef<HTMLButtonElement>();
|
||||
|
||||
public constructor(props: IAuthEntryProps & T) {
|
||||
super(props);
|
||||
|
|
|
@ -298,7 +298,7 @@ const SettingsList: React.FC<ISettingsListProps> = ({ onBack, onView, onEdit })
|
|||
<code>{i}</code>
|
||||
</AccessibleButton>
|
||||
<AccessibleButton
|
||||
title={_t("devtools|edit_setting")}
|
||||
alt={_t("devtools|edit_setting")}
|
||||
onClick={() => onEdit(i)}
|
||||
className="mx_DevTools_SettingsExplorer_edit"
|
||||
>
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2018, 2019 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 React, { useCallback, useEffect, useState } from "react";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { _t } from "../../../../languageHandler";
|
||||
import DialogButtons from "../../elements/DialogButtons";
|
||||
import BaseDialog from "../BaseDialog";
|
||||
import Spinner from "../../elements/Spinner";
|
||||
import { createCrossSigning } from "../../../../CreateCrossSigning";
|
||||
|
||||
interface Props {
|
||||
matrixClient: MatrixClient;
|
||||
accountPassword?: string;
|
||||
tokenLogin: boolean;
|
||||
onFinished: (success?: boolean) => void;
|
||||
}
|
||||
|
||||
/*
|
||||
* Walks the user through the process of creating a cross-signing keys. In most
|
||||
* cases, only a spinner is shown, but for more complex auth like SSO, the user
|
||||
* may need to complete some steps to proceed.
|
||||
*/
|
||||
const CreateCrossSigningDialog: React.FC<Props> = ({ matrixClient, accountPassword, tokenLogin, onFinished }) => {
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
const bootstrapCrossSigning = useCallback(async () => {
|
||||
const cryptoApi = matrixClient.getCrypto();
|
||||
if (!cryptoApi) return;
|
||||
|
||||
setError(false);
|
||||
|
||||
try {
|
||||
await createCrossSigning(matrixClient, tokenLogin, accountPassword);
|
||||
onFinished(true);
|
||||
} catch (e) {
|
||||
if (tokenLogin) {
|
||||
// ignore any failures, we are relying on grace period here
|
||||
onFinished(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setError(true);
|
||||
logger.error("Error bootstrapping cross-signing", e);
|
||||
}
|
||||
}, [matrixClient, tokenLogin, accountPassword, onFinished]);
|
||||
|
||||
const onCancel = useCallback(() => {
|
||||
onFinished(false);
|
||||
}, [onFinished]);
|
||||
|
||||
useEffect(() => {
|
||||
bootstrapCrossSigning();
|
||||
}, [bootstrapCrossSigning]);
|
||||
|
||||
let content;
|
||||
if (error) {
|
||||
content = (
|
||||
<div>
|
||||
<p>{_t("encryption|unable_to_setup_keys_error")}</p>
|
||||
<div className="mx_Dialog_buttons">
|
||||
<DialogButtons
|
||||
primaryButton={_t("action|retry")}
|
||||
onPrimaryButtonClick={bootstrapCrossSigning}
|
||||
onCancel={onCancel}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<div>
|
||||
<Spinner />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
className="mx_CreateCrossSigningDialog"
|
||||
onFinished={onFinished}
|
||||
title={_t("encryption|bootstrap_title")}
|
||||
hasCancel={false}
|
||||
fixedWidth={false}
|
||||
>
|
||||
<div>{content}</div>
|
||||
</BaseDialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateCrossSigningDialog;
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2018, 2019 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 React, { useCallback } from "react";
|
||||
|
||||
import { _t } from "../../../../languageHandler";
|
||||
import DialogButtons from "../../elements/DialogButtons";
|
||||
import BaseDialog from "../BaseDialog";
|
||||
import Spinner from "../../elements/Spinner";
|
||||
import { InitialCryptoSetupStore, useInitialCryptoSetupStatus } from "../../../../stores/InitialCryptoSetupStore";
|
||||
|
||||
interface Props {
|
||||
onFinished: (success?: boolean) => void;
|
||||
}
|
||||
|
||||
/*
|
||||
* Walks the user through the process of creating a cross-signing keys.
|
||||
* In most cases, only a spinner is shown, but for more
|
||||
* complex auth like SSO, the user may need to complete some steps to proceed.
|
||||
*/
|
||||
export const InitialCryptoSetupDialog: React.FC<Props> = ({ onFinished }) => {
|
||||
const onRetryClick = useCallback(() => {
|
||||
InitialCryptoSetupStore.sharedInstance().retry();
|
||||
}, []);
|
||||
|
||||
const onCancelClick = useCallback(() => {
|
||||
onFinished(false);
|
||||
}, [onFinished]);
|
||||
|
||||
const status = useInitialCryptoSetupStatus(InitialCryptoSetupStore.sharedInstance());
|
||||
|
||||
let content;
|
||||
if (status === "error") {
|
||||
content = (
|
||||
<div>
|
||||
<p>{_t("encryption|unable_to_setup_keys_error")}</p>
|
||||
<div className="mx_Dialog_buttons">
|
||||
<DialogButtons
|
||||
primaryButton={_t("action|retry")}
|
||||
onPrimaryButtonClick={onRetryClick}
|
||||
onCancel={onCancelClick}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<div>
|
||||
<Spinner />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
className="mx_CreateCrossSigningDialog"
|
||||
onFinished={onFinished}
|
||||
title={_t("encryption|bootstrap_title")}
|
||||
hasCancel={false}
|
||||
fixedWidth={false}
|
||||
>
|
||||
<div>{content}</div>
|
||||
</BaseDialog>
|
||||
);
|
||||
};
|
|
@ -1253,7 +1253,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
|||
<span>{filterToLabel(filter)}</span>
|
||||
<AccessibleButton
|
||||
tabIndex={-1}
|
||||
title={_t("spotlight_dialog|remove_filter", {
|
||||
alt={_t("spotlight_dialog|remove_filter", {
|
||||
filter: filterToLabel(filter),
|
||||
})}
|
||||
className="mx_SpotlightDialog_filter--close"
|
||||
|
|
|
@ -13,15 +13,15 @@ import { useRovingTabIndex } from "../../../../accessibility/RovingTabIndex";
|
|||
import AccessibleButton, { ButtonProps } from "../../elements/AccessibleButton";
|
||||
import { Ref } from "../../../../accessibility/roving/types";
|
||||
|
||||
type TooltipOptionProps<T extends keyof HTMLElementTagNameMap> = ButtonProps<T> & {
|
||||
className?: string;
|
||||
type TooltipOptionProps<T extends keyof JSX.IntrinsicElements> = ButtonProps<T> & {
|
||||
endAdornment?: ReactNode;
|
||||
inputRef?: Ref;
|
||||
};
|
||||
|
||||
export const TooltipOption = <T extends keyof HTMLElementTagNameMap>({
|
||||
export const TooltipOption = <T extends keyof JSX.IntrinsicElements>({
|
||||
inputRef,
|
||||
className,
|
||||
element,
|
||||
...props
|
||||
}: TooltipOptionProps<T>): JSX.Element => {
|
||||
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
|
||||
|
@ -34,6 +34,7 @@ export const TooltipOption = <T extends keyof HTMLElementTagNameMap>({
|
|||
tabIndex={-1}
|
||||
aria-selected={isActive}
|
||||
role="option"
|
||||
element={element as keyof JSX.IntrinsicElements}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -168,7 +168,7 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
|
|||
adornment: (
|
||||
<AccessibleButton
|
||||
className="mx_NetworkDropdown_removeServer"
|
||||
title={_t("spotlight|public_rooms|network_dropdown_remove_server_adornment", { roomServer })}
|
||||
alt={_t("spotlight|public_rooms|network_dropdown_remove_server_adornment", { roomServer })}
|
||||
onClick={() => setUserDefinedServers(without(userDefinedServers, roomServer))}
|
||||
/>
|
||||
),
|
||||
|
|
|
@ -6,15 +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.
|
||||
*/
|
||||
|
||||
import React, {
|
||||
ComponentProps,
|
||||
ComponentPropsWithoutRef,
|
||||
forwardRef,
|
||||
FunctionComponent,
|
||||
ReactElement,
|
||||
KeyboardEvent,
|
||||
Ref,
|
||||
} from "react";
|
||||
import React, { ComponentProps, forwardRef, FunctionComponent, HTMLAttributes, InputHTMLAttributes, Ref } from "react";
|
||||
import classnames from "classnames";
|
||||
import { Tooltip } from "@vector-im/compound-web";
|
||||
|
||||
|
@ -46,8 +38,20 @@ export type AccessibleButtonKind =
|
|||
| "icon_primary"
|
||||
| "icon_primary_outline";
|
||||
|
||||
type ElementType = keyof HTMLElementTagNameMap;
|
||||
const defaultElement = "div";
|
||||
/**
|
||||
* This type construct allows us to specifically pass those props down to the element we’re creating that the element
|
||||
* actually supports.
|
||||
*
|
||||
* e.g., if element is set to "a", we’ll support href and target, if it’s set to "input", we support type.
|
||||
*
|
||||
* To remain compatible with existing code, we’ll continue to support InputHTMLAttributes<Element>
|
||||
*/
|
||||
type DynamicHtmlElementProps<T extends keyof JSX.IntrinsicElements> =
|
||||
JSX.IntrinsicElements[T] extends HTMLAttributes<{}> ? DynamicElementProps<T> : DynamicElementProps<"div">;
|
||||
type DynamicElementProps<T extends keyof JSX.IntrinsicElements> = Partial<
|
||||
Omit<JSX.IntrinsicElements[T], "ref" | "onClick" | "onMouseDown" | "onKeyUp" | "onKeyDown">
|
||||
> &
|
||||
Omit<InputHTMLAttributes<Element>, "onClick">;
|
||||
|
||||
type TooltipProps = ComponentProps<typeof Tooltip>;
|
||||
|
||||
|
@ -56,7 +60,7 @@ type TooltipProps = ComponentProps<typeof Tooltip>;
|
|||
*
|
||||
* Extends props accepted by the underlying element specified using the `element` prop.
|
||||
*/
|
||||
type Props<T extends ElementType = "div"> = {
|
||||
type Props<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> & {
|
||||
/**
|
||||
* The base element type. "div" by default.
|
||||
*/
|
||||
|
@ -101,12 +105,14 @@ type Props<T extends ElementType = "div"> = {
|
|||
disableTooltip?: TooltipProps["disabled"];
|
||||
};
|
||||
|
||||
export type ButtonProps<T extends ElementType> = Props<T> & Omit<ComponentPropsWithoutRef<T>, keyof Props<T>>;
|
||||
export type ButtonProps<T extends keyof JSX.IntrinsicElements> = Props<T>;
|
||||
|
||||
/**
|
||||
* Type of the props passed to the element that is rendered by AccessibleButton.
|
||||
*/
|
||||
type RenderedElementProps<T extends ElementType> = React.InputHTMLAttributes<Element> & RefProp<T>;
|
||||
interface RenderedElementProps extends React.InputHTMLAttributes<Element> {
|
||||
ref?: React.Ref<Element>;
|
||||
}
|
||||
|
||||
/**
|
||||
* AccessibleButton is a generic wrapper for any element that should be treated
|
||||
|
@ -118,9 +124,9 @@ type RenderedElementProps<T extends ElementType> = React.InputHTMLAttributes<Ele
|
|||
* @param {Object} props react element properties
|
||||
* @returns {Object} rendered react
|
||||
*/
|
||||
const AccessibleButton = forwardRef(function <T extends ElementType = typeof defaultElement>(
|
||||
const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicElements>(
|
||||
{
|
||||
element,
|
||||
element = "div" as T,
|
||||
onClick,
|
||||
children,
|
||||
kind,
|
||||
|
@ -135,10 +141,10 @@ const AccessibleButton = forwardRef(function <T extends ElementType = typeof def
|
|||
onTooltipOpenChange,
|
||||
disableTooltip,
|
||||
...restProps
|
||||
}: ButtonProps<T>,
|
||||
ref: Ref<HTMLElementTagNameMap[T]>,
|
||||
}: Props<T>,
|
||||
ref: Ref<HTMLElement>,
|
||||
): JSX.Element {
|
||||
const newProps = restProps as RenderedElementProps<T>;
|
||||
const newProps: RenderedElementProps = restProps;
|
||||
newProps["aria-label"] = newProps["aria-label"] ?? title;
|
||||
if (disabled) {
|
||||
newProps["aria-disabled"] = true;
|
||||
|
@ -156,7 +162,7 @@ const AccessibleButton = forwardRef(function <T extends ElementType = typeof def
|
|||
// And divs which we report as role button to assistive technologies.
|
||||
// Browsers handle space and enter key presses differently and we are only adjusting to the
|
||||
// inconsistencies here
|
||||
newProps.onKeyDown = (e: KeyboardEvent<never>) => {
|
||||
newProps.onKeyDown = (e) => {
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
|
||||
switch (action) {
|
||||
|
@ -172,7 +178,7 @@ const AccessibleButton = forwardRef(function <T extends ElementType = typeof def
|
|||
onKeyDown?.(e);
|
||||
}
|
||||
};
|
||||
newProps.onKeyUp = (e: KeyboardEvent<never>) => {
|
||||
newProps.onKeyUp = (e) => {
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
|
||||
switch (action) {
|
||||
|
@ -201,7 +207,7 @@ const AccessibleButton = forwardRef(function <T extends ElementType = typeof def
|
|||
});
|
||||
|
||||
// React.createElement expects InputHTMLAttributes
|
||||
const button = React.createElement(element ?? defaultElement, newProps, children);
|
||||
const button = React.createElement(element, newProps, children);
|
||||
|
||||
if (title) {
|
||||
return (
|
||||
|
@ -227,15 +233,4 @@ const AccessibleButton = forwardRef(function <T extends ElementType = typeof def
|
|||
};
|
||||
(AccessibleButton as FunctionComponent).displayName = "AccessibleButton";
|
||||
|
||||
interface RefProp<T extends ElementType> {
|
||||
ref?: Ref<HTMLElementTagNameMap[T]>;
|
||||
}
|
||||
|
||||
interface ButtonComponent {
|
||||
// With the explicit `element` prop
|
||||
<C extends ElementType>(props: { element?: C } & ButtonProps<C> & RefProp<C>): ReactElement;
|
||||
// Without the explicit `element` prop
|
||||
(props: ButtonProps<"div"> & RefProp<"div">): ReactElement;
|
||||
}
|
||||
|
||||
export default AccessibleButton as ButtonComponent;
|
||||
export default AccessibleButton;
|
||||
|
|
|
@ -133,7 +133,12 @@ export default class EditableItemList<P = {}> extends React.PureComponent<IProps
|
|||
onChange={this.onNewItemChanged}
|
||||
list={this.props.suggestionsListId}
|
||||
/>
|
||||
<AccessibleButton onClick={this.onItemAdded} kind="primary" disabled={!this.props.newItem}>
|
||||
<AccessibleButton
|
||||
onClick={this.onItemAdded}
|
||||
kind="primary"
|
||||
type="submit"
|
||||
disabled={!this.props.newItem}
|
||||
>
|
||||
{_t("action|add")}
|
||||
</AccessibleButton>
|
||||
</form>
|
||||
|
|
|
@ -58,11 +58,10 @@ const EffectsOverlay: FunctionComponent<IProps> = ({ roomWidth }) => {
|
|||
if (canvas) canvas.height = UIStore.instance.windowHeight;
|
||||
UIStore.instance.on(UI_EVENTS.Resize, resize);
|
||||
|
||||
const currentEffects = effectsRef.current; // this is not a react node ref, warning can be safely ignored
|
||||
return () => {
|
||||
dis.unregister(dispatcherRef);
|
||||
UIStore.instance.off(UI_EVENTS.Resize, resize);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const currentEffects = effectsRef.current; // this is not a react node ref, warning can be safely ignored
|
||||
for (const effect in currentEffects) {
|
||||
const effectModule: ICanvasEffect = currentEffects.get(effect)!;
|
||||
if (effectModule && effectModule.isRunning) {
|
||||
|
|
|
@ -31,7 +31,7 @@ class Emoji extends React.PureComponent<IProps> {
|
|||
return (
|
||||
<RovingAccessibleButton
|
||||
id={this.props.id}
|
||||
onClick={(ev: ButtonEvent) => onClick(ev, emoji)}
|
||||
onClick={(ev) => onClick(ev, emoji)}
|
||||
onMouseEnter={() => onMouseEnter(emoji)}
|
||||
onMouseLeave={() => onMouseLeave(emoji)}
|
||||
className="mx_EmojiPicker_item_wrapper"
|
||||
|
|
|
@ -90,7 +90,7 @@ export const MPollEndBody = React.forwardRef<any, IBodyProps>(({ mxEvent, ...pro
|
|||
const { pollStartEvent, isLoadingPollStartEvent } = usePollStartEvent(mxEvent);
|
||||
|
||||
if (!pollStartEvent) {
|
||||
const pollEndFallbackMessage = M_TEXT.findIn<string>(mxEvent.getContent()) || textForEvent(mxEvent, cli);
|
||||
const pollEndFallbackMessage = M_TEXT.findIn(mxEvent.getContent()) || textForEvent(mxEvent, cli);
|
||||
return (
|
||||
<>
|
||||
<PollIcon className="mx_MPollEndBody_icon" />
|
||||
|
|
|
@ -435,7 +435,7 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
|
|||
<RovingAccessibleButton
|
||||
className="mx_MessageActionBar_iconButton"
|
||||
title={isPinned ? _t("action|unpin") : _t("action|pin")}
|
||||
onClick={(e: ButtonEvent) => this.onPinClick(e, isPinned)}
|
||||
onClick={(e) => this.onPinClick(e, isPinned)}
|
||||
onContextMenu={(e: ButtonEvent) => this.onPinClick(e, isPinned)}
|
||||
key="pin"
|
||||
placement="left"
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { JSX, useEffect, useRef, useState } from "react";
|
||||
import React, { JSX, useEffect, useState } from "react";
|
||||
import PinIcon from "@vector-im/compound-design-tokens/assets/web/icons/pin-solid";
|
||||
import { Button } from "@vector-im/compound-web";
|
||||
import { MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { Room } from "matrix-js-sdk/src/matrix";
|
||||
import classNames from "classnames";
|
||||
|
||||
import { usePinnedEvents, useSortedFetchedPinnedEvents } from "../../../hooks/usePinnedEvents";
|
||||
|
@ -25,7 +25,6 @@ import { Action } from "../../../dispatcher/actions";
|
|||
import MessageEvent from "../messages/MessageEvent";
|
||||
import PosthogTrackers from "../../../PosthogTrackers.ts";
|
||||
import { EventPreview } from "./EventPreview.tsx";
|
||||
import ResizeNotifier from "../../../utils/ResizeNotifier";
|
||||
|
||||
/**
|
||||
* The props for the {@link PinnedMessageBanner} component.
|
||||
|
@ -39,20 +38,12 @@ interface PinnedMessageBannerProps {
|
|||
* The room where the banner is displayed
|
||||
*/
|
||||
room: Room;
|
||||
/**
|
||||
* The resize notifier to notify the timeline to resize itself when the banner is displayed or hidden.
|
||||
*/
|
||||
resizeNotifier: ResizeNotifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* A banner that displays the pinned messages in a room.
|
||||
*/
|
||||
export function PinnedMessageBanner({
|
||||
room,
|
||||
permalinkCreator,
|
||||
resizeNotifier,
|
||||
}: PinnedMessageBannerProps): JSX.Element | null {
|
||||
export function PinnedMessageBanner({ room, permalinkCreator }: PinnedMessageBannerProps): JSX.Element | null {
|
||||
const pinnedEventIds = usePinnedEvents(room);
|
||||
const pinnedEvents = useSortedFetchedPinnedEvents(room, pinnedEventIds);
|
||||
const eventCount = pinnedEvents.length;
|
||||
|
@ -65,8 +56,6 @@ export function PinnedMessageBanner({
|
|||
}, [eventCount]);
|
||||
|
||||
const pinnedEvent = pinnedEvents[currentEventIndex];
|
||||
useNotifyTimeline(pinnedEvent, resizeNotifier);
|
||||
|
||||
if (!pinnedEvent) return null;
|
||||
|
||||
const shouldUseMessageEvent = pinnedEvent.isRedacted() || pinnedEvent.isDecryptionFailure();
|
||||
|
@ -139,23 +128,6 @@ export function PinnedMessageBanner({
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the banner is displayed or hidden, we want to notify the timeline to resize itself.
|
||||
* @param pinnedEvent
|
||||
* @param resizeNotifier
|
||||
*/
|
||||
function useNotifyTimeline(pinnedEvent: MatrixEvent | null, resizeNotifier: ResizeNotifier): void {
|
||||
const previousEvent = useRef<MatrixEvent | null>(null);
|
||||
useEffect(() => {
|
||||
// If we switch from a pinned message to no pinned message or the opposite, we want to resize the timeline
|
||||
if ((previousEvent.current && !pinnedEvent) || (!previousEvent.current && pinnedEvent)) {
|
||||
resizeNotifier.notifyTimelineHeightChanged();
|
||||
}
|
||||
|
||||
previousEvent.current = pinnedEvent;
|
||||
}, [pinnedEvent, resizeNotifier]);
|
||||
}
|
||||
|
||||
const MAX_INDICATORS = 3;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
import React, { ForwardedRef, forwardRef, MutableRefObject, useRef } from "react";
|
||||
import React, { ForwardedRef, forwardRef, MutableRefObject, useMemo } from "react";
|
||||
import classNames from "classnames";
|
||||
|
||||
import EditorStateTransfer from "../../../../utils/EditorStateTransfer";
|
||||
|
@ -44,7 +44,7 @@ export default function EditWysiwygComposer({
|
|||
className,
|
||||
...props
|
||||
}: EditWysiwygComposerProps): JSX.Element {
|
||||
const defaultContextValue = useRef(getDefaultContextValue({ editorStateTransfer }));
|
||||
const defaultContextValue = useMemo(() => getDefaultContextValue({ editorStateTransfer }), []);
|
||||
const initialContent = useInitialContent(editorStateTransfer);
|
||||
const isReady = !editorStateTransfer || initialContent !== undefined;
|
||||
|
||||
|
@ -55,7 +55,7 @@ export default function EditWysiwygComposer({
|
|||
}
|
||||
|
||||
return (
|
||||
<ComposerContext.Provider value={defaultContextValue.current}>
|
||||
<ComposerContext.Provider value={defaultContextValue}>
|
||||
<WysiwygComposer
|
||||
className={classNames("mx_EditWysiwygComposer", className)}
|
||||
initialContent={initialContent}
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
import React, { ForwardedRef, forwardRef, MutableRefObject, useRef } from "react";
|
||||
import React, { ForwardedRef, forwardRef, MutableRefObject, useMemo } from "react";
|
||||
import { IEventRelation } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { useWysiwygSendActionHandler } from "./hooks/useWysiwygSendActionHandler";
|
||||
|
@ -52,10 +52,10 @@ export default function SendWysiwygComposer({
|
|||
...props
|
||||
}: SendWysiwygComposerProps): JSX.Element {
|
||||
const Composer = isRichTextEnabled ? WysiwygComposer : PlainTextComposer;
|
||||
const defaultContextValue = useRef(getDefaultContextValue({ eventRelation: props.eventRelation }));
|
||||
const defaultContextValue = useMemo(() => getDefaultContextValue({ eventRelation: props.eventRelation }), []);
|
||||
|
||||
return (
|
||||
<ComposerContext.Provider value={defaultContextValue.current}>
|
||||
<ComposerContext.Provider value={defaultContextValue}>
|
||||
<Composer
|
||||
className="mx_SendWysiwygComposer"
|
||||
leftComponent={e2eStatus && <E2EIcon status={e2eStatus} />}
|
||||
|
|
|
@ -407,6 +407,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
|
|||
forceValidity={this.state.error ? false : undefined}
|
||||
/>
|
||||
<AccessibleButton
|
||||
type="submit"
|
||||
kind="primary_sm"
|
||||
onClick={this.checkIdServer}
|
||||
disabled={!this.idServerChangeEnabled()}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { ChangeEvent, JSX, useCallback, useMemo, useRef, useState } from "react";
|
||||
import React, { ChangeEvent, JSX, useCallback, useMemo, useState } from "react";
|
||||
import {
|
||||
InlineField,
|
||||
ToggleControl,
|
||||
|
@ -39,12 +39,12 @@ import { useSettingValue } from "../../../hooks/useSettings";
|
|||
*/
|
||||
export function ThemeChoicePanel(): JSX.Element {
|
||||
const themeState = useTheme();
|
||||
const themeWatcher = useRef(new ThemeWatcher());
|
||||
const themeWatcher = useMemo(() => new ThemeWatcher(), []);
|
||||
const customThemeEnabled = useSettingValue<boolean>("feature_custom_themes");
|
||||
|
||||
return (
|
||||
<SettingsSubsection heading={_t("common|theme")} legacy={false} data-testid="themePanel">
|
||||
{themeWatcher.current.isSystemThemeSupported() && (
|
||||
{themeWatcher.isSystemThemeSupported() && (
|
||||
<SystemTheme systemThemeActivated={themeState.systemThemeActivated} />
|
||||
)}
|
||||
<ThemeSelectors theme={themeState.theme} disabled={themeState.systemThemeActivated} />
|
||||
|
|
|
@ -7,21 +7,23 @@ Please see LICENSE files in the repository root for full details.
|
|||
*/
|
||||
|
||||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
import React, { ComponentProps } from "react";
|
||||
import { ChevronDownIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { _t } from "../../../../languageHandler";
|
||||
import AccessibleButton, { ButtonProps } from "../../elements/AccessibleButton";
|
||||
import AccessibleButton from "../../elements/AccessibleButton";
|
||||
|
||||
type Props<T extends keyof HTMLElementTagNameMap> = Omit<
|
||||
ButtonProps<T>,
|
||||
"aria-label" | "title" | "kind" | "className" | "element"
|
||||
type Props<T extends keyof JSX.IntrinsicElements> = Omit<
|
||||
ComponentProps<typeof AccessibleButton<T>>,
|
||||
"aria-label" | "title" | "kind" | "className" | "onClick" | "element"
|
||||
> & {
|
||||
isExpanded: boolean;
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
export const DeviceExpandDetailsButton = <T extends keyof HTMLElementTagNameMap>({
|
||||
export const DeviceExpandDetailsButton = <T extends keyof JSX.IntrinsicElements>({
|
||||
isExpanded,
|
||||
onClick,
|
||||
...rest
|
||||
}: Props<T>): JSX.Element => {
|
||||
const label = isExpanded ? _t("settings|sessions|hide_details") : _t("settings|sessions|show_details");
|
||||
|
@ -34,6 +36,7 @@ export const DeviceExpandDetailsButton = <T extends keyof HTMLElementTagNameMap>
|
|||
className={classNames("mx_DeviceExpandDetailsButton", {
|
||||
mx_DeviceExpandDetailsButton_expanded: isExpanded,
|
||||
})}
|
||||
onClick={onClick}
|
||||
>
|
||||
<ChevronDownIcon className="mx_DeviceExpandDetailsButton_icon" />
|
||||
</AccessibleButton>
|
||||
|
|
|
@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
|
||||
import React, { useCallback, useMemo, useState } from "react";
|
||||
import { JoinRule, EventType, RoomState, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { RoomPowerLevelsEventContent } from "matrix-js-sdk/src/types";
|
||||
|
||||
import { _t } from "../../../../../languageHandler";
|
||||
import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
|
||||
|
@ -24,48 +25,49 @@ interface ElementCallSwitchProps {
|
|||
|
||||
const ElementCallSwitch: React.FC<ElementCallSwitchProps> = ({ room }) => {
|
||||
const isPublic = useMemo(() => room.getJoinRule() === JoinRule.Public, [room]);
|
||||
const [content, events, maySend] = useRoomState(
|
||||
const [content, maySend] = useRoomState(
|
||||
room,
|
||||
useCallback(
|
||||
(state: RoomState) => {
|
||||
const content = state?.getStateEvents(EventType.RoomPowerLevels, "")?.getContent();
|
||||
const content = state
|
||||
?.getStateEvents(EventType.RoomPowerLevels, "")
|
||||
?.getContent<RoomPowerLevelsEventContent>();
|
||||
return [
|
||||
content ?? {},
|
||||
content?.["events"] ?? {},
|
||||
state?.maySendStateEvent(EventType.RoomPowerLevels, room.client.getSafeUserId()),
|
||||
];
|
||||
] as const;
|
||||
},
|
||||
[room.client],
|
||||
),
|
||||
);
|
||||
|
||||
const [elementCallEnabled, setElementCallEnabled] = useState<boolean>(() => {
|
||||
return events[ElementCall.MEMBER_EVENT_TYPE.name] === 0;
|
||||
return content.events?.[ElementCall.MEMBER_EVENT_TYPE.name] === 0;
|
||||
});
|
||||
|
||||
const onChange = useCallback(
|
||||
(enabled: boolean): void => {
|
||||
setElementCallEnabled(enabled);
|
||||
|
||||
// Take a copy to avoid mutating the original
|
||||
const newContent = { events: {}, ...content };
|
||||
|
||||
if (enabled) {
|
||||
const userLevel = events[EventType.RoomMessage] ?? content.users_default ?? 0;
|
||||
const userLevel = newContent.events[EventType.RoomMessage] ?? content.users_default ?? 0;
|
||||
const moderatorLevel = content.kick ?? 50;
|
||||
|
||||
events[ElementCall.CALL_EVENT_TYPE.name] = isPublic ? moderatorLevel : userLevel;
|
||||
events[ElementCall.MEMBER_EVENT_TYPE.name] = userLevel;
|
||||
newContent.events[ElementCall.CALL_EVENT_TYPE.name] = isPublic ? moderatorLevel : userLevel;
|
||||
newContent.events[ElementCall.MEMBER_EVENT_TYPE.name] = userLevel;
|
||||
} else {
|
||||
const adminLevel = events[EventType.RoomPowerLevels] ?? content.state_default ?? 100;
|
||||
const adminLevel = newContent.events[EventType.RoomPowerLevels] ?? content.state_default ?? 100;
|
||||
|
||||
events[ElementCall.CALL_EVENT_TYPE.name] = adminLevel;
|
||||
events[ElementCall.MEMBER_EVENT_TYPE.name] = adminLevel;
|
||||
newContent.events[ElementCall.CALL_EVENT_TYPE.name] = adminLevel;
|
||||
newContent.events[ElementCall.MEMBER_EVENT_TYPE.name] = adminLevel;
|
||||
}
|
||||
|
||||
room.client.sendStateEvent(room.roomId, EventType.RoomPowerLevels, {
|
||||
events: events,
|
||||
...content,
|
||||
});
|
||||
room.client.sendStateEvent(room.roomId, EventType.RoomPowerLevels, newContent);
|
||||
},
|
||||
[room.client, room.roomId, content, events, isPublic],
|
||||
[room.client, room.roomId, content, isPublic],
|
||||
);
|
||||
|
||||
const brand = SdkConfig.get("element_call").brand ?? DEFAULTS.element_call.brand;
|
||||
|
|
|
@ -268,6 +268,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
|
|||
onChange={this.onPersonalRuleChanged}
|
||||
/>
|
||||
<AccessibleButton
|
||||
type="submit"
|
||||
kind="primary"
|
||||
onClick={this.onAddPersonalRule}
|
||||
disabled={this.state.busy}
|
||||
|
@ -294,7 +295,12 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
|
|||
value={this.state.newList}
|
||||
onChange={this.onNewListChanged}
|
||||
/>
|
||||
<AccessibleButton kind="primary" onClick={this.onSubscribeList} disabled={this.state.busy}>
|
||||
<AccessibleButton
|
||||
type="submit"
|
||||
kind="primary"
|
||||
onClick={this.onSubscribeList}
|
||||
disabled={this.state.busy}
|
||||
>
|
||||
{_t("action|subscribe")}
|
||||
</AccessibleButton>
|
||||
</form>
|
||||
|
|
|
@ -27,7 +27,7 @@ type Props = {
|
|||
const MATCH_SYSTEM_THEME_ID = "MATCH_SYSTEM_THEME_ID";
|
||||
|
||||
const QuickThemeSwitcher: React.FC<Props> = ({ requestClose }) => {
|
||||
const orderedThemes = useMemo(getOrderedThemes, []);
|
||||
const orderedThemes = useMemo(() => getOrderedThemes(), []);
|
||||
|
||||
const themeState = useTheme();
|
||||
const nonHighContrast = findNonHighContrastTheme(themeState.theme);
|
||||
|
|
|
@ -71,6 +71,7 @@ export const SpaceAvatar: React.FC<Pick<IProps, "avatarUrl" | "avatarDisabled" |
|
|||
<AccessibleButton
|
||||
className="mx_SpaceBasicSettings_avatar"
|
||||
onClick={() => avatarUploadRef.current?.click()}
|
||||
alt=""
|
||||
/>
|
||||
<AccessibleButton
|
||||
onClick={() => avatarUploadRef.current?.click()}
|
||||
|
|
|
@ -221,7 +221,7 @@ const CreateSpaceButton: React.FC<Pick<IInnerSpacePanelProps, "isPanelCollapsed"
|
|||
isPanelCollapsed,
|
||||
setPanelCollapsed,
|
||||
}) => {
|
||||
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
|
||||
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLElement>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPanelCollapsed && menuDisplayed) {
|
||||
|
|
|
@ -30,7 +30,7 @@ import defaultDispatcher from "../../../dispatcher/dispatcher";
|
|||
import { Action } from "../../../dispatcher/actions";
|
||||
import { ContextMenuTooltipButton } from "../../../accessibility/context_menu/ContextMenuTooltipButton";
|
||||
import { toRightOf, useContextMenu } from "../../structures/ContextMenu";
|
||||
import AccessibleButton, { ButtonEvent, ButtonProps as AccessibleButtonProps } from "../elements/AccessibleButton";
|
||||
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
|
||||
import { StaticNotificationState } from "../../../stores/notifications/StaticNotificationState";
|
||||
import { NotificationLevel } from "../../../stores/notifications/NotificationLevel";
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
|
@ -39,8 +39,8 @@ import SpaceContextMenu from "../context_menus/SpaceContextMenu";
|
|||
import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
|
||||
type ButtonProps<T extends keyof HTMLElementTagNameMap> = Omit<
|
||||
AccessibleButtonProps<T>,
|
||||
type ButtonProps<T extends keyof JSX.IntrinsicElements> = Omit<
|
||||
ComponentProps<typeof AccessibleButton<T>>,
|
||||
"title" | "onClick" | "size" | "element"
|
||||
> & {
|
||||
space?: Room;
|
||||
|
@ -52,12 +52,12 @@ type ButtonProps<T extends keyof HTMLElementTagNameMap> = Omit<
|
|||
notificationState?: NotificationState;
|
||||
isNarrow?: boolean;
|
||||
size: string;
|
||||
innerRef?: RefObject<HTMLDivElement>;
|
||||
innerRef?: RefObject<HTMLElement>;
|
||||
ContextMenuComponent?: ComponentType<ComponentProps<typeof SpaceContextMenu>>;
|
||||
onClick?(ev?: ButtonEvent): void;
|
||||
};
|
||||
|
||||
export const SpaceButton = <T extends keyof HTMLElementTagNameMap>({
|
||||
export const SpaceButton = <T extends keyof JSX.IntrinsicElements>({
|
||||
space,
|
||||
spaceKey: _spaceKey,
|
||||
className,
|
||||
|
@ -72,8 +72,8 @@ export const SpaceButton = <T extends keyof HTMLElementTagNameMap>({
|
|||
ContextMenuComponent,
|
||||
...props
|
||||
}: ButtonProps<T>): JSX.Element => {
|
||||
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>(innerRef);
|
||||
const [onFocus, isActive, ref] = useRovingTabIndex<HTMLDivElement>(handle);
|
||||
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLElement>(innerRef);
|
||||
const [onFocus, isActive, ref] = useRovingTabIndex(handle);
|
||||
const tabIndex = isActive ? 0 : -1;
|
||||
|
||||
const spaceKey = _spaceKey ?? space?.roomId;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { ClientEvent, MatrixClient, MatrixEventEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { throttle } from "lodash";
|
||||
|
||||
|
@ -42,14 +42,12 @@ export function useUnreadThreadRooms(forceComputation: boolean): Result {
|
|||
setResult(computeUnreadThreadRooms(mxClient, msc3946ProcessDynamicPredecessor, settingTACOnlyNotifs));
|
||||
}, [mxClient, msc3946ProcessDynamicPredecessor, settingTACOnlyNotifs]);
|
||||
|
||||
// The exhautive deps lint rule can't compute dependencies here since it's not a plain inline func.
|
||||
// We make this as simple as possible so its only dep is doUpdate itself.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const scheduleUpdate = useCallback(
|
||||
throttle(doUpdate, MIN_UPDATE_INTERVAL_MS, {
|
||||
leading: false,
|
||||
trailing: true,
|
||||
}),
|
||||
const scheduleUpdate = useMemo(
|
||||
() =>
|
||||
throttle(doUpdate, MIN_UPDATE_INTERVAL_MS, {
|
||||
leading: false,
|
||||
trailing: true,
|
||||
}),
|
||||
[doUpdate],
|
||||
);
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ interface IDropdownButtonProps extends ButtonProps {
|
|||
}
|
||||
|
||||
const LegacyCallViewDropdownButton: React.FC<IDropdownButtonProps> = ({ state, deviceKinds, ...props }) => {
|
||||
const [menuDisplayed, buttonRef, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
|
||||
const [menuDisplayed, buttonRef, openMenu, closeMenu] = useContextMenu();
|
||||
const [hoveringDropdown, setHoveringDropdown] = useState(false);
|
||||
|
||||
const classes = classNames("mx_LegacyCallViewButtons_button", "mx_LegacyCallViewButtons_dropdownButton", {
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
import { ReactNode, createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
|
||||
import { ReactNode, createContext, useCallback, useContext, useEffect, useState, useMemo } from "react";
|
||||
|
||||
/**
|
||||
* A ToastContext helps components display any kind of toast message and can be provided
|
||||
|
@ -33,19 +33,19 @@ export function useToastContext(): ToastRack {
|
|||
* the ToastRack object that should be provided to the context
|
||||
*/
|
||||
export function useActiveToast(): [ReactNode | undefined, ToastRack] {
|
||||
const toastRack = useRef(new ToastRack());
|
||||
const toastRack = useMemo(() => new ToastRack(), []);
|
||||
|
||||
const [activeToast, setActiveToast] = useState<ReactNode | undefined>(toastRack.current.getActiveToast());
|
||||
const [activeToast, setActiveToast] = useState<ReactNode | undefined>(toastRack.getActiveToast());
|
||||
|
||||
const updateCallback = useCallback(() => {
|
||||
setActiveToast(toastRack.current.getActiveToast());
|
||||
setActiveToast(toastRack.getActiveToast());
|
||||
}, [setActiveToast, toastRack]);
|
||||
|
||||
useEffect(() => {
|
||||
toastRack.current.setCallback(updateCallback);
|
||||
toastRack.setCallback(updateCallback);
|
||||
}, [toastRack, updateCallback]);
|
||||
|
||||
return [activeToast, toastRack.current];
|
||||
return [activeToast, toastRack];
|
||||
}
|
||||
|
||||
interface DisplayedToast {
|
||||
|
|
|
@ -2936,7 +2936,6 @@
|
|||
"warning": "<w>WARNUNG:</w> <description/>"
|
||||
},
|
||||
"share": {
|
||||
"link_copied": "Link kopiert",
|
||||
"permalink_message": "Link zur ausgewählten Nachricht",
|
||||
"permalink_most_recent": "Link zur aktuellsten Nachricht",
|
||||
"share_call": "Konferenzeinladungslink",
|
||||
|
|
|
@ -398,7 +398,7 @@
|
|||
},
|
||||
"bug_reporting": {
|
||||
"additional_context": "If there is additional context that would help in analysing the issue, such as what you were doing at the time, room IDs, user IDs, etc., please include those things here.",
|
||||
"before_submitting": "We recommend <a>creating a GitHub issue</a> to ensure that your report is reviewed.",
|
||||
"before_submitting": "Before submitting logs, you must <a>create a GitHub issue</a> to describe your problem.",
|
||||
"collecting_information": "Collecting app version information",
|
||||
"collecting_logs": "Collecting logs",
|
||||
"create_new_issue": "Please <newIssueLink>create a new issue</newIssueLink> on GitHub so that we can investigate this bug.",
|
||||
|
|
|
@ -340,7 +340,7 @@
|
|||
"set_email_prompt": "Czy chcesz ustawić adres e-mail?",
|
||||
"sign_in_description": "Użyj swojego konta, aby kontynuować.",
|
||||
"sign_in_instead": "Zamiast tego zaloguj się",
|
||||
"sign_in_instead_prompt": "Masz już konto? <a>Zaloguj się tutaj</a>",
|
||||
"sign_in_instead_prompt": "Zamiast tego zaloguj się",
|
||||
"sign_in_or_register": "Zaloguj się lub utwórz konto",
|
||||
"sign_in_or_register_description": "Użyj konta lub utwórz nowe, aby kontynuować.",
|
||||
"sign_in_prompt": "Posiadasz już konto? <a>Zaloguj się</a>",
|
||||
|
@ -505,7 +505,6 @@
|
|||
"matrix": "Matrix",
|
||||
"message": "Wiadomość",
|
||||
"message_layout": "Wygląd wiadomości",
|
||||
"message_timestamp_invalid": "Nieprawidłowy znacznik czasu",
|
||||
"microphone": "Mikrofon",
|
||||
"model": "Model",
|
||||
"modern": "Współczesny",
|
||||
|
@ -909,8 +908,6 @@
|
|||
"warning": "Jeżeli nie ustawiłeś nowej metody odzyskiwania, atakujący może uzyskać dostęp do Twojego konta. Zmień hasło konta i natychmiast ustaw nową metodę odzyskiwania w Ustawieniach."
|
||||
},
|
||||
"not_supported": "<niewspierany>",
|
||||
"pinned_identity_changed": "Tożsamość użytkownika %(displayName)s (<b>%(userId)s</b>) uległa zmianie. <a>Dowiedz się więcej</a>",
|
||||
"pinned_identity_changed_no_displayname": "Tożsamość użytkownika <b>%(userId)s</b> uległa zmianie <a>Dowiedz się więcej</a>",
|
||||
"recovery_method_removed": {
|
||||
"description_1": "Ta sesja wykryła, że Twoja fraza bezpieczeństwa i klucz dla bezpiecznych wiadomości zostały usunięte.",
|
||||
"description_2": "Jeśli zrobiłeś to przez pomyłkę, możesz ustawić bezpieczne wiadomości w tej sesji, co zaszyfruje ponownie historię wiadomości za pomocą nowej metody odzyskiwania.",
|
||||
|
@ -999,7 +996,7 @@
|
|||
"unverified_sessions_toast_description": "Sprawdź, by upewnić się że Twoje konto jest bezpieczne",
|
||||
"unverified_sessions_toast_reject": "Później",
|
||||
"unverified_sessions_toast_title": "Masz niezweryfikowane sesje",
|
||||
"verification_description": "Zweryfikuj swoją tożsamość, aby uzyskać dostęp do wiadomości szyfrowanych i potwierdzić swoją tożsamość innym. Jeśli korzystasz z urządzenia mobilnego, otwórz na niej aplikację.",
|
||||
"verification_description": "Zweryfikuj swoją tożsamość, aby uzyskać dostęp do wiadomości szyfrowanych i potwierdzić swoją tożsamość innym.",
|
||||
"verification_dialog_title_device": "Zweryfikuj drugie urządzenie",
|
||||
"verification_dialog_title_user": "Żądanie weryfikacji",
|
||||
"verification_skip_warning": "Bez weryfikacji, nie będziesz posiadać dostępu do wszystkich swoich wiadomości, a inni będą Cię widzieć jako niezaufanego.",
|
||||
|
@ -1105,15 +1102,7 @@
|
|||
"you": "Dodano reakcję %(reaction)s do %(message)s"
|
||||
},
|
||||
"m.sticker": "%(senderName)s: %(stickerName)s",
|
||||
"m.text": "%(senderName)s: %(message)s",
|
||||
"prefix": {
|
||||
"audio": "Audio",
|
||||
"file": "Plik",
|
||||
"image": "Obraz",
|
||||
"poll": "Ankieta",
|
||||
"video": "Wideo"
|
||||
},
|
||||
"preview": "<bold>%(prefix)s:</bold> %(preview)s"
|
||||
"m.text": "%(senderName)s: %(message)s"
|
||||
},
|
||||
"export_chat": {
|
||||
"cancelled": "Eksport został anulowany",
|
||||
|
@ -2950,7 +2939,6 @@
|
|||
"warning": "<w>OSTRZEŻENIE:</w> <description/>"
|
||||
},
|
||||
"share": {
|
||||
"link_copied": "Skopiowano link",
|
||||
"permalink_message": "Link do zaznaczonej wiadomości",
|
||||
"permalink_most_recent": "Link do najnowszej wiadomości",
|
||||
"share_call": "Link zaproszenia do konferencji",
|
||||
|
@ -3259,8 +3247,8 @@
|
|||
"historical_event_no_key_backup": "Historia wiadomości nie jest dostępna na tym urządzeniu",
|
||||
"historical_event_unverified_device": "Musisz zweryfikować to urządzenie, aby wyświetlić historię wiadomości",
|
||||
"historical_event_user_not_joined": "Nie masz dostępu do tej wiadomości",
|
||||
"sender_identity_previously_verified": "Zweryfikowana tożsamość nadawcy uległa zmianie",
|
||||
"sender_unsigned_device": "Wysłano z niezabezpieczonego urządzenia.",
|
||||
"sender_identity_previously_verified": "Zweryfikowana tożsamość uległa zmianie",
|
||||
"sender_unsigned_device": "Zaszyfrowano przez urządzenie niezweryfikowane przez właściciela.",
|
||||
"unable_to_decrypt": "Nie można rozszyfrować wiadomości"
|
||||
},
|
||||
"disambiguated_profile": "%(displayName)s (%(matrixId)s)",
|
||||
|
@ -3732,7 +3720,6 @@
|
|||
"error_files_too_large": "Te pliki są <b>zbyt duże</b> do wysłania. Ograniczenie wielkości plików to %(limit)s.",
|
||||
"error_some_files_too_large": "Niektóre pliki są <b>zbyt duże</b> do wysłania. Ograniczenie wielkości plików to %(limit)s.",
|
||||
"error_title": "Błąd wysyłania",
|
||||
"not_image": "Wybrany plik nie jest prawidłowym plikiem obrazu.",
|
||||
"title": "Prześlij pliki",
|
||||
"title_progress": "Prześlij pliki (%(current)s z %(total)s)",
|
||||
"upload_all_button": "Prześlij wszystko",
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
Copyright 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 EventEmitter from "events";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { createCrossSigning } from "../CreateCrossSigning";
|
||||
import { SdkContextClass } from "../contexts/SDKContext";
|
||||
|
||||
type Status = "in_progress" | "complete" | "error" | undefined;
|
||||
|
||||
export const useInitialCryptoSetupStatus = (store: InitialCryptoSetupStore): Status => {
|
||||
const [status, setStatus] = useState<Status>(store.getStatus());
|
||||
|
||||
useEffect(() => {
|
||||
const update = (): void => {
|
||||
setStatus(store.getStatus());
|
||||
};
|
||||
|
||||
store.on("update", update);
|
||||
|
||||
return () => {
|
||||
store.off("update", update);
|
||||
};
|
||||
}, [store]);
|
||||
|
||||
return status;
|
||||
};
|
||||
|
||||
/**
|
||||
* Logic for setting up crypto state that's done immediately after
|
||||
* a user registers. Should be transparent to the user, not requiring
|
||||
* interaction in most cases.
|
||||
* As distinct from SetupEncryptionStore which is for setting up
|
||||
* 4S or verifying the device, will always require interaction
|
||||
* from the user in some form.
|
||||
*/
|
||||
export class InitialCryptoSetupStore extends EventEmitter {
|
||||
private status: Status = undefined;
|
||||
|
||||
private client?: MatrixClient;
|
||||
private isTokenLogin?: boolean;
|
||||
private stores?: SdkContextClass;
|
||||
private onFinished?: (success: boolean) => void;
|
||||
|
||||
public static sharedInstance(): InitialCryptoSetupStore {
|
||||
if (!window.mxInitialCryptoStore) window.mxInitialCryptoStore = new InitialCryptoSetupStore();
|
||||
return window.mxInitialCryptoStore;
|
||||
}
|
||||
|
||||
public getStatus(): Status {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the initial crypto setup process.
|
||||
*
|
||||
* @param {MatrixClient} client The client to use for the setup
|
||||
* @param {boolean} isTokenLogin True if the user logged in via a token login, otherwise false
|
||||
* @param {SdkContextClass} stores The stores to use for the setup
|
||||
*/
|
||||
public startInitialCryptoSetup(
|
||||
client: MatrixClient,
|
||||
isTokenLogin: boolean,
|
||||
stores: SdkContextClass,
|
||||
onFinished: (success: boolean) => void,
|
||||
): void {
|
||||
this.client = client;
|
||||
this.isTokenLogin = isTokenLogin;
|
||||
this.stores = stores;
|
||||
this.onFinished = onFinished;
|
||||
|
||||
// We just start this process: it's progress is tracked by the events rather
|
||||
// than returning a promise, so we don't bother.
|
||||
this.doSetup().catch(() => logger.error("Initial crypto setup failed"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry the initial crypto setup process.
|
||||
*
|
||||
* If no crypto setup is currently in process, this will return false.
|
||||
*
|
||||
* @returns {boolean} True if a retry was initiated, otherwise false
|
||||
*/
|
||||
public retry(): boolean {
|
||||
if (this.client === undefined || this.isTokenLogin === undefined || this.stores == undefined) return false;
|
||||
|
||||
this.doSetup().catch(() => logger.error("Initial crypto setup failed"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private reset(): void {
|
||||
this.client = undefined;
|
||||
this.isTokenLogin = undefined;
|
||||
this.stores = undefined;
|
||||
}
|
||||
|
||||
private async doSetup(): Promise<void> {
|
||||
if (this.client === undefined || this.isTokenLogin === undefined || this.stores == undefined) {
|
||||
throw new Error("No setup is in progress");
|
||||
}
|
||||
|
||||
const cryptoApi = this.client.getCrypto();
|
||||
if (!cryptoApi) throw new Error("No crypto module found!");
|
||||
|
||||
this.status = "in_progress";
|
||||
this.emit("update");
|
||||
|
||||
try {
|
||||
await createCrossSigning(this.client, this.isTokenLogin, this.stores.accountPasswordStore.getPassword());
|
||||
|
||||
this.reset();
|
||||
|
||||
this.status = "complete";
|
||||
this.emit("update");
|
||||
this.onFinished?.(true);
|
||||
} catch (e) {
|
||||
if (this.isTokenLogin) {
|
||||
// ignore any failures, we are relying on grace period here
|
||||
this.reset();
|
||||
|
||||
this.status = "complete";
|
||||
this.emit("update");
|
||||
this.onFinished?.(true);
|
||||
|
||||
return;
|
||||
}
|
||||
logger.error("Error bootstrapping cross-signing", e);
|
||||
this.status = "error";
|
||||
this.emit("update");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,11 +33,6 @@ export enum Phase {
|
|||
ConfirmReset = 6,
|
||||
}
|
||||
|
||||
/**
|
||||
* Logic for setting up 4S and/or verifying the user's device: a process requiring
|
||||
* ongoing interaction with the user, as distinct from InitialCryptoSetupStore which
|
||||
* a (usually) non-interactive process that happens immediately after registration.
|
||||
*/
|
||||
export class SetupEncryptionStore extends EventEmitter {
|
||||
private started?: boolean;
|
||||
public phase?: Phase;
|
||||
|
|
|
@ -194,7 +194,6 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
|||
EventType.CallSDPStreamMetadataChanged,
|
||||
EventType.CallSDPStreamMetadataChangedPrefix,
|
||||
EventType.CallReplaces,
|
||||
EventType.CallEncryptionKeysPrefix,
|
||||
];
|
||||
for (const eventType of sendRecvToDevice) {
|
||||
this.allowedCapabilities.add(
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useMemo } from "react";
|
||||
|
||||
import type { Map as MapLibreMap } from "maplibre-gl";
|
||||
import { createMap } from "./map";
|
||||
|
@ -26,29 +26,25 @@ interface UseMapProps {
|
|||
*/
|
||||
export const useMap = ({ interactive, bodyId, onError }: UseMapProps): MapLibreMap | undefined => {
|
||||
const cli = useMatrixClientContext();
|
||||
const [map, setMap] = useState<MapLibreMap>();
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
try {
|
||||
setMap(createMap(cli, !!interactive, bodyId, onError));
|
||||
} catch (error) {
|
||||
console.error("Error encountered in useMap", error);
|
||||
if (error instanceof Error) {
|
||||
onError?.(error);
|
||||
}
|
||||
const map = useMemo(() => {
|
||||
try {
|
||||
return createMap(cli, !!interactive, bodyId, onError);
|
||||
} catch (error) {
|
||||
console.error("Error encountered in useMap", error);
|
||||
if (error instanceof Error) {
|
||||
onError?.(error);
|
||||
}
|
||||
return () => {
|
||||
if (map) {
|
||||
map.remove();
|
||||
setMap(undefined);
|
||||
}
|
||||
};
|
||||
},
|
||||
// map is excluded as a dependency
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[interactive, bodyId, onError],
|
||||
);
|
||||
}
|
||||
}, [bodyId, cli, interactive, onError]);
|
||||
|
||||
// cleanup
|
||||
useEffect(() => {
|
||||
if (!map) return;
|
||||
return () => {
|
||||
map.remove();
|
||||
};
|
||||
}, [map]);
|
||||
|
||||
return map;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2018-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 React from "react";
|
||||
import { render, screen, waitFor } from "jest-matrix-react";
|
||||
import { mocked } from "jest-mock";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { createCrossSigning } from "../../../../../src/CreateCrossSigning";
|
||||
import CreateCrossSigningDialog from "../../../../../src/components/views/dialogs/security/CreateCrossSigningDialog";
|
||||
import { createTestClient } from "../../../../test-utils";
|
||||
|
||||
jest.mock("../../../../../src/CreateCrossSigning", () => ({
|
||||
createCrossSigning: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("CreateCrossSigningDialog", () => {
|
||||
let client: MatrixClient;
|
||||
let createCrossSigningResolve: () => void;
|
||||
let createCrossSigningReject: (e: Error) => void;
|
||||
|
||||
beforeEach(() => {
|
||||
client = createTestClient();
|
||||
mocked(createCrossSigning).mockImplementation(() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
createCrossSigningResolve = resolve;
|
||||
createCrossSigningReject = reject;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("should call createCrossSigning and show a spinner while it runs", async () => {
|
||||
const onFinished = jest.fn();
|
||||
|
||||
render(
|
||||
<CreateCrossSigningDialog
|
||||
matrixClient={client}
|
||||
accountPassword="hunter2"
|
||||
tokenLogin={false}
|
||||
onFinished={onFinished}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(createCrossSigning).toHaveBeenCalledWith(client, false, "hunter2");
|
||||
expect(screen.getByTestId("spinner")).toBeInTheDocument();
|
||||
|
||||
createCrossSigningResolve!();
|
||||
|
||||
await waitFor(() => expect(onFinished).toHaveBeenCalledWith(true));
|
||||
});
|
||||
|
||||
it("should display an error if createCrossSigning fails", async () => {
|
||||
render(
|
||||
<CreateCrossSigningDialog
|
||||
matrixClient={client}
|
||||
accountPassword="hunter2"
|
||||
tokenLogin={false}
|
||||
onFinished={jest.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
createCrossSigningReject!(new Error("generic error message"));
|
||||
|
||||
await expect(await screen.findByRole("button", { name: "Retry" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("ignores failures when tokenLogin is true", async () => {
|
||||
const onFinished = jest.fn();
|
||||
|
||||
render(
|
||||
<CreateCrossSigningDialog
|
||||
matrixClient={client}
|
||||
accountPassword="hunter2"
|
||||
tokenLogin={true}
|
||||
onFinished={onFinished}
|
||||
/>,
|
||||
);
|
||||
|
||||
createCrossSigningReject!(new Error("generic error message"));
|
||||
|
||||
await waitFor(() => expect(onFinished).toHaveBeenCalledWith(false));
|
||||
});
|
||||
|
||||
it("cancels the dialog when the cancel button is clicked", async () => {
|
||||
const onFinished = jest.fn();
|
||||
|
||||
render(
|
||||
<CreateCrossSigningDialog
|
||||
matrixClient={client}
|
||||
accountPassword="hunter2"
|
||||
tokenLogin={false}
|
||||
onFinished={onFinished}
|
||||
/>,
|
||||
);
|
||||
|
||||
createCrossSigningReject!(new Error("generic error message"));
|
||||
|
||||
const cancelButton = await screen.findByRole("button", { name: "Cancel" });
|
||||
cancelButton.click();
|
||||
|
||||
expect(onFinished).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it("should retry when the retry button is clicked", async () => {
|
||||
render(
|
||||
<CreateCrossSigningDialog
|
||||
matrixClient={client}
|
||||
accountPassword="hunter2"
|
||||
tokenLogin={false}
|
||||
onFinished={jest.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
createCrossSigningReject!(new Error("generic error message"));
|
||||
|
||||
const retryButton = await screen.findByRole("button", { name: "Retry" });
|
||||
retryButton.click();
|
||||
|
||||
expect(createCrossSigning).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2018-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 React from "react";
|
||||
import { render, screen } from "jest-matrix-react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
import { InitialCryptoSetupDialog } from "../../../../../src/components/views/dialogs/security/InitialCryptoSetupDialog";
|
||||
import { InitialCryptoSetupStore } from "../../../../../src/stores/InitialCryptoSetupStore";
|
||||
|
||||
describe("InitialCryptoSetupDialog", () => {
|
||||
const storeMock = {
|
||||
getStatus: jest.fn(),
|
||||
retry: jest.fn(),
|
||||
on: jest.fn(),
|
||||
off: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(InitialCryptoSetupStore, "sharedInstance").mockReturnValue(storeMock as any);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("should show a spinner while the setup is in progress", async () => {
|
||||
const onFinished = jest.fn();
|
||||
|
||||
storeMock.getStatus.mockReturnValue("in_progress");
|
||||
|
||||
render(<InitialCryptoSetupDialog onFinished={onFinished} />);
|
||||
|
||||
expect(screen.getByTestId("spinner")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should display an error if setup has failed", async () => {
|
||||
storeMock.getStatus.mockReturnValue("error");
|
||||
|
||||
render(<InitialCryptoSetupDialog onFinished={jest.fn()} />);
|
||||
|
||||
await expect(await screen.findByRole("button", { name: "Retry" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls retry when retry button pressed", async () => {
|
||||
const onFinished = jest.fn();
|
||||
storeMock.getStatus.mockReturnValue("error");
|
||||
|
||||
render(<InitialCryptoSetupDialog onFinished={onFinished} />);
|
||||
|
||||
await userEvent.click(await screen.findByRole("button", { name: "Retry" }));
|
||||
|
||||
expect(storeMock.retry).toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -314,6 +314,7 @@ exports[`<MatrixChat /> with a soft-logged-out session should show the soft-logo
|
|||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="submit"
|
||||
>
|
||||
Sign in
|
||||
</div>
|
||||
|
|
|
@ -135,9 +135,8 @@ exports[`<RoomSummaryCard /> has button to edit topic 1`] = `
|
|||
style="--mx-box-flex: 1;"
|
||||
>
|
||||
<a
|
||||
class="_link_ue21z_17"
|
||||
class="_link_1mzip_17"
|
||||
data-kind="primary"
|
||||
data-size="medium"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
<p
|
||||
|
@ -753,9 +752,8 @@ exports[`<RoomSummaryCard /> renders the room summary 1`] = `
|
|||
style="--mx-box-flex: 1;"
|
||||
>
|
||||
<a
|
||||
class="_link_ue21z_17"
|
||||
class="_link_1mzip_17"
|
||||
data-kind="primary"
|
||||
data-size="medium"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
<p
|
||||
|
@ -1408,9 +1406,8 @@ exports[`<RoomSummaryCard /> renders the room topic in the summary 1`] = `
|
|||
style="--mx-box-flex: 1;"
|
||||
>
|
||||
<a
|
||||
class="_link_ue21z_17"
|
||||
class="_link_1mzip_17"
|
||||
data-kind="primary"
|
||||
data-size="medium"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
<p
|
||||
|
|
|
@ -20,7 +20,6 @@ import RightPanelStore from "../../../../../src/stores/right-panel/RightPanelSto
|
|||
import { RightPanelPhases } from "../../../../../src/stores/right-panel/RightPanelStorePhases";
|
||||
import { UPDATE_EVENT } from "../../../../../src/stores/AsyncStore";
|
||||
import { Action } from "../../../../../src/dispatcher/actions";
|
||||
import ResizeNotifier from "../../../../../src/utils/ResizeNotifier.ts";
|
||||
|
||||
describe("<PinnedMessageBanner />", () => {
|
||||
const userId = "@alice:server.org";
|
||||
|
@ -29,12 +28,10 @@ describe("<PinnedMessageBanner />", () => {
|
|||
let mockClient: MatrixClient;
|
||||
let room: Room;
|
||||
let permalinkCreator: RoomPermalinkCreator;
|
||||
let resizeNotifier: ResizeNotifier;
|
||||
beforeEach(() => {
|
||||
mockClient = stubClient();
|
||||
room = new Room(roomId, mockClient, userId);
|
||||
permalinkCreator = new RoomPermalinkCreator(room);
|
||||
resizeNotifier = new ResizeNotifier();
|
||||
jest.spyOn(dis, "dispatch").mockReturnValue(undefined);
|
||||
});
|
||||
|
||||
|
@ -80,7 +77,7 @@ describe("<PinnedMessageBanner />", () => {
|
|||
*/
|
||||
function renderBanner() {
|
||||
return render(
|
||||
<PinnedMessageBanner permalinkCreator={permalinkCreator} room={room} resizeNotifier={resizeNotifier} />,
|
||||
<PinnedMessageBanner permalinkCreator={permalinkCreator} room={room} />,
|
||||
withClientContextRenderOptions(mockClient),
|
||||
);
|
||||
}
|
||||
|
@ -148,9 +145,7 @@ describe("<PinnedMessageBanner />", () => {
|
|||
event3.getId()!,
|
||||
]);
|
||||
jest.spyOn(pinnedEventHooks, "useSortedFetchedPinnedEvents").mockReturnValue([event1, event2, event3]);
|
||||
rerender(
|
||||
<PinnedMessageBanner permalinkCreator={permalinkCreator} room={room} resizeNotifier={resizeNotifier} />,
|
||||
);
|
||||
rerender(<PinnedMessageBanner permalinkCreator={permalinkCreator} room={room} />);
|
||||
await expect(screen.findByText("Third pinned message")).resolves.toBeVisible();
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
@ -211,42 +206,6 @@ describe("<PinnedMessageBanner />", () => {
|
|||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("Notify the timeline to resize", () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(resizeNotifier, "notifyTimelineHeightChanged");
|
||||
jest.spyOn(pinnedEventHooks, "usePinnedEvents").mockReturnValue([event1.getId()!, event2.getId()!]);
|
||||
jest.spyOn(pinnedEventHooks, "useSortedFetchedPinnedEvents").mockReturnValue([event1, event2]);
|
||||
});
|
||||
|
||||
it("should notify the timeline to resize when we display the banner", async () => {
|
||||
renderBanner();
|
||||
await expect(screen.findByText("Second pinned message")).resolves.toBeVisible();
|
||||
// The banner is displayed, so we need to resize the timeline
|
||||
expect(resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalledTimes(1);
|
||||
|
||||
await userEvent.click(screen.getByRole("button", { name: "View the pinned message in the timeline." }));
|
||||
await expect(screen.findByText("First pinned message")).resolves.toBeVisible();
|
||||
// The banner is already displayed, so we don't need to resize the timeline
|
||||
expect(resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should notify the timeline to resize when we hide the banner", async () => {
|
||||
const { rerender } = renderBanner();
|
||||
await expect(screen.findByText("Second pinned message")).resolves.toBeVisible();
|
||||
// The banner is displayed, so we need to resize the timeline
|
||||
expect(resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalledTimes(1);
|
||||
|
||||
// The banner has no event to display and is hidden
|
||||
jest.spyOn(pinnedEventHooks, "usePinnedEvents").mockReturnValue([]);
|
||||
jest.spyOn(pinnedEventHooks, "useSortedFetchedPinnedEvents").mockReturnValue([]);
|
||||
rerender(
|
||||
<PinnedMessageBanner permalinkCreator={permalinkCreator} room={room} resizeNotifier={resizeNotifier} />,
|
||||
);
|
||||
// The timeline should be resized
|
||||
expect(resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Right button", () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(pinnedEventHooks, "usePinnedEvents").mockReturnValue([event1.getId()!, event2.getId()!]);
|
||||
|
@ -258,8 +217,6 @@ describe("<PinnedMessageBanner />", () => {
|
|||
jest.spyOn(RightPanelStore.instance, "isOpenForRoom").mockReturnValue(false);
|
||||
|
||||
renderBanner();
|
||||
await expect(screen.findByText("Second pinned message")).resolves.toBeVisible();
|
||||
|
||||
expect(screen.getByRole("button", { name: "View all" })).toBeVisible();
|
||||
});
|
||||
|
||||
|
@ -271,8 +228,6 @@ describe("<PinnedMessageBanner />", () => {
|
|||
});
|
||||
|
||||
renderBanner();
|
||||
await expect(screen.findByText("Second pinned message")).resolves.toBeVisible();
|
||||
|
||||
expect(screen.getByRole("button", { name: "View all" })).toBeVisible();
|
||||
});
|
||||
|
||||
|
@ -284,8 +239,6 @@ describe("<PinnedMessageBanner />", () => {
|
|||
});
|
||||
|
||||
renderBanner();
|
||||
await expect(screen.findByText("Second pinned message")).resolves.toBeVisible();
|
||||
|
||||
expect(screen.getByRole("button", { name: "Close list" })).toBeVisible();
|
||||
});
|
||||
|
||||
|
@ -310,7 +263,6 @@ describe("<PinnedMessageBanner />", () => {
|
|||
});
|
||||
|
||||
renderBanner();
|
||||
await expect(screen.findByText("Second pinned message")).resolves.toBeVisible();
|
||||
expect(screen.getByRole("button", { name: "Close list" })).toBeVisible();
|
||||
|
||||
jest.spyOn(RightPanelStore.instance, "isOpenForRoom").mockReturnValue(false);
|
||||
|
|
|
@ -10,7 +10,6 @@ import React, { ComponentProps } from "react";
|
|||
import { render, screen, waitFor } from "jest-matrix-react";
|
||||
import { RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import {
|
||||
determineAvatarPosition,
|
||||
|
@ -21,9 +20,6 @@ import * as languageHandler from "../../../../../src/languageHandler";
|
|||
import { stubClient } from "../../../../test-utils";
|
||||
import dispatcher from "../../../../../src/dispatcher/dispatcher";
|
||||
import { Action } from "../../../../../src/dispatcher/actions";
|
||||
import { formatDate } from "../../../../../src/DateUtils";
|
||||
|
||||
jest.mock("../../../../../src/DateUtils");
|
||||
|
||||
describe("ReadReceiptGroup", () => {
|
||||
describe("TooltipText", () => {
|
||||
|
@ -91,10 +87,6 @@ describe("ReadReceiptGroup", () => {
|
|||
describe("<ReadReceiptPerson />", () => {
|
||||
stubClient();
|
||||
|
||||
// We pick a fixed time but this can still vary depending on the locale
|
||||
// the tests are run in. We are not testing date formatting here, so stub it out.
|
||||
mocked(formatDate).mockReturnValue("==MOCK FORMATTED DATE==");
|
||||
|
||||
const ROOM_ID = "roomId";
|
||||
const USER_ID = "@alice:example.org";
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ exports[`ReadReceiptGroup <ReadReceiptPerson /> should render 1`] = `
|
|||
<p
|
||||
class="mx_ReadReceiptGroup_secondary"
|
||||
>
|
||||
==MOCK FORMATTED DATE==
|
||||
Wed, 15 May, 0:00
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -35,7 +35,7 @@ describe("SetIntegrationManager", () => {
|
|||
deleteThreePid: jest.fn(),
|
||||
});
|
||||
|
||||
let stores!: SdkContextClass;
|
||||
let stores: SdkContextClass;
|
||||
|
||||
const getComponent = () => (
|
||||
<MatrixClientContext.Provider value={mockClient}>
|
||||
|
|
|
@ -19,14 +19,14 @@ exports[`<LayoutSwitcher /> should render 1`] = `
|
|||
class="mx_SettingsSubsection_content mx_SettingsSubsection_content_newUi"
|
||||
>
|
||||
<form
|
||||
class="_root_ssths_24 mx_LayoutSwitcher_LayoutSelector"
|
||||
class="_root_dgy0u_24 mx_LayoutSwitcher_LayoutSelector"
|
||||
>
|
||||
<div
|
||||
class="_field_ssths_34 mxLayoutSwitcher_LayoutSelector_LayoutRadio"
|
||||
class="_field_dgy0u_34 mxLayoutSwitcher_LayoutSelector_LayoutRadio"
|
||||
>
|
||||
<label
|
||||
aria-label="Modern"
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:r0:"
|
||||
>
|
||||
<div
|
||||
|
@ -149,11 +149,11 @@ exports[`<LayoutSwitcher /> should render 1`] = `
|
|||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="_field_ssths_34 mxLayoutSwitcher_LayoutSelector_LayoutRadio"
|
||||
class="_field_dgy0u_34 mxLayoutSwitcher_LayoutSelector_LayoutRadio"
|
||||
>
|
||||
<label
|
||||
aria-label="Message bubbles"
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:r9:"
|
||||
>
|
||||
<div
|
||||
|
@ -275,11 +275,11 @@ exports[`<LayoutSwitcher /> should render 1`] = `
|
|||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="_field_ssths_34 mxLayoutSwitcher_LayoutSelector_LayoutRadio"
|
||||
class="_field_dgy0u_34 mxLayoutSwitcher_LayoutSelector_LayoutRadio"
|
||||
>
|
||||
<label
|
||||
aria-label="IRC (experimental)"
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:ri:"
|
||||
>
|
||||
<div
|
||||
|
@ -402,13 +402,13 @@ exports[`<LayoutSwitcher /> should render 1`] = `
|
|||
</div>
|
||||
</form>
|
||||
<form
|
||||
class="_root_ssths_24"
|
||||
class="_root_dgy0u_24"
|
||||
>
|
||||
<div
|
||||
class="_inline-field_ssths_40"
|
||||
class="_inline-field_dgy0u_40"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_qnvru_18"
|
||||
|
@ -427,16 +427,16 @@ exports[`<LayoutSwitcher /> should render 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:rr:"
|
||||
>
|
||||
Show compact text and messages
|
||||
</label>
|
||||
<span
|
||||
class="_message_ssths_93 _help-message_ssths_99"
|
||||
class="_message_dgy0u_98 _help-message_dgy0u_104"
|
||||
id="radix-:rs:"
|
||||
>
|
||||
Modern layout must be selected to use this feature.
|
||||
|
|
|
@ -19,13 +19,13 @@ exports[`<ThemeChoicePanel /> custom theme should display custom theme 1`] = `
|
|||
class="mx_SettingsSubsection_content mx_SettingsSubsection_content_newUi"
|
||||
>
|
||||
<form
|
||||
class="_root_ssths_24"
|
||||
class="_root_dgy0u_24"
|
||||
>
|
||||
<div
|
||||
class="_inline-field_ssths_40"
|
||||
class="_inline-field_dgy0u_40"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_qnvru_18"
|
||||
|
@ -43,10 +43,10 @@ exports[`<ThemeChoicePanel /> custom theme should display custom theme 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:r28:"
|
||||
>
|
||||
Match system theme
|
||||
|
@ -55,13 +55,13 @@ exports[`<ThemeChoicePanel /> custom theme should display custom theme 1`] = `
|
|||
</div>
|
||||
</form>
|
||||
<form
|
||||
class="_root_ssths_24 mx_ThemeChoicePanel_ThemeSelectors"
|
||||
class="_root_dgy0u_24 mx_ThemeChoicePanel_ThemeSelectors"
|
||||
>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector mx_ThemeChoicePanel_themeSelector_enabled cpd-theme-light"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector mx_ThemeChoicePanel_themeSelector_enabled cpd-theme-light"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -81,10 +81,10 @@ exports[`<ThemeChoicePanel /> custom theme should display custom theme 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r29:"
|
||||
>
|
||||
Light
|
||||
|
@ -92,10 +92,10 @@ exports[`<ThemeChoicePanel /> custom theme should display custom theme 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector cpd-theme-dark"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector cpd-theme-dark"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -114,10 +114,10 @@ exports[`<ThemeChoicePanel /> custom theme should display custom theme 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r2a:"
|
||||
>
|
||||
Dark
|
||||
|
@ -125,10 +125,10 @@ exports[`<ThemeChoicePanel /> custom theme should display custom theme 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector cpd-theme-light"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector cpd-theme-light"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -147,10 +147,10 @@ exports[`<ThemeChoicePanel /> custom theme should display custom theme 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r2b:"
|
||||
>
|
||||
High contrast
|
||||
|
@ -158,10 +158,10 @@ exports[`<ThemeChoicePanel /> custom theme should display custom theme 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector cpd-theme-dark"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector cpd-theme-dark"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -180,10 +180,10 @@ exports[`<ThemeChoicePanel /> custom theme should display custom theme 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r2c:"
|
||||
>
|
||||
Alice theme
|
||||
|
@ -195,13 +195,13 @@ exports[`<ThemeChoicePanel /> custom theme should display custom theme 1`] = `
|
|||
class="mx_ThemeChoicePanel_CustomTheme"
|
||||
>
|
||||
<form
|
||||
class="_root_ssths_24 mx_ThemeChoicePanel_CustomTheme_EditInPlace"
|
||||
class="_root_dgy0u_24 mx_ThemeChoicePanel_CustomTheme_EditInPlace"
|
||||
>
|
||||
<div
|
||||
class="_field_ssths_34"
|
||||
class="_field_dgy0u_34"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:r2d:"
|
||||
>
|
||||
Add custom theme
|
||||
|
@ -219,7 +219,7 @@ exports[`<ThemeChoicePanel /> custom theme should display custom theme 1`] = `
|
|||
/>
|
||||
</div>
|
||||
<span
|
||||
class="_message_ssths_93 _help-message_ssths_99"
|
||||
class="_message_dgy0u_98 _help-message_dgy0u_104"
|
||||
id="radix-:r2e:"
|
||||
>
|
||||
Enter the URL of a custom theme you want to apply.
|
||||
|
@ -296,13 +296,13 @@ exports[`<ThemeChoicePanel /> custom theme should render the custom theme sectio
|
|||
class="mx_SettingsSubsection_content mx_SettingsSubsection_content_newUi"
|
||||
>
|
||||
<form
|
||||
class="_root_ssths_24"
|
||||
class="_root_dgy0u_24"
|
||||
>
|
||||
<div
|
||||
class="_inline-field_ssths_40"
|
||||
class="_inline-field_dgy0u_40"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_qnvru_18"
|
||||
|
@ -320,10 +320,10 @@ exports[`<ThemeChoicePanel /> custom theme should render the custom theme sectio
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:r10:"
|
||||
>
|
||||
Match system theme
|
||||
|
@ -332,13 +332,13 @@ exports[`<ThemeChoicePanel /> custom theme should render the custom theme sectio
|
|||
</div>
|
||||
</form>
|
||||
<form
|
||||
class="_root_ssths_24 mx_ThemeChoicePanel_ThemeSelectors"
|
||||
class="_root_dgy0u_24 mx_ThemeChoicePanel_ThemeSelectors"
|
||||
>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector mx_ThemeChoicePanel_themeSelector_enabled cpd-theme-light"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector mx_ThemeChoicePanel_themeSelector_enabled cpd-theme-light"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -358,10 +358,10 @@ exports[`<ThemeChoicePanel /> custom theme should render the custom theme sectio
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r11:"
|
||||
>
|
||||
Light
|
||||
|
@ -369,10 +369,10 @@ exports[`<ThemeChoicePanel /> custom theme should render the custom theme sectio
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector cpd-theme-dark"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector cpd-theme-dark"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -391,10 +391,10 @@ exports[`<ThemeChoicePanel /> custom theme should render the custom theme sectio
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r12:"
|
||||
>
|
||||
Dark
|
||||
|
@ -402,10 +402,10 @@ exports[`<ThemeChoicePanel /> custom theme should render the custom theme sectio
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector cpd-theme-light"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector cpd-theme-light"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -424,10 +424,10 @@ exports[`<ThemeChoicePanel /> custom theme should render the custom theme sectio
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r13:"
|
||||
>
|
||||
High contrast
|
||||
|
@ -435,10 +435,10 @@ exports[`<ThemeChoicePanel /> custom theme should render the custom theme sectio
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector cpd-theme-dark"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector cpd-theme-dark"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -457,10 +457,10 @@ exports[`<ThemeChoicePanel /> custom theme should render the custom theme sectio
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r14:"
|
||||
>
|
||||
Alice theme
|
||||
|
@ -472,13 +472,13 @@ exports[`<ThemeChoicePanel /> custom theme should render the custom theme sectio
|
|||
class="mx_ThemeChoicePanel_CustomTheme"
|
||||
>
|
||||
<form
|
||||
class="_root_ssths_24 mx_ThemeChoicePanel_CustomTheme_EditInPlace"
|
||||
class="_root_dgy0u_24 mx_ThemeChoicePanel_CustomTheme_EditInPlace"
|
||||
>
|
||||
<div
|
||||
class="_field_ssths_34"
|
||||
class="_field_dgy0u_34"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:r15:"
|
||||
>
|
||||
Add custom theme
|
||||
|
@ -496,7 +496,7 @@ exports[`<ThemeChoicePanel /> custom theme should render the custom theme sectio
|
|||
/>
|
||||
</div>
|
||||
<span
|
||||
class="_message_ssths_93 _help-message_ssths_99"
|
||||
class="_message_dgy0u_98 _help-message_dgy0u_104"
|
||||
id="radix-:r16:"
|
||||
>
|
||||
Enter the URL of a custom theme you want to apply.
|
||||
|
@ -573,13 +573,13 @@ exports[`<ThemeChoicePanel /> renders the theme choice UI 1`] = `
|
|||
class="mx_SettingsSubsection_content mx_SettingsSubsection_content_newUi"
|
||||
>
|
||||
<form
|
||||
class="_root_ssths_24"
|
||||
class="_root_dgy0u_24"
|
||||
>
|
||||
<div
|
||||
class="_inline-field_ssths_40"
|
||||
class="_inline-field_dgy0u_40"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_qnvru_18"
|
||||
|
@ -597,10 +597,10 @@ exports[`<ThemeChoicePanel /> renders the theme choice UI 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:r0:"
|
||||
>
|
||||
Match system theme
|
||||
|
@ -609,13 +609,13 @@ exports[`<ThemeChoicePanel /> renders the theme choice UI 1`] = `
|
|||
</div>
|
||||
</form>
|
||||
<form
|
||||
class="_root_ssths_24 mx_ThemeChoicePanel_ThemeSelectors"
|
||||
class="_root_dgy0u_24 mx_ThemeChoicePanel_ThemeSelectors"
|
||||
>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector mx_ThemeChoicePanel_themeSelector_enabled cpd-theme-light"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector mx_ThemeChoicePanel_themeSelector_enabled cpd-theme-light"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -635,10 +635,10 @@ exports[`<ThemeChoicePanel /> renders the theme choice UI 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r1:"
|
||||
>
|
||||
Light
|
||||
|
@ -646,10 +646,10 @@ exports[`<ThemeChoicePanel /> renders the theme choice UI 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector cpd-theme-dark"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector cpd-theme-dark"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -668,10 +668,10 @@ exports[`<ThemeChoicePanel /> renders the theme choice UI 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r2:"
|
||||
>
|
||||
Dark
|
||||
|
@ -679,10 +679,10 @@ exports[`<ThemeChoicePanel /> renders the theme choice UI 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector cpd-theme-light"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector cpd-theme-light"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -701,10 +701,10 @@ exports[`<ThemeChoicePanel /> renders the theme choice UI 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r3:"
|
||||
>
|
||||
High contrast
|
||||
|
|
|
@ -32,13 +32,13 @@ exports[`AppearanceUserSettingsTab should render 1`] = `
|
|||
class="mx_SettingsSubsection_content mx_SettingsSubsection_content_newUi"
|
||||
>
|
||||
<form
|
||||
class="_root_ssths_24 mx_ThemeChoicePanel_ThemeSelectors"
|
||||
class="_root_dgy0u_24 mx_ThemeChoicePanel_ThemeSelectors"
|
||||
>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector mx_ThemeChoicePanel_themeSelector_disabled cpd-theme-light"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector mx_ThemeChoicePanel_themeSelector_disabled cpd-theme-light"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -58,10 +58,10 @@ exports[`AppearanceUserSettingsTab should render 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r0:"
|
||||
>
|
||||
Light
|
||||
|
@ -69,10 +69,10 @@ exports[`AppearanceUserSettingsTab should render 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector mx_ThemeChoicePanel_themeSelector_disabled cpd-theme-dark"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector mx_ThemeChoicePanel_themeSelector_disabled cpd-theme-dark"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -92,10 +92,10 @@ exports[`AppearanceUserSettingsTab should render 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r1:"
|
||||
>
|
||||
Dark
|
||||
|
@ -103,10 +103,10 @@ exports[`AppearanceUserSettingsTab should render 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_ssths_40 mx_ThemeChoicePanel_themeSelector mx_ThemeChoicePanel_themeSelector_disabled cpd-theme-light"
|
||||
class="_inline-field_dgy0u_40 mx_ThemeChoicePanel_themeSelector mx_ThemeChoicePanel_themeSelector_disabled cpd-theme-light"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_1vw5h_18"
|
||||
|
@ -126,10 +126,10 @@ exports[`AppearanceUserSettingsTab should render 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
class="_label_dgy0u_67 mx_ThemeChoicePanel_themeSelector_Label"
|
||||
for="radix-:r2:"
|
||||
>
|
||||
High contrast
|
||||
|
@ -162,14 +162,14 @@ exports[`AppearanceUserSettingsTab should render 1`] = `
|
|||
class="mx_SettingsSubsection_content mx_SettingsSubsection_content_newUi"
|
||||
>
|
||||
<form
|
||||
class="_root_ssths_24 mx_LayoutSwitcher_LayoutSelector"
|
||||
class="_root_dgy0u_24 mx_LayoutSwitcher_LayoutSelector"
|
||||
>
|
||||
<div
|
||||
class="_field_ssths_34 mxLayoutSwitcher_LayoutSelector_LayoutRadio"
|
||||
class="_field_dgy0u_34 mxLayoutSwitcher_LayoutSelector_LayoutRadio"
|
||||
>
|
||||
<label
|
||||
aria-label="Modern"
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:r3:"
|
||||
>
|
||||
<div
|
||||
|
@ -292,11 +292,11 @@ exports[`AppearanceUserSettingsTab should render 1`] = `
|
|||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="_field_ssths_34 mxLayoutSwitcher_LayoutSelector_LayoutRadio"
|
||||
class="_field_dgy0u_34 mxLayoutSwitcher_LayoutSelector_LayoutRadio"
|
||||
>
|
||||
<label
|
||||
aria-label="Message bubbles"
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:rc:"
|
||||
>
|
||||
<div
|
||||
|
@ -418,11 +418,11 @@ exports[`AppearanceUserSettingsTab should render 1`] = `
|
|||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="_field_ssths_34 mxLayoutSwitcher_LayoutSelector_LayoutRadio"
|
||||
class="_field_dgy0u_34 mxLayoutSwitcher_LayoutSelector_LayoutRadio"
|
||||
>
|
||||
<label
|
||||
aria-label="IRC (experimental)"
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:rl:"
|
||||
>
|
||||
<div
|
||||
|
@ -545,13 +545,13 @@ exports[`AppearanceUserSettingsTab should render 1`] = `
|
|||
</div>
|
||||
</form>
|
||||
<form
|
||||
class="_root_ssths_24"
|
||||
class="_root_dgy0u_24"
|
||||
>
|
||||
<div
|
||||
class="_inline-field_ssths_40"
|
||||
class="_inline-field_dgy0u_40"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_ssths_52"
|
||||
class="_inline-field-control_dgy0u_52"
|
||||
>
|
||||
<div
|
||||
class="_container_qnvru_18"
|
||||
|
@ -570,16 +570,16 @@ exports[`AppearanceUserSettingsTab should render 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_ssths_46"
|
||||
class="_inline-field-body_dgy0u_46"
|
||||
>
|
||||
<label
|
||||
class="_label_ssths_67"
|
||||
class="_label_dgy0u_67"
|
||||
for="radix-:ru:"
|
||||
>
|
||||
Show compact text and messages
|
||||
</label>
|
||||
<span
|
||||
class="_message_ssths_93 _help-message_ssths_99"
|
||||
class="_message_dgy0u_98 _help-message_dgy0u_104"
|
||||
id="radix-:rv:"
|
||||
>
|
||||
Modern layout must be selected to use this feature.
|
||||
|
|
|
@ -85,6 +85,7 @@ exports[`<MjolnirUserSettingsTab /> renders correctly when user has no ignored u
|
|||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="submit"
|
||||
>
|
||||
Ignore
|
||||
</div>
|
||||
|
@ -149,6 +150,7 @@ exports[`<MjolnirUserSettingsTab /> renders correctly when user has no ignored u
|
|||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="submit"
|
||||
>
|
||||
Subscribe
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,6 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
|
|||
>
|
||||
<div
|
||||
class="mx_UserMenu"
|
||||
data-floating-ui-inert=""
|
||||
>
|
||||
<div
|
||||
aria-expanded="false"
|
||||
|
@ -43,7 +42,6 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
|
|||
<ul
|
||||
aria-label="Spaces"
|
||||
class="mx_AutoHideScrollbar mx_SpaceTreeLevel"
|
||||
data-floating-ui-inert=""
|
||||
data-rbd-droppable-context-id="0"
|
||||
data-rbd-droppable-id="top-level-spaces"
|
||||
role="tree"
|
||||
|
@ -238,7 +236,6 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
|
|||
aria-label="Threads"
|
||||
aria-labelledby=":r14:"
|
||||
class="_icon-button_bh2qc_17 mx_ThreadsActivityCentreButton"
|
||||
data-floating-ui-inert=""
|
||||
role="button"
|
||||
style="--cpd-icon-button-size: 32px;"
|
||||
tabindex="0"
|
||||
|
@ -263,7 +260,6 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
|
|||
</button>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
data-floating-ui-inert=""
|
||||
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: fixed; white-space: nowrap; width: 1px; top: 0px; left: 0px;"
|
||||
tabindex="-1"
|
||||
/>
|
||||
|
@ -276,7 +272,6 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
|
|||
/>
|
||||
<span
|
||||
aria-owns=":r19:"
|
||||
data-floating-ui-inert=""
|
||||
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: fixed; white-space: nowrap; width: 1px; top: 0px; left: 0px;"
|
||||
/>
|
||||
<span
|
||||
|
@ -291,7 +286,6 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
|
|||
aria-expanded="false"
|
||||
aria-label="Quick settings"
|
||||
class="mx_AccessibleButton mx_QuickSettingsButton"
|
||||
data-floating-ui-inert=""
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
|
|
|
@ -477,7 +477,9 @@ exports[`ThreadsActivityCentre should order the room with the same notification
|
|||
|
||||
exports[`ThreadsActivityCentre should render the release announcement 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
data-floating-ui-inert=""
|
||||
>
|
||||
<div
|
||||
class="mx_ThreadsActivityCentre_container"
|
||||
>
|
||||
|
@ -489,7 +491,6 @@ exports[`ThreadsActivityCentre should render the release announcement 1`] = `
|
|||
aria-label="Threads"
|
||||
aria-labelledby=":rc:"
|
||||
class="_icon-button_bh2qc_17 mx_ThreadsActivityCentreButton"
|
||||
data-floating-ui-inert=""
|
||||
role="button"
|
||||
style="--cpd-icon-button-size: 32px;"
|
||||
tabindex="0"
|
||||
|
@ -514,7 +515,6 @@ exports[`ThreadsActivityCentre should render the release announcement 1`] = `
|
|||
</button>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
data-floating-ui-inert=""
|
||||
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: fixed; white-space: nowrap; width: 1px; top: 0px; left: 0px;"
|
||||
tabindex="-1"
|
||||
/>
|
||||
|
@ -527,7 +527,6 @@ exports[`ThreadsActivityCentre should render the release announcement 1`] = `
|
|||
/>
|
||||
<span
|
||||
aria-owns=":rh:"
|
||||
data-floating-ui-inert=""
|
||||
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: fixed; white-space: nowrap; width: 1px; top: 0px; left: 0px;"
|
||||
/>
|
||||
<span
|
||||
|
@ -586,6 +585,7 @@ exports[`ThreadsActivityCentre should render the release announcement 1`] = `
|
|||
>
|
||||
<span
|
||||
data-floating-ui-focus-guard=""
|
||||
data-floating-ui-inert=""
|
||||
data-type="inside"
|
||||
role="button"
|
||||
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: fixed; white-space: nowrap; width: 1px; top: 0px; left: 0px;"
|
||||
|
@ -648,6 +648,7 @@ exports[`ThreadsActivityCentre should render the release announcement 1`] = `
|
|||
</div>
|
||||
<span
|
||||
data-floating-ui-focus-guard=""
|
||||
data-floating-ui-inert=""
|
||||
data-type="inside"
|
||||
role="button"
|
||||
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: fixed; white-space: nowrap; width: 1px; top: 0px; left: 0px;"
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
Copyright 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 { mocked } from "jest-mock";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { waitFor } from "jest-matrix-react";
|
||||
|
||||
import { createCrossSigning } from "../../../src/CreateCrossSigning";
|
||||
import { InitialCryptoSetupStore } from "../../../src/stores/InitialCryptoSetupStore";
|
||||
import { SdkContextClass } from "../../../src/contexts/SDKContext";
|
||||
import { createTestClient } from "../../test-utils";
|
||||
import { AccountPasswordStore } from "../../../src/stores/AccountPasswordStore";
|
||||
|
||||
jest.mock("../../../src/CreateCrossSigning", () => ({
|
||||
createCrossSigning: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("InitialCryptoSetupStore", () => {
|
||||
let testStore: InitialCryptoSetupStore;
|
||||
let client: MatrixClient;
|
||||
let stores: SdkContextClass;
|
||||
|
||||
let createCrossSigningResolve: () => void;
|
||||
let createCrossSigningReject: (e: Error) => void;
|
||||
|
||||
beforeEach(() => {
|
||||
testStore = new InitialCryptoSetupStore();
|
||||
client = createTestClient();
|
||||
stores = {
|
||||
accountPasswordStore: {
|
||||
getPassword: jest.fn(),
|
||||
} as unknown as AccountPasswordStore,
|
||||
} as unknown as SdkContextClass;
|
||||
|
||||
mocked(createCrossSigning).mockImplementation(() => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
createCrossSigningResolve = resolve;
|
||||
createCrossSigningReject = reject;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should call createCrossSigning when startInitialCryptoSetup is called", async () => {
|
||||
testStore.startInitialCryptoSetup(client, false, stores, jest.fn());
|
||||
|
||||
await waitFor(() => expect(createCrossSigning).toHaveBeenCalled());
|
||||
});
|
||||
|
||||
it("emits an update event when createCrossSigning resolves", async () => {
|
||||
const updateSpy = jest.fn();
|
||||
testStore.on("update", updateSpy);
|
||||
|
||||
testStore.startInitialCryptoSetup(client, false, stores, jest.fn());
|
||||
createCrossSigningResolve();
|
||||
|
||||
await waitFor(() => expect(updateSpy).toHaveBeenCalled());
|
||||
expect(testStore.getStatus()).toBe("complete");
|
||||
});
|
||||
|
||||
it("emits an update event when createCrossSigning rejects", async () => {
|
||||
const updateSpy = jest.fn();
|
||||
testStore.on("update", updateSpy);
|
||||
|
||||
testStore.startInitialCryptoSetup(client, false, stores, jest.fn());
|
||||
createCrossSigningReject(new Error("Test error"));
|
||||
|
||||
await waitFor(() => expect(updateSpy).toHaveBeenCalled());
|
||||
expect(testStore.getStatus()).toBe("error");
|
||||
});
|
||||
|
||||
it("should ignore failures if tokenLogin is true", async () => {
|
||||
const updateSpy = jest.fn();
|
||||
testStore.on("update", updateSpy);
|
||||
|
||||
testStore.startInitialCryptoSetup(client, true, stores, jest.fn());
|
||||
createCrossSigningReject(new Error("Test error"));
|
||||
|
||||
await waitFor(() => expect(updateSpy).toHaveBeenCalled());
|
||||
expect(testStore.getStatus()).toBe("complete");
|
||||
});
|
||||
});
|
|
@ -178,26 +178,22 @@ describe("formatDate", () => {
|
|||
|
||||
it("should return time string if date is within same day", () => {
|
||||
const date = new Date(REPEATABLE_DATE.getTime() + 2 * HOUR_MS + 12 * MINUTE_MS);
|
||||
// We use en-US for these tests because there was a change in Node 22.12 which removed
|
||||
// the comma after the weekday for en-GB which makes the test output different things
|
||||
// on different node versions. I'm not sure what a better fix would be, so let's just use
|
||||
// a locale that happens to have a more stable formatting right now.
|
||||
expect(formatDate(date, false, "en-US")).toMatchInlineSnapshot(`"19:10"`);
|
||||
expect(formatDate(date, false, "en-GB")).toMatchInlineSnapshot(`"19:10"`);
|
||||
});
|
||||
|
||||
it("should return time string with weekday if date is within last 6 days", () => {
|
||||
const date = new Date(REPEATABLE_DATE.getTime() - 6 * DAY_MS + 2 * HOUR_MS + 12 * MINUTE_MS);
|
||||
expect(formatDate(date, false, "en-US")).toMatchInlineSnapshot(`"Fri 19:10"`);
|
||||
expect(formatDate(date, false, "en-GB")).toMatchInlineSnapshot(`"Fri 19:10"`);
|
||||
});
|
||||
|
||||
it("should return time & date string without year if it is within the same year", () => {
|
||||
const date = new Date(REPEATABLE_DATE.getTime() - 66 * DAY_MS + 2 * HOUR_MS + 12 * MINUTE_MS);
|
||||
expect(formatDate(date, false, "en-US")).toMatchInlineSnapshot(`"Mon, Sep 12, 19:10"`);
|
||||
expect(formatDate(date, false, "en-GB")).toMatchInlineSnapshot(`"Mon, 12 Sept, 19:10"`);
|
||||
});
|
||||
|
||||
it("should return full time & date string otherwise", () => {
|
||||
const date = new Date(REPEATABLE_DATE.getTime() - 666 * DAY_MS + 2 * HOUR_MS + 12 * MINUTE_MS);
|
||||
expect(formatDate(date, false, "en-US")).toMatchInlineSnapshot(`"Wed, Jan 20, 2021, 19:10"`);
|
||||
expect(formatDate(date, false, "en-GB")).toMatchInlineSnapshot(`"Wed, 20 Jan 2021, 19:10"`);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -187,6 +187,18 @@ module.exports = (env, argv) => {
|
|||
},
|
||||
|
||||
resolve: {
|
||||
// We define an alternative import path so we can safely use src/ across the react-sdk
|
||||
// and js-sdk. We already import from src/ where possible to ensure our source maps are
|
||||
// extremely accurate (and because we're capable of compiling the layers manually rather
|
||||
// than relying on partially-mangled output from babel), though we do need to fix the
|
||||
// package level import (stuff like `import {Thing} from "matrix-js-sdk"` for example).
|
||||
// We can't use the aliasing down below to point at src/ because that'll fail to resolve
|
||||
// the package.json for the dependency. Instead, we rely on the package.json of each
|
||||
// layer to have our custom alternate fields to load things in the right order. These are
|
||||
// the defaults of webpack prepended with `matrix_src_`.
|
||||
mainFields: ["matrix_src_browser", "matrix_src_main", "browser", "main"],
|
||||
aliasFields: ["matrix_src_browser", "browser"],
|
||||
|
||||
// We need to specify that TS can be resolved without an extension
|
||||
extensions: [".js", ".json", ".ts", ".tsx"],
|
||||
alias: {
|
||||
|
|
426
yarn.lock
|
@ -34,7 +34,7 @@
|
|||
dependencies:
|
||||
axe-core "~4.10.2"
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2":
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0":
|
||||
version "7.26.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85"
|
||||
integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==
|
||||
|
@ -51,17 +51,12 @@
|
|||
"@babel/highlight" "^7.25.7"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.26.0":
|
||||
"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.9", "@babel/compat-data@^7.26.0":
|
||||
version "7.26.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.2.tgz#278b6b13664557de95b8f35b90d96785850bb56e"
|
||||
integrity sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==
|
||||
|
||||
"@babel/compat-data@^7.25.9":
|
||||
version "7.26.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.3.tgz#99488264a56b2aded63983abd6a417f03b92ed02"
|
||||
integrity sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==
|
||||
|
||||
"@babel/core@^7.0.0", "@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.18.5", "@babel/core@^7.21.3", "@babel/core@^7.23.9":
|
||||
"@babel/core@^7.0.0", "@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.18.5", "@babel/core@^7.21.3", "@babel/core@^7.23.9", "@babel/core@^7.24.4":
|
||||
version "7.26.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40"
|
||||
integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==
|
||||
|
@ -108,13 +103,13 @@
|
|||
"@jridgewell/trace-mapping" "^0.3.25"
|
||||
jsesc "^3.0.2"
|
||||
|
||||
"@babel/generator@^7.26.0", "@babel/generator@^7.26.3":
|
||||
version "7.26.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.3.tgz#ab8d4360544a425c90c248df7059881f4b2ce019"
|
||||
integrity sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==
|
||||
"@babel/generator@^7.25.9", "@babel/generator@^7.26.0":
|
||||
version "7.26.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.2.tgz#87b75813bec87916210e5e01939a4c823d6bb74f"
|
||||
integrity sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.26.3"
|
||||
"@babel/types" "^7.26.3"
|
||||
"@babel/parser" "^7.26.2"
|
||||
"@babel/types" "^7.26.0"
|
||||
"@jridgewell/gen-mapping" "^0.3.5"
|
||||
"@jridgewell/trace-mapping" "^0.3.25"
|
||||
jsesc "^3.0.2"
|
||||
|
@ -308,13 +303,20 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.25.8"
|
||||
|
||||
"@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3":
|
||||
"@babel/parser@^7.24.4":
|
||||
version "7.26.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234"
|
||||
integrity sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==
|
||||
dependencies:
|
||||
"@babel/types" "^7.26.3"
|
||||
|
||||
"@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.2":
|
||||
version "7.26.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.2.tgz#fd7b6f487cfea09889557ef5d4eeb9ff9a5abd11"
|
||||
integrity sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==
|
||||
dependencies:
|
||||
"@babel/types" "^7.26.0"
|
||||
|
||||
"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz#cc2e53ebf0a0340777fff5ed521943e253b4d8fe"
|
||||
|
@ -1065,9 +1067,9 @@
|
|||
esutils "^2.0.2"
|
||||
|
||||
"@babel/preset-react@^7.12.10", "@babel/preset-react@^7.18.6":
|
||||
version "7.26.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.26.3.tgz#7c5e028d623b4683c1f83a0bd4713b9100560caa"
|
||||
integrity sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.25.9.tgz#5f473035dc2094bcfdbc7392d0766bd42dce173e"
|
||||
integrity sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.25.9"
|
||||
"@babel/helper-validator-option" "^7.25.9"
|
||||
|
@ -1126,15 +1128,15 @@
|
|||
globals "^11.1.0"
|
||||
|
||||
"@babel/traverse@^7.25.9":
|
||||
version "7.26.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.4.tgz#ac3a2a84b908dde6d463c3bfa2c5fdc1653574bd"
|
||||
integrity sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84"
|
||||
integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.26.2"
|
||||
"@babel/generator" "^7.26.3"
|
||||
"@babel/parser" "^7.26.3"
|
||||
"@babel/code-frame" "^7.25.9"
|
||||
"@babel/generator" "^7.25.9"
|
||||
"@babel/parser" "^7.25.9"
|
||||
"@babel/template" "^7.25.9"
|
||||
"@babel/types" "^7.26.3"
|
||||
"@babel/types" "^7.25.9"
|
||||
debug "^4.3.1"
|
||||
globals "^11.1.0"
|
||||
|
||||
|
@ -1147,7 +1149,7 @@
|
|||
"@babel/helper-validator-identifier" "^7.25.7"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@^7.25.7", "@babel/types@^7.4.4":
|
||||
"@babel/types@^7.25.7", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.4.4":
|
||||
version "7.26.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.0.tgz#deabd08d6b753bc8e0f198f8709fb575e31774ff"
|
||||
integrity sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==
|
||||
|
@ -1155,7 +1157,7 @@
|
|||
"@babel/helper-string-parser" "^7.25.9"
|
||||
"@babel/helper-validator-identifier" "^7.25.9"
|
||||
|
||||
"@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.3":
|
||||
"@babel/types@^7.26.3":
|
||||
version "7.26.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0"
|
||||
integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==
|
||||
|
@ -1584,10 +1586,10 @@
|
|||
dependencies:
|
||||
"@floating-ui/dom" "^1.0.0"
|
||||
|
||||
"@floating-ui/react@^0.27.0":
|
||||
version "0.27.0"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.27.0.tgz#e0931fd09374ab4b8ce1a1af5cb44d1ccd1bb95a"
|
||||
integrity sha512-WLEksq7fJapXSJbmfiyq9pAW0a7ZFMEJToFE4oTDESxGjoa+nZu3YMjmZE2KvoUtQhqOK2yMMfWQFZyeWD0wGQ==
|
||||
"@floating-ui/react@^0.26.24":
|
||||
version "0.26.25"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.25.tgz#cf4c8a2b89fab1a71712d15e6551df3bfbd2ea1d"
|
||||
integrity sha512-hZOmgN0NTOzOuZxI1oIrDu3Gcl8WViIkvPMpB4xdd4QD6xAMtwgwr3VPoiyH/bLtRcS1cDnhxLSD1NsMJmwh/A==
|
||||
dependencies:
|
||||
"@floating-ui/react-dom" "^2.1.2"
|
||||
"@floating-ui/utils" "^0.2.8"
|
||||
|
@ -1608,37 +1610,36 @@
|
|||
resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.1.0.tgz#ab629b2c662457022d2d6a29854b8dc8ba538c47"
|
||||
integrity sha512-zKZR3kf1G0noIes1frLfOHP5EXVVm0M7sV/l9f/AaYf+M/DId35FO4LkigWjqWYjTJZGgplhdv4cB+ssvCqr5A==
|
||||
|
||||
"@formatjs/ecma402-abstract@2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.1.tgz#cdeb3ffe1aeea9c4284b85b7e37e8e8615314c39"
|
||||
integrity sha512-Ip9uV+/MpLXWRk03U/GzeJMuPeOXpJBSB5V1tjA6kJhvqssye5J5LoYLc7Z5IAHb7nR62sRoguzrFiVCP/hnzw==
|
||||
"@formatjs/ecma402-abstract@2.2.4":
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.2.4.tgz#355e42d375678229d46dc8ad7a7139520dd03e7b"
|
||||
integrity sha512-lFyiQDVvSbQOpU+WFd//ILolGj4UgA/qXrKeZxdV14uKiAUiPAtX6XAn7WBCRi7Mx6I7EybM9E5yYn4BIpZWYg==
|
||||
dependencies:
|
||||
"@formatjs/fast-memoize" "2.2.5"
|
||||
"@formatjs/intl-localematcher" "0.5.9"
|
||||
decimal.js "10"
|
||||
"@formatjs/fast-memoize" "2.2.3"
|
||||
"@formatjs/intl-localematcher" "0.5.8"
|
||||
tslib "2"
|
||||
|
||||
"@formatjs/fast-memoize@2.2.5":
|
||||
version "2.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.5.tgz#54a4a1793d773b72c372d3dcab3595149aee7880"
|
||||
integrity sha512-6PoewUMrrcqxSoBXAOJDiW1m+AmkrAj0RiXnOMD59GRaswjXhm3MDhgepXPBgonc09oSirAJTsAggzAGQf6A6g==
|
||||
"@formatjs/fast-memoize@2.2.3":
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.3.tgz#74e64109279d5244f9fc281f3ae90c407cece823"
|
||||
integrity sha512-3jeJ+HyOfu8osl3GNSL4vVHUuWFXR03Iz9jjgI7RwjG6ysu/Ymdr0JRCPHfF5yGbTE6JCrd63EpvX1/WybYRbA==
|
||||
dependencies:
|
||||
tslib "2"
|
||||
|
||||
"@formatjs/intl-localematcher@0.5.9":
|
||||
version "0.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.9.tgz#43c6ee22be85b83340bcb09bdfed53657a2720db"
|
||||
integrity sha512-8zkGu/sv5euxbjfZ/xmklqLyDGQSxsLqg8XOq88JW3cmJtzhCP8EtSJXlaKZnVO4beEaoiT9wj4eIoCQ9smwxA==
|
||||
"@formatjs/intl-localematcher@0.5.8":
|
||||
version "0.5.8"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.8.tgz#b11bbd04bd3551f7cadcb1ef1e231822d0e3c97e"
|
||||
integrity sha512-I+WDNWWJFZie+jkfkiK5Mp4hEDyRSEvmyfYadflOno/mmKJKcB17fEpEH0oJu/OWhhCJ8kJBDz2YMd/6cDl7Mg==
|
||||
dependencies:
|
||||
tslib "2"
|
||||
|
||||
"@formatjs/intl-segmenter@^11.5.7":
|
||||
version "11.7.7"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-segmenter/-/intl-segmenter-11.7.7.tgz#8a5aaa316e11ca2d31b99222e6fcf1ab539b085e"
|
||||
integrity sha512-610J5xz5DxtEpa16zNR89CrvA9qWHxQFkUB3FKiGao0Nwn7i8cl+oyBhuH9SvtXF9j2LUOM9VMdVCMzJkVANNw==
|
||||
version "11.7.4"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-segmenter/-/intl-segmenter-11.7.4.tgz#f99d87ee3f98515069285438a4913681fc243252"
|
||||
integrity sha512-pyHgFO86/CReKl20oK9jgaTMzSaG/nIMteMW8YuwUcS22EoMI1qbGTZ65oQ38KMT05SiHiMee2CP3WZvCi8YSQ==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "2.3.1"
|
||||
"@formatjs/intl-localematcher" "0.5.9"
|
||||
"@formatjs/ecma402-abstract" "2.2.4"
|
||||
"@formatjs/intl-localematcher" "0.5.8"
|
||||
tslib "2"
|
||||
|
||||
"@humanwhocodes/config-array@^0.13.0":
|
||||
|
@ -1881,9 +1882,9 @@
|
|||
chalk "^4.0.0"
|
||||
|
||||
"@jridgewell/gen-mapping@^0.3.5":
|
||||
version "0.3.8"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142"
|
||||
integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==
|
||||
version "0.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
|
||||
integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
|
||||
dependencies:
|
||||
"@jridgewell/set-array" "^1.2.1"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
@ -2433,10 +2434,10 @@
|
|||
"@sentry/core" "8.40.0"
|
||||
"@sentry/types" "8.40.0"
|
||||
|
||||
"@sentry/babel-plugin-component-annotate@2.22.7":
|
||||
version "2.22.7"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.22.7.tgz#604c7e33d48528a13477e7af597c4d5fca51b8bd"
|
||||
integrity sha512-aa7XKgZMVl6l04NY+3X7BP7yvQ/s8scn8KzQfTLrGRarziTlMGrsCOBQtCNWXOPEbtxAIHpZ9dsrAn5EJSivOQ==
|
||||
"@sentry/babel-plugin-component-annotate@2.22.6":
|
||||
version "2.22.6"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.22.6.tgz#829d6caf2c95c1c46108336de4e1049e6521435e"
|
||||
integrity sha512-V2g1Y1I5eSe7dtUVMBvAJr8BaLRr4CLrgNgtPaZyMT4Rnps82SrZ5zqmEkLXPumlXhLUWR6qzoMNN2u+RXVXfQ==
|
||||
|
||||
"@sentry/browser@^8.0.0":
|
||||
version "8.40.0"
|
||||
|
@ -2450,14 +2451,14 @@
|
|||
"@sentry/core" "8.40.0"
|
||||
"@sentry/types" "8.40.0"
|
||||
|
||||
"@sentry/bundler-plugin-core@2.22.7":
|
||||
version "2.22.7"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.22.7.tgz#28204a224cd1fef58d157e5beeb2493947a9bc35"
|
||||
integrity sha512-ouQh5sqcB8vsJ8yTTe0rf+iaUkwmeUlGNFi35IkCFUQlWJ22qS6OfvNjOqFI19e6eGUXks0c/2ieFC4+9wJ+1g==
|
||||
"@sentry/bundler-plugin-core@2.22.6":
|
||||
version "2.22.6"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.22.6.tgz#a1ea1fd43700a3ece9e7db016997e79a2782b87d"
|
||||
integrity sha512-1esQdgSUCww9XAntO4pr7uAM5cfGhLsgTK9MEwAKNfvpMYJi9NUTYa3A7AZmdA8V6107Lo4OD7peIPrDRbaDCg==
|
||||
dependencies:
|
||||
"@babel/core" "^7.18.5"
|
||||
"@sentry/babel-plugin-component-annotate" "2.22.7"
|
||||
"@sentry/cli" "2.39.1"
|
||||
"@sentry/babel-plugin-component-annotate" "2.22.6"
|
||||
"@sentry/cli" "^2.36.1"
|
||||
dotenv "^16.3.1"
|
||||
find-up "^5.0.0"
|
||||
glob "^9.3.2"
|
||||
|
@ -2499,7 +2500,7 @@
|
|||
resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.39.1.tgz#1a874a5570c6d162b35d9d001c96e5389d07d2cb"
|
||||
integrity sha512-xv0R2CMf/X1Fte3cMWie1NXuHmUyQPDBfCyIt6k6RPFPxAYUgcqgMPznYwVMwWEA1W43PaOkSn3d8ZylsDaETw==
|
||||
|
||||
"@sentry/cli@2.39.1":
|
||||
"@sentry/cli@^2.36.1":
|
||||
version "2.39.1"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.39.1.tgz#916bb5b7567ccf7fdf94ef6cf8a2b9ab78370d29"
|
||||
integrity sha512-JIb3e9vh0+OmQ0KxmexMXg9oZsR/G7HMwxt5BUIKAXZ9m17Xll4ETXTRnRUBT3sf7EpNGAmlQk1xEmVN9pYZYQ==
|
||||
|
@ -2531,11 +2532,11 @@
|
|||
integrity sha512-nuCf3U3deolPM9BjNnwCc33UtFl9ec15/r74ngAkNccn+A2JXdIAsDkGJMO/9mgSFykLe1QyeJ0pQFRisCGOiA==
|
||||
|
||||
"@sentry/webpack-plugin@^2.7.1":
|
||||
version "2.22.7"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/webpack-plugin/-/webpack-plugin-2.22.7.tgz#992c6c782c736f22e72eb318745e28cc24aabad7"
|
||||
integrity sha512-j5h5LZHWDlm/FQCCmEghQ9FzYXwfZdlOf3FE/X6rK6lrtx0JCAkq+uhMSasoyP4XYKL4P4vRS6WFSos4jxf/UA==
|
||||
version "2.22.6"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/webpack-plugin/-/webpack-plugin-2.22.6.tgz#8c9d27d5cd89153a5b6e08cc9dcb3048b122ffbc"
|
||||
integrity sha512-BiLhAzQYAz/9kCXKj2LeUKWf/9GBVn2dD0DeYK89s+sjDEaxjbcLBBiLlLrzT7eC9QVj2tUZRKOi6puCfc8ysw==
|
||||
dependencies:
|
||||
"@sentry/bundler-plugin-core" "2.22.7"
|
||||
"@sentry/bundler-plugin-core" "2.22.6"
|
||||
unplugin "1.0.1"
|
||||
uuid "^9.0.0"
|
||||
|
||||
|
@ -3048,9 +3049,9 @@
|
|||
"@types/node" "*"
|
||||
|
||||
"@types/jsrsasign@^10.5.4":
|
||||
version "10.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@types/jsrsasign/-/jsrsasign-10.5.15.tgz#5cf1ee506b2fa2435b6e1786a873285c7110eb82"
|
||||
integrity sha512-3stUTaSRtN09PPzVWR6aySD9gNnuymz+WviNHoTb85dKu+BjaV4uBbWWGykBBJkfwPtcNZVfTn2lbX00U+yhpQ==
|
||||
version "10.5.14"
|
||||
resolved "https://registry.yarnpkg.com/@types/jsrsasign/-/jsrsasign-10.5.14.tgz#61d1dbd791ecd11db556c1ca5d82453fc7207338"
|
||||
integrity sha512-lppSlfK6etu+cuKs40K4rg8As79PH6hzIB+v55zSqImbSH3SE6Fm8MBHCiI91cWlAP3Z4igtJK1VL3fSN09blQ==
|
||||
|
||||
"@types/katex@^0.16.0":
|
||||
version "0.16.7"
|
||||
|
@ -3114,9 +3115,9 @@
|
|||
undici-types "~6.20.0"
|
||||
|
||||
"@types/node@18":
|
||||
version "18.19.68"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.68.tgz#f4f10d9927a7eaf3568c46a6d739cc0967ccb701"
|
||||
integrity sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw==
|
||||
version "18.19.66"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.66.tgz#0937a47904ceba5994eedf5cf4b6d503d8d6136c"
|
||||
integrity sha512-14HmtUdGxFUalGRfLLn9Gc1oNWvWh5zNbsyOLo5JV6WARSeN1QcEBKRnZm9QqNfrutgsl/hY4eJW63aZ44aBCg==
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
|
||||
|
@ -3401,12 +3402,12 @@
|
|||
resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-2.1.1.tgz#d6175a99fe4b97688464126f255386990f3048d6"
|
||||
integrity sha512-QnUi2K14D9KTXxcLQKUU3V75cforZLMwhaaJDNftT8F5mG86950hAM+qhgDNEpEU+pkTffQj0/g/5859YmqWzQ==
|
||||
|
||||
"@vector-im/compound-web@^7.5.0":
|
||||
version "7.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-7.5.0.tgz#1547af5f0ee27b94f79ab11eee006059f3d09707"
|
||||
integrity sha512-Xhef8H5WrRmPuanzRBs8rnl+hwbcQnC7nKSCupUczAQ5hjlieBx4vcQYQ/nMkrs4rMGjgfFtR3E18wT5LlML/A==
|
||||
"@vector-im/compound-web@^7.4.0":
|
||||
version "7.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-7.4.0.tgz#a5af8af6346f8ff6c14c70f5d4eb2eab7357a7cc"
|
||||
integrity sha512-ZRBUeEGNmj/fTkIRa8zGnyVN7ytowpfOtHChqNm+m/+OTJN3o/lOMuQHDV8jeSEW2YwPJqGvPuG/dRr89IcQkA==
|
||||
dependencies:
|
||||
"@floating-ui/react" "^0.27.0"
|
||||
"@floating-ui/react" "^0.26.24"
|
||||
"@radix-ui/react-context-menu" "^2.2.1"
|
||||
"@radix-ui/react-dropdown-menu" "^2.1.1"
|
||||
"@radix-ui/react-form" "^0.1.0"
|
||||
|
@ -3424,7 +3425,7 @@
|
|||
dependencies:
|
||||
eslint-plugin-unicorn "^54.0.0"
|
||||
|
||||
"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1":
|
||||
"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.12.1":
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6"
|
||||
integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==
|
||||
|
@ -3490,7 +3491,7 @@
|
|||
resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz#917a20e93f71ad5602966c2d685ae0c6c21f60f1"
|
||||
integrity sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==
|
||||
|
||||
"@webassemblyjs/wasm-edit@^1.14.1":
|
||||
"@webassemblyjs/wasm-edit@^1.12.1":
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz#ac6689f502219b59198ddec42dcd496b1004d597"
|
||||
integrity sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==
|
||||
|
@ -3525,7 +3526,7 @@
|
|||
"@webassemblyjs/wasm-gen" "1.14.1"
|
||||
"@webassemblyjs/wasm-parser" "1.14.1"
|
||||
|
||||
"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.14.1":
|
||||
"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.12.1":
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz#b3e13f1893605ca78b52c68e54cf6a865f90b9fb"
|
||||
integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==
|
||||
|
@ -4211,15 +4212,7 @@ bytes@3.1.2:
|
|||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
|
||||
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
|
||||
|
||||
call-bind-apply-helpers@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz#32e5892e6361b29b0b545ba6f7763378daca2840"
|
||||
integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==
|
||||
dependencies:
|
||||
es-errors "^1.3.0"
|
||||
function-bind "^1.1.2"
|
||||
|
||||
call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6:
|
||||
call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
|
||||
integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
|
||||
|
@ -4230,16 +4223,6 @@ call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6:
|
|||
get-intrinsic "^1.2.4"
|
||||
set-function-length "^1.2.1"
|
||||
|
||||
call-bind@^1.0.7:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c"
|
||||
integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==
|
||||
dependencies:
|
||||
call-bind-apply-helpers "^1.0.0"
|
||||
es-define-property "^1.0.0"
|
||||
get-intrinsic "^1.2.4"
|
||||
set-function-length "^1.2.2"
|
||||
|
||||
callsites@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
|
@ -4821,11 +4804,11 @@ css-tree@^2.3.1:
|
|||
source-map-js "^1.0.1"
|
||||
|
||||
css-tree@^3.0.0, css-tree@^3.0.1:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-3.1.0.tgz#7aabc035f4e66b5c86f54570d55e05b1346eb0fd"
|
||||
integrity sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-3.0.1.tgz#bea6deaea60bb5bcf416adfb1ecf607a8d9471f6"
|
||||
integrity sha512-8Fxxv+tGhORlshCdCwnNJytvlvq46sOLSYEx2ZIGurahWvMucSRnyjPA3AmrMq4VPRYbHVpWj5VkiVasrM2H4Q==
|
||||
dependencies:
|
||||
mdn-data "2.12.2"
|
||||
mdn-data "2.12.1"
|
||||
source-map-js "^1.0.1"
|
||||
|
||||
css-tree@~2.2.0:
|
||||
|
@ -5002,10 +4985,10 @@ debug@2.6.9:
|
|||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@4, debug@^4.1.0, debug@^4.3.1:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
|
||||
integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
|
||||
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7, debug@~4.3.6:
|
||||
version "4.3.7"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
|
||||
integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
|
||||
dependencies:
|
||||
ms "^2.1.3"
|
||||
|
||||
|
@ -5016,19 +4999,12 @@ debug@^3.2.7:
|
|||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.1.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7, debug@~4.3.6:
|
||||
version "4.3.7"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
|
||||
integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
|
||||
dependencies:
|
||||
ms "^2.1.3"
|
||||
|
||||
decamelize@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==
|
||||
|
||||
decimal.js@10, decimal.js@^10.4.2:
|
||||
decimal.js@^10.4.2:
|
||||
version "10.4.3"
|
||||
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23"
|
||||
integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==
|
||||
|
@ -5280,18 +5256,9 @@ dot-case@^3.0.4:
|
|||
tslib "^2.0.3"
|
||||
|
||||
dotenv@^16.0.2, dotenv@^16.3.1:
|
||||
version "16.4.7"
|
||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26"
|
||||
integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==
|
||||
|
||||
dunder-proto@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.0.tgz#c2fce098b3c8f8899554905f4377b6d85dabaa80"
|
||||
integrity sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==
|
||||
dependencies:
|
||||
call-bind-apply-helpers "^1.0.0"
|
||||
es-errors "^1.3.0"
|
||||
gopd "^1.2.0"
|
||||
version "16.4.5"
|
||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
|
||||
integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
|
||||
|
||||
duplexer@^0.1.2:
|
||||
version "0.1.2"
|
||||
|
@ -5330,9 +5297,9 @@ ejs@^3.1.8:
|
|||
jake "^10.8.5"
|
||||
|
||||
electron-to-chromium@^1.5.41:
|
||||
version "1.5.72"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.72.tgz#a732805986d3a5b5fedd438ddf4616c7d78ac2df"
|
||||
integrity sha512-ZpSAUOZ2Izby7qnZluSrAlGgGQzucmFbN0n64dYzocYxnxV5ufurpj3VgEe4cUp7ir9LmeLxNYo8bVnlM8bQHw==
|
||||
version "1.5.67"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.67.tgz#66ebd2be4a77469ac2760ef5e9e460ba9a43a845"
|
||||
integrity sha512-nz88NNBsD7kQSAGGJyp8hS6xSPtWwqNogA0mjtc2nUYeEf3nURK9qpV18TuBdDmEDgVWotS8Wkzf+V52dSQ/LQ==
|
||||
|
||||
emittery@^0.13.1:
|
||||
version "0.13.1"
|
||||
|
@ -5481,10 +5448,12 @@ es-abstract@^1.17.5, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23
|
|||
unbox-primitive "^1.0.2"
|
||||
which-typed-array "^1.1.15"
|
||||
|
||||
es-define-property@^1.0.0, es-define-property@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
|
||||
integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
|
||||
es-define-property@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
|
||||
integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
|
||||
dependencies:
|
||||
get-intrinsic "^1.2.4"
|
||||
|
||||
es-errors@^1.2.1, es-errors@^1.3.0:
|
||||
version "1.3.0"
|
||||
|
@ -5674,6 +5643,18 @@ eslint-plugin-matrix-org@^2.0.2:
|
|||
resolved "https://registry.yarnpkg.com/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-2.0.2.tgz#95b86b0f16704ab19740f7c3c62eae69e20365e6"
|
||||
integrity sha512-cQy5Rjeq6uyu1mLXlPZwEJdyM0NmclrnEz68y792FSuuxzMyJNNYLGDQ5CkYW8H+PrD825HUFZ34pNXnjMOzOw==
|
||||
|
||||
eslint-plugin-react-compiler@^19.0.0-beta-df7b47d-20241124:
|
||||
version "19.0.0-beta-df7b47d-20241124"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.0.0-beta-df7b47d-20241124.tgz#468751d3a8a6781189405ee56b39b80545306df8"
|
||||
integrity sha512-82PfnllC8jP/68KdLAbpWuYTcfmtGLzkqy2IW85WopKMTr+4rdQpp+lfliQ/QE79wWrv/dRoADrk3Pdhq25nTw==
|
||||
dependencies:
|
||||
"@babel/core" "^7.24.4"
|
||||
"@babel/parser" "^7.24.4"
|
||||
"@babel/plugin-transform-private-methods" "^7.25.9"
|
||||
hermes-parser "^0.25.1"
|
||||
zod "^3.22.4"
|
||||
zod-validation-error "^3.0.3"
|
||||
|
||||
eslint-plugin-react-hooks@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz#72e2eefbac4b694f5324154619fee44f5f60f101"
|
||||
|
@ -5967,9 +5948,9 @@ expect@^29.0.0, expect@^29.7.0:
|
|||
jest-util "^29.7.0"
|
||||
|
||||
express@^4.18.2, express@^4.19.2:
|
||||
version "4.21.2"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32"
|
||||
integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==
|
||||
version "4.21.1"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.21.1.tgz#9dae5dda832f16b4eec941a4e44aa89ec481b281"
|
||||
integrity sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==
|
||||
dependencies:
|
||||
accepts "~1.3.8"
|
||||
array-flatten "1.1.1"
|
||||
|
@ -5990,7 +5971,7 @@ express@^4.18.2, express@^4.19.2:
|
|||
methods "~1.1.2"
|
||||
on-finished "2.4.1"
|
||||
parseurl "~1.3.3"
|
||||
path-to-regexp "0.1.12"
|
||||
path-to-regexp "0.1.10"
|
||||
proxy-addr "~2.0.7"
|
||||
qs "6.13.0"
|
||||
range-parser "~1.2.1"
|
||||
|
@ -6351,7 +6332,7 @@ get-east-asian-width@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz#21b4071ee58ed04ee0db653371b55b4299875389"
|
||||
integrity sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==
|
||||
|
||||
get-intrinsic@^1.2.1, get-intrinsic@^1.2.3:
|
||||
get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
|
||||
integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
|
||||
|
@ -6362,20 +6343,6 @@ get-intrinsic@^1.2.1, get-intrinsic@^1.2.3:
|
|||
has-symbols "^1.0.3"
|
||||
hasown "^2.0.0"
|
||||
|
||||
get-intrinsic@^1.2.4:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.5.tgz#dfe7dd1b30761b464fe51bf4bb00ac7c37b681e7"
|
||||
integrity sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==
|
||||
dependencies:
|
||||
call-bind-apply-helpers "^1.0.0"
|
||||
dunder-proto "^1.0.0"
|
||||
es-define-property "^1.0.1"
|
||||
es-errors "^1.3.0"
|
||||
function-bind "^1.1.2"
|
||||
gopd "^1.2.0"
|
||||
has-symbols "^1.1.0"
|
||||
hasown "^2.0.2"
|
||||
|
||||
get-nonce@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3"
|
||||
|
@ -6552,12 +6519,7 @@ globjoin@^0.1.4:
|
|||
resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43"
|
||||
integrity sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==
|
||||
|
||||
gopd@^1.0.1, gopd@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
|
||||
integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
|
||||
|
||||
gopd@^1.1.0:
|
||||
gopd@^1.0.1, gopd@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.1.0.tgz#df8f0839c2d48caefc32a025a49294d39606c912"
|
||||
integrity sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==
|
||||
|
@ -6608,30 +6570,18 @@ has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2:
|
|||
dependencies:
|
||||
es-define-property "^1.0.0"
|
||||
|
||||
has-proto@^1.0.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5"
|
||||
integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==
|
||||
dependencies:
|
||||
dunder-proto "^1.0.0"
|
||||
|
||||
has-proto@^1.0.3:
|
||||
has-proto@^1.0.1, has-proto@^1.0.3:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.1.0.tgz#deb10494cbbe8809bce168a3b961f42969f5ed43"
|
||||
integrity sha512-QLdzI9IIO1Jg7f9GT1gXpPpXArAn6cS31R1eEZqz08Gc+uQ8/XiqHWt17Fiw+2p6oTTIq5GXEpQkAlA88YRl/Q==
|
||||
dependencies:
|
||||
call-bind "^1.0.7"
|
||||
|
||||
has-symbols@^1.0.2:
|
||||
has-symbols@^1.0.2, has-symbols@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
|
||||
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
|
||||
|
||||
has-symbols@^1.0.3, has-symbols@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
|
||||
integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
|
||||
|
||||
has-tostringtag@^1.0.0, has-tostringtag@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
|
||||
|
@ -6651,6 +6601,18 @@ he@^1.2.0:
|
|||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||
|
||||
hermes-estree@0.25.1:
|
||||
version "0.25.1"
|
||||
resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.25.1.tgz#6aeec17d1983b4eabf69721f3aa3eb705b17f480"
|
||||
integrity sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==
|
||||
|
||||
hermes-parser@^0.25.1:
|
||||
version "0.25.1"
|
||||
resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.25.1.tgz#5be0e487b2090886c62bd8a11724cd766d5f54d1"
|
||||
integrity sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==
|
||||
dependencies:
|
||||
hermes-estree "0.25.1"
|
||||
|
||||
highlight.js@^11.3.1:
|
||||
version "11.10.0"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.10.0.tgz#6e3600dc4b33d6dc23d5bd94fbf72405f5892b92"
|
||||
|
@ -7829,21 +7791,16 @@ jsdom@^20.0.0:
|
|||
ws "^8.11.0"
|
||||
xml-name-validator "^4.0.0"
|
||||
|
||||
jsesc@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d"
|
||||
integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
|
||||
jsesc@^3.0.2, jsesc@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e"
|
||||
integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==
|
||||
|
||||
jsesc@~0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
|
||||
integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==
|
||||
|
||||
jsesc@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e"
|
||||
integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==
|
||||
|
||||
json-buffer@3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
|
||||
|
@ -7960,9 +7917,9 @@ kleur@^3.0.3:
|
|||
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
|
||||
|
||||
knip@^5.36.2:
|
||||
version "5.39.2"
|
||||
resolved "https://registry.yarnpkg.com/knip/-/knip-5.39.2.tgz#1faacd8d8ef36b509b2f6e396cce85b645abb04e"
|
||||
integrity sha512-BuvuWRllLWV/r2G4m9ggNH+DZ6gouP/dhtJPXVlMbWNF++w9/EfrF6k2g7YBKCwjzCC+PXmYtpH8S2t8RjnY4Q==
|
||||
version "5.38.3"
|
||||
resolved "https://registry.yarnpkg.com/knip/-/knip-5.38.3.tgz#a139e0c6215c9958d213ce1a9e3985cf5de2774e"
|
||||
integrity sha512-pg3CMzWlZy4mnuwxieGoK74oOgzFPvsUR/aE8NSqx2oQr56soXTzmw8GsHR277pU52Fe0h4/pho2PMhVeEvj8g==
|
||||
dependencies:
|
||||
"@nodelib/fs.walk" "1.2.8"
|
||||
"@snyk/github-codeowners" "1.1.0"
|
||||
|
@ -8041,10 +7998,10 @@ lines-and-columns@^1.1.6:
|
|||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
||||
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
||||
|
||||
linkify-element@4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/linkify-element/-/linkify-element-4.2.0.tgz#fb5c6d47576487a463fd22a0cc889e15833aa943"
|
||||
integrity sha512-LahyRMhXAgWTP9TOid7pTv8UUZFDz+saLkIVAoGNmOvISt+uSeBzdGhk3dsvkdzAh1QMhkO+fVJjmkMEITre5g==
|
||||
linkify-element@4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/linkify-element/-/linkify-element-4.1.4.tgz#d4050b41fb47c44871e5eed93bc11865e403cc90"
|
||||
integrity sha512-XhSTTF7b7OoX4KIkwVG8MET5DSFEHohT0Gp5pjmsByYp+JCyZq5rSZGsar5dYzeuKUV6TqTSLtsH/NzBBwBxgQ==
|
||||
|
||||
linkify-it@^4.0.1:
|
||||
version "4.0.1"
|
||||
|
@ -8053,20 +8010,20 @@ linkify-it@^4.0.1:
|
|||
dependencies:
|
||||
uc.micro "^1.0.1"
|
||||
|
||||
linkify-react@4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/linkify-react/-/linkify-react-4.2.0.tgz#d143b2af8efa5e3b09517b66ed442624c3e06bcf"
|
||||
integrity sha512-dIcDGo+n4FP2FPIHDcqB7cUE+omkcEgQJpc7sNNP4+XZ9FUhFAkKjGnHMzsZM+B4yF93sK166z9K5cKTe/JpzA==
|
||||
linkify-react@4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/linkify-react/-/linkify-react-4.1.4.tgz#6c709f3f96543914874982f4b0b00f9c9270ce93"
|
||||
integrity sha512-UI9nqHtFzHYRUvVRrYeua5GIXkc0Jy3RpLsJBWEht7HwqjAa2qSaIksGmNSLqclNpO/5AkwaxUJv71I/pQsk9Q==
|
||||
|
||||
linkify-string@4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/linkify-string/-/linkify-string-4.2.0.tgz#e8c5a9d57698e81e7cce7f4915ddbcbde17134c0"
|
||||
integrity sha512-LqOKk0+RlqibFkxjPAGOL7Mfssqj6/SdG9QWGvzeVDpoWXhaw9OXxseCtFanjIl7C6UyTTZizhyGr4IWLfijiw==
|
||||
linkify-string@4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/linkify-string/-/linkify-string-4.1.4.tgz#89fb814e05c5b22f76d2a2a640bc8b1db4c6694f"
|
||||
integrity sha512-4z2UEzEi4SxnhWMzzZ8Pa8vIOwX/2U0XWxk/0UIA7lI+Dn0ZRKqTE9ildnO6Jl6K5hqVuLKTeMD8p4bdFW6P8g==
|
||||
|
||||
linkifyjs@4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-4.2.0.tgz#9dd30222b9cbabec9c950e725ec00031c7fa3f08"
|
||||
integrity sha512-pCj3PrQyATaoTYKHrgWRF3SJwsm61udVh+vuls/Rl6SptiDhgE7ziUIudAedRY9QEfynmM7/RmLEfPUyw1HPCw==
|
||||
linkifyjs@4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-4.1.4.tgz#2766605a20078d50c90f35af22275a42dfb7dfc4"
|
||||
integrity sha512-0/NxkHNpiJ0k9VrYCkAn9OtU1eu8xEr1tCCpDtSsVRm/SF0xAak2Gzv3QimSfgUgqLBCDlfhMbu73XvaEHUTPQ==
|
||||
|
||||
lint-staged@^15.0.2:
|
||||
version "15.2.10"
|
||||
|
@ -8368,7 +8325,12 @@ mdn-data@2.0.30:
|
|||
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc"
|
||||
integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==
|
||||
|
||||
mdn-data@2.12.2, mdn-data@^2.12.2:
|
||||
mdn-data@2.12.1:
|
||||
version "2.12.1"
|
||||
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.12.1.tgz#10cb462215c13d95c92ff60d0fb3becac1bbb924"
|
||||
integrity sha512-rsfnCbOHjqrhWxwt5/wtSLzpoKTzW7OXdT5lLOIH1OTYhWu9rRJveGq0sKvDZODABH7RX+uoR+DYcpFnq4Tf6Q==
|
||||
|
||||
mdn-data@^2.12.2:
|
||||
version "2.12.2"
|
||||
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.12.2.tgz#9ae6c41a9e65adf61318b32bff7b64fbfb13f8cf"
|
||||
integrity sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==
|
||||
|
@ -8652,9 +8614,9 @@ node-int64@^0.4.0:
|
|||
integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
|
||||
|
||||
node-releases@^2.0.18:
|
||||
version "2.0.19"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314"
|
||||
integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==
|
||||
version "2.0.18"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f"
|
||||
integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==
|
||||
|
||||
normalize-package-data@^2.5.0:
|
||||
version "2.5.0"
|
||||
|
@ -9040,10 +9002,10 @@ path-scurry@^2.0.0:
|
|||
lru-cache "^11.0.0"
|
||||
minipass "^7.1.2"
|
||||
|
||||
path-to-regexp@0.1.12:
|
||||
version "0.1.12"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7"
|
||||
integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==
|
||||
path-to-regexp@0.1.10:
|
||||
version "0.1.10"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b"
|
||||
integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==
|
||||
|
||||
path-to-regexp@^2.2.1:
|
||||
version "2.4.0"
|
||||
|
@ -9781,10 +9743,10 @@ prelude-ls@^1.2.1:
|
|||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
|
||||
|
||||
prettier@3.4.2:
|
||||
version "3.4.2"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f"
|
||||
integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==
|
||||
prettier@3.4.1:
|
||||
version "3.4.1"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.1.tgz#e211d451d6452db0a291672ca9154bc8c2579f7b"
|
||||
integrity sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==
|
||||
|
||||
pretty-error@^4.0.0:
|
||||
version "4.0.0"
|
||||
|
@ -10597,7 +10559,7 @@ set-blocking@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
|
||||
|
||||
set-function-length@^1.2.1, set-function-length@^1.2.2:
|
||||
set-function-length@^1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
|
||||
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
|
||||
|
@ -11257,7 +11219,7 @@ terser-webpack-plugin@^5.3.10, terser-webpack-plugin@^5.3.9:
|
|||
serialize-javascript "^6.0.1"
|
||||
terser "^5.26.0"
|
||||
|
||||
terser@^5.10.0:
|
||||
terser@^5.10.0, terser@^5.26.0:
|
||||
version "5.36.0"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.36.0.tgz#8b0dbed459ac40ff7b4c9fd5a3a2029de105180e"
|
||||
integrity sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==
|
||||
|
@ -11267,16 +11229,6 @@ terser@^5.10.0:
|
|||
commander "^2.20.0"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
terser@^5.26.0:
|
||||
version "5.37.0"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.37.0.tgz#38aa66d1cfc43d0638fab54e43ff8a4f72a21ba3"
|
||||
integrity sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==
|
||||
dependencies:
|
||||
"@jridgewell/source-map" "^0.3.3"
|
||||
acorn "^8.8.2"
|
||||
commander "^2.20.0"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
test-exclude@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"
|
||||
|
@ -11972,15 +11924,15 @@ webpack-virtual-modules@^0.5.0:
|
|||
integrity sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==
|
||||
|
||||
webpack@^5.89.0:
|
||||
version "5.97.1"
|
||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.97.1.tgz#972a8320a438b56ff0f1d94ade9e82eac155fa58"
|
||||
integrity sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==
|
||||
version "5.96.1"
|
||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.96.1.tgz#3676d1626d8312b6b10d0c18cc049fba7ac01f0c"
|
||||
integrity sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==
|
||||
dependencies:
|
||||
"@types/eslint-scope" "^3.7.7"
|
||||
"@types/estree" "^1.0.6"
|
||||
"@webassemblyjs/ast" "^1.14.1"
|
||||
"@webassemblyjs/wasm-edit" "^1.14.1"
|
||||
"@webassemblyjs/wasm-parser" "^1.14.1"
|
||||
"@webassemblyjs/ast" "^1.12.1"
|
||||
"@webassemblyjs/wasm-edit" "^1.12.1"
|
||||
"@webassemblyjs/wasm-parser" "^1.12.1"
|
||||
acorn "^8.14.0"
|
||||
browserslist "^4.24.0"
|
||||
chrome-trace-event "^1.0.2"
|
||||
|
@ -12319,6 +12271,6 @@ zod-validation-error@^3.0.3:
|
|||
integrity sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==
|
||||
|
||||
zod@^3.22.4:
|
||||
version "3.24.0"
|
||||
resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.0.tgz#babb32313f7c5f4a99812feee806d186b4f76bde"
|
||||
integrity sha512-Hz+wiY8yD0VLA2k/+nsg2Abez674dDGTai33SwNvMPuf9uIrBC9eFgIMQxBBbHFxVXi8W+5nX9DcAh9YNSQm/w==
|
||||
version "3.23.8"
|
||||
resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d"
|
||||
integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==
|
||||
|
|