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