diff --git a/.eslintrc.js b/.eslintrc.js
index f3e38f94c3c..bcf20ab5a62 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -115,6 +115,8 @@ module.exports = {
"@typescript-eslint/no-explicit-any": "off",
// We'd rather not do this but we do
"@typescript-eslint/ban-ts-comment": "off",
+ // We're okay with assertion errors when we ask for them
+ "@typescript-eslint/no-non-null-assertion": "off",
},
},
// temporary override for offending icon require files
diff --git a/.github/workflows/element-build-and-test.yaml b/.github/workflows/element-build-and-test.yaml
index a1047094158..9ed06bd8ad9 100644
--- a/.github/workflows/element-build-and-test.yaml
+++ b/.github/workflows/element-build-and-test.yaml
@@ -71,6 +71,7 @@ jobs:
# to run the tests, so use chrome.
browser: chrome
start: npx serve -p 8080 webapp
+ wait-on: 'http://localhost:8080'
record: true
command-prefix: 'yarn percy exec --'
env:
@@ -83,6 +84,8 @@ jobs:
PERCY_BROWSER_EXECUTABLE: /usr/bin/chromium-browser
# pass GitHub token to allow accurately detecting a build vs a re-run build
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # make Node's os.tmpdir() return something where we actually have permissions
+ TMPDIR: ${{ runner.temp }}
- name: Upload Artifact
if: failure()
diff --git a/.github/workflows/i18n_check.yml b/.github/workflows/i18n_check.yml
new file mode 100644
index 00000000000..2acfb126850
--- /dev/null
+++ b/.github/workflows/i18n_check.yml
@@ -0,0 +1,40 @@
+name: i18n Check
+on:
+ workflow_call: { }
+jobs:
+ check:
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: read
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: "Get modified files"
+ id: changed_files
+ if: github.event_name == 'pull_request' && github.event.pull_request.user.login != 'RiotTranslateBot'
+ uses: tj-actions/changed-files@v19
+ with:
+ files: |
+ src/i18n/strings/*
+ files_ignore: |
+ src/i18n/strings/en_EN.json
+
+ - name: "Assert only en_EN was modified"
+ if: |
+ github.event_name == 'pull_request' &&
+ github.event.pull_request.user.login != 'RiotTranslateBot' &&
+ steps.changed_files.outputs.any_modified == 'true'
+ run: |
+ echo "Only translation files modified by `yarn i18n` can be committed - other translation files will confuse weblate in unrecoverable ways."
+ exit 1
+
+ - uses: actions/setup-node@v3
+ with:
+ cache: 'yarn'
+
+ # Does not need branch matching as only analyses this layer
+ - name: Install Deps
+ run: "yarn install --pure-lockfile"
+
+ - name: i18n Check
+ run: "yarn run diff-i18n"
diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml
index 8d115062ea6..d861ea054e6 100644
--- a/.github/workflows/pull_request.yaml
+++ b/.github/workflows/pull_request.yaml
@@ -2,6 +2,7 @@ name: Pull Request
on:
pull_request_target:
types: [ opened, edited, labeled, unlabeled, synchronize ]
+concurrency: ${{ github.workflow }}-${{ github.event.pull_request.head.ref }}
jobs:
changelog:
name: Preview Changelog
diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml
index 95b06bab6b5..11660e68ba4 100644
--- a/.github/workflows/sonarqube.yml
+++ b/.github/workflows/sonarqube.yml
@@ -5,7 +5,7 @@ on:
types:
- completed
concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
+ group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true
jobs:
prdetails:
diff --git a/.github/workflows/static_analysis.yaml b/.github/workflows/static_analysis.yaml
index 266f7c728ad..82a99190a43 100644
--- a/.github/workflows/static_analysis.yaml
+++ b/.github/workflows/static_analysis.yaml
@@ -39,41 +39,7 @@ jobs:
i18n_lint:
name: "i18n Check"
- runs-on: ubuntu-latest
- permissions:
- pull-requests: read
- steps:
- - uses: actions/checkout@v2
-
- - name: "Get modified files"
- id: changed_files
- if: github.event_name == 'pull_request' && github.actor != 'RiotTranslateBot'
- uses: tj-actions/changed-files@v19
- with:
- files: |
- src/i18n/strings/*
- files_ignore: |
- src/i18n/strings/en_EN.json
-
- - name: "Assert only en_EN was modified"
- if: |
- github.event_name == 'pull_request' &&
- github.actor != 'RiotTranslateBot' &&
- steps.changed_files.outputs.any_modified == 'true'
- run: |
- echo "You can only modify en_EN.json, do not touch any of the other i18n files as Weblate will be confused"
- exit 1
-
- - uses: actions/setup-node@v3
- with:
- cache: 'yarn'
-
- # Does not need branch matching as only analyses this layer
- - name: Install Deps
- run: "yarn install"
-
- - name: i18n Check
- run: "yarn run diff-i18n"
+ uses: matrix-org/matrix-react-sdk/.github/workflows/i18n_check.yml@develop
js_lint:
name: "ESLint"
diff --git a/.gitignore b/.gitignore
index 1c4eb114e7d..024057643b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,5 +27,4 @@ package-lock.json
/cypress/synapselogs
# These could have files in them but don't currently
# Cypress will still auto-create them though...
-/cypress/fixtures
/cypress/performance
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d6ad5a02863..3474847522e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,57 @@
+Changes in [3.46.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.46.0) (2022-06-07)
+=====================================================================================================
+
+## ✨ Features
+ * Configure custom home.html via `.well-known/matrix/client["io.element.embedded_pages"]["home_url"]` for all your element-web/desktop users ([\#7790](https://github.com/matrix-org/matrix-react-sdk/pull/7790)). Contributed by @johannes-krude.
+ * Live location sharing - open location in OpenStreetMap ([\#8695](https://github.com/matrix-org/matrix-react-sdk/pull/8695)). Contributed by @kerryarchibald.
+ * Show a dialog when Jitsi encounters an error ([\#8701](https://github.com/matrix-org/matrix-react-sdk/pull/8701)). Fixes vector-im/element-web#22284.
+ * Add support for setting the `avatar_url` of widgets by integration managers. ([\#8550](https://github.com/matrix-org/matrix-react-sdk/pull/8550)). Contributed by @Fox32.
+ * Add an option to ignore (block) a user when reporting their events ([\#8471](https://github.com/matrix-org/matrix-react-sdk/pull/8471)).
+ * Add the option to disable hardware acceleration ([\#8655](https://github.com/matrix-org/matrix-react-sdk/pull/8655)). Contributed by @novocaine.
+ * Slightly better presentation of read receipts to screen reader users ([\#8662](https://github.com/matrix-org/matrix-react-sdk/pull/8662)). Fixes vector-im/element-web#22293. Contributed by @pvagner.
+ * Add jump to related event context menu item ([\#6775](https://github.com/matrix-org/matrix-react-sdk/pull/6775)). Fixes vector-im/element-web#19883.
+ * Add public room directory hook ([\#8626](https://github.com/matrix-org/matrix-react-sdk/pull/8626)).
+
+## 🐛 Bug Fixes
+ * Remove inline margin from UTD error message inside a reply tile on ThreadView ([\#8708](https://github.com/matrix-org/matrix-react-sdk/pull/8708)). Fixes vector-im/element-web#22376. Contributed by @luixxiul.
+ * Move unread notification dots of the threads list to the expected position ([\#8700](https://github.com/matrix-org/matrix-react-sdk/pull/8700)). Fixes vector-im/element-web#22350. Contributed by @luixxiul.
+ * Prevent overflow of grid items on a bubble with UTD generally ([\#8697](https://github.com/matrix-org/matrix-react-sdk/pull/8697)). Contributed by @luixxiul.
+ * Create 'Unable To Decrypt' grid layout for hidden events on a bubble layout ([\#8704](https://github.com/matrix-org/matrix-react-sdk/pull/8704)). Fixes vector-im/element-web#22365. Contributed by @luixxiul.
+ * Fix - AccessibleButton does not set disabled attribute ([\#8682](https://github.com/matrix-org/matrix-react-sdk/pull/8682)). Contributed by @kerryarchibald.
+ * Fix font not resetting when logging out ([\#8670](https://github.com/matrix-org/matrix-react-sdk/pull/8670)). Fixes vector-im/element-web#17228.
+ * Fix local aliases section of room settings not working for some homeservers (ie ([\#8698](https://github.com/matrix-org/matrix-react-sdk/pull/8698)). Fixes vector-im/element-web#22337.
+ * Align EventTile_line with display name on message bubble ([\#8692](https://github.com/matrix-org/matrix-react-sdk/pull/8692)). Fixes vector-im/element-web#22343. Contributed by @luixxiul.
+ * Convert references to direct chat -> direct message ([\#8694](https://github.com/matrix-org/matrix-react-sdk/pull/8694)). Contributed by @novocaine.
+ * Improve combining diacritics for U+20D0 to U+20F0 in Chrome ([\#8687](https://github.com/matrix-org/matrix-react-sdk/pull/8687)).
+ * Make the empty thread panel fill BaseCard ([\#8690](https://github.com/matrix-org/matrix-react-sdk/pull/8690)). Fixes vector-im/element-web#22338. Contributed by @luixxiul.
+ * Fix edge case around composer handling gendered facepalm emoji ([\#8686](https://github.com/matrix-org/matrix-react-sdk/pull/8686)).
+ * Fix a grid blowout due to nowrap displayName on a bubble with UTD ([\#8688](https://github.com/matrix-org/matrix-react-sdk/pull/8688)). Fixes vector-im/element-web#21914. Contributed by @luixxiul.
+ * Apply the same max-width to image tile on the thread timeline as message bubble ([\#8669](https://github.com/matrix-org/matrix-react-sdk/pull/8669)). Fixes vector-im/element-web#22313. Contributed by @luixxiul.
+ * Fix dropdown button size for picture-in-picture CallView ([\#8680](https://github.com/matrix-org/matrix-react-sdk/pull/8680)). Fixes vector-im/element-web#22316. Contributed by @luixxiul.
+ * Live location sharing - fix square border for image-less avatar (PSF-1052) ([\#8679](https://github.com/matrix-org/matrix-react-sdk/pull/8679)). Contributed by @kerryarchibald.
+ * Stop connecting to a video room if the widget messaging disappears ([\#8660](https://github.com/matrix-org/matrix-react-sdk/pull/8660)).
+ * Fix file button and audio player overflowing from message bubble ([\#8666](https://github.com/matrix-org/matrix-react-sdk/pull/8666)). Fixes vector-im/element-web#22308. Contributed by @luixxiul.
+ * Don't show broken composer format bar when selection is whitespace ([\#8673](https://github.com/matrix-org/matrix-react-sdk/pull/8673)). Fixes vector-im/element-web#10788.
+ * Fix media upload http 413 handling ([\#8674](https://github.com/matrix-org/matrix-react-sdk/pull/8674)).
+ * Fix emoji picker for editing thread responses ([\#8671](https://github.com/matrix-org/matrix-react-sdk/pull/8671)). Fixes matrix-org/element-web-rageshakes#13129.
+ * Map attribution while sharing live location is now visible ([\#8621](https://github.com/matrix-org/matrix-react-sdk/pull/8621)). Fixes vector-im/element-web#22236. Contributed by @weeman1337.
+ * Fix info tile overlapping the time stamp on TimelineCard ([\#8639](https://github.com/matrix-org/matrix-react-sdk/pull/8639)). Fixes vector-im/element-web#22256. Contributed by @luixxiul.
+ * Fix position of wide images on IRC / modern layout ([\#8667](https://github.com/matrix-org/matrix-react-sdk/pull/8667)). Fixes vector-im/element-web#22309. Contributed by @luixxiul.
+ * Fix other user's displayName being wrapped on the bubble message layout ([\#8456](https://github.com/matrix-org/matrix-react-sdk/pull/8456)). Fixes vector-im/element-web#22004. Contributed by @luixxiul.
+ * Set spacing declarations to elements in mx_EventTile_mediaLine ([\#8665](https://github.com/matrix-org/matrix-react-sdk/pull/8665)). Fixes vector-im/element-web#22307. Contributed by @luixxiul.
+ * Fix wide image overflowing from the thumbnail container ([\#8663](https://github.com/matrix-org/matrix-react-sdk/pull/8663)). Fixes vector-im/element-web#22303. Contributed by @luixxiul.
+ * Fix styles of "Show all" link button on ReactionsRow ([\#8658](https://github.com/matrix-org/matrix-react-sdk/pull/8658)). Fixes vector-im/element-web#22300. Contributed by @luixxiul.
+ * Automatically log in after registration ([\#8654](https://github.com/matrix-org/matrix-react-sdk/pull/8654)). Fixes vector-im/element-web#19305. Contributed by @justjanne.
+ * Fix offline status in window title not working reliably ([\#8656](https://github.com/matrix-org/matrix-react-sdk/pull/8656)).
+ * Align input area with event body's first letter in a thread on IRC/modern layout ([\#8636](https://github.com/matrix-org/matrix-react-sdk/pull/8636)). Fixes vector-im/element-web#22252. Contributed by @luixxiul.
+ * Fix crash on null idp for SSO buttons ([\#8650](https://github.com/matrix-org/matrix-react-sdk/pull/8650)). Contributed by @hughns.
+ * Don't open the regular browser or our context menu on right-clicking the `Options` button in the message action bar ([\#8648](https://github.com/matrix-org/matrix-react-sdk/pull/8648)). Fixes vector-im/element-web#22279.
+ * Show notifications even when Element is focused ([\#8590](https://github.com/matrix-org/matrix-react-sdk/pull/8590)). Contributed by @sumnerevans.
+ * Remove padding from the buttons on edit message composer of a event tile on a thread ([\#8632](https://github.com/matrix-org/matrix-react-sdk/pull/8632)). Contributed by @luixxiul.
+ * ensure metaspace changes correctly notify listeners ([\#8611](https://github.com/matrix-org/matrix-react-sdk/pull/8611)). Fixes vector-im/element-web#21006. Contributed by @justjanne.
+ * Hide image banner on stickers, they have a tooltip already ([\#8641](https://github.com/matrix-org/matrix-react-sdk/pull/8641)). Fixes vector-im/element-web#22244.
+ * Adjust EditMessageComposer style declarations ([\#8631](https://github.com/matrix-org/matrix-react-sdk/pull/8631)). Fixes vector-im/element-web#22231. Contributed by @luixxiul.
+
Changes in [3.45.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.45.0) (2022-05-24)
=====================================================================================================
diff --git a/README.md b/README.md
index 1602476c153..77ff075cd4c 100644
--- a/README.md
+++ b/README.md
@@ -20,17 +20,18 @@ a 'skin'. A skin provides:
* The containing application
* Zero or more 'modules' containing non-UI functionality
-As of Aug 2018, the only skin that exists is [`vector-im/element-web`](https://github.com/vector-im/element-web/); it and
+As of Aug 2018, the only skin that exists is
+[`vector-im/element-web`](https://github.com/vector-im/element-web/); it and
`matrix-org/matrix-react-sdk` should effectively
be considered as a single project (for instance, matrix-react-sdk bugs
are currently filed against vector-im/element-web rather than this project).
Translation Status
-==================
+------------------
[![Translation status](https://translate.element.io/widgets/element-web/-/multi-auto.svg)](https://translate.element.io/engage/element-web/?utm_source=widget)
Developer Guide
-===============
+---------------
Platform Targets:
* Chrome, Firefox and Safari.
@@ -49,21 +50,25 @@ Please follow the Matrix JS/React code style as per:
https://github.com/matrix-org/matrix-react-sdk/blob/master/code_style.md
Code should be committed as follows:
- * All new components: https://github.com/matrix-org/matrix-react-sdk/tree/master/src/components
- * Element-specific components: https://github.com/vector-im/element-web/tree/master/src/components
- * In practice, `matrix-react-sdk` is still evolving so fast that the maintenance
- burden of customising and overriding these components for Element can seriously
- impede development. So right now, there should be very few (if any) customisations for Element.
+ * All new components:
+ https://github.com/matrix-org/matrix-react-sdk/tree/master/src/components
+ * Element-specific components:
+ https://github.com/vector-im/element-web/tree/master/src/components
+ * In practice, `matrix-react-sdk` is still evolving so fast that the
+ maintenance burden of customising and overriding these components for
+ Element can seriously impede development. So right now, there should be
+ very few (if any) customisations for Element.
* CSS: https://github.com/matrix-org/matrix-react-sdk/tree/master/res/css
- * Theme specific CSS & resources: https://github.com/matrix-org/matrix-react-sdk/tree/master/res/themes
+ * Theme specific CSS & resources:
+ https://github.com/matrix-org/matrix-react-sdk/tree/master/res/themes
React components in matrix-react-sdk come in two different flavours:
'structures' and 'views'. Structures are stateful components which handle the
more complicated business logic of the app, delegating their actual presentation
rendering to stateless 'view' components. For instance, the RoomView component
-that orchestrates the act of visualising the contents of a given Matrix chat room
-tracks lots of state for its child components which it passes into them for visual
-rendering via props.
+that orchestrates the act of visualising the contents of a given Matrix chat
+room tracks lots of state for its child components which it passes into them for
+visual rendering via props.
Good separation between the components is maintained by adopting various best
practices that anyone working with the SDK needs to be aware of and uphold:
@@ -80,18 +85,19 @@ practices that anyone working with the SDK needs to be aware of and uphold:
* Per-view CSS is optional - it could choose to inherit all its styling from
the context of the rest of the app, although this is unusual for any but
- * Theme specific CSS & resources: https://github.com/matrix-org/matrix-react-sdk/tree/master/res/themes
- structural components (lacking presentation logic) and the simplest view
- components.
+ * Theme specific CSS & resources:
+ https://github.com/matrix-org/matrix-react-sdk/tree/master/res/themes
+ structural components (lacking presentation logic) and the simplest view
+ components.
* The view MUST *only* refer to the CSS rules defined in its own CSS file.
'Stealing' styling information from other components (including parents)
is not cool, as it breaks the independence of the components.
- * CSS classes are named with an app-specific name-spacing prefix to try to avoid
- CSS collisions. The base skin shipped by Matrix.org with the matrix-react-sdk
- uses the naming prefix "mx_". A company called Yoyodyne Inc might use a
- prefix like "yy_" for its app-specific classes.
+ * CSS classes are named with an app-specific name-spacing prefix to try to
+ avoid CSS collisions. The base skin shipped by Matrix.org with the
+ matrix-react-sdk uses the naming prefix "mx_". A company called Yoyodyne
+ Inc might use a prefix like "yy_" for its app-specific classes.
* CSS classes use upper camel case when they describe React components - e.g.
.mx_MessageTile is the selector for the CSS applied to a MessageTile view.
@@ -128,13 +134,13 @@ the distinction between 'structural' and 'view' components, so we backed away
from it.
Github Issues
-=============
+-------------
All issues should be filed under https://github.com/vector-im/element-web/issues
for now.
Development
-===========
+-----------
Ensure you have the latest LTS version of Node.js installed.
@@ -143,9 +149,10 @@ guide](https://classic.yarnpkg.com/docs/install) if you do not have it
already. This project has not yet been migrated to Yarn 2, so please ensure
`yarn --version` shows a version from the 1.x series.
-`matrix-react-sdk` depends on [`matrix-js-sdk`](https://github.com/matrix-org/matrix-js-sdk). To make use of changes in the
-latter and to ensure tests run against the develop branch of `matrix-js-sdk`,
-you should set up `matrix-js-sdk`:
+`matrix-react-sdk` depends on
+[`matrix-js-sdk`](https://github.com/matrix-org/matrix-js-sdk). To make use of
+changes in the latter and to ensure tests run against the develop branch of
+`matrix-js-sdk`, you should set up `matrix-js-sdk`:
```bash
git clone https://github.com/matrix-org/matrix-js-sdk
@@ -168,8 +175,7 @@ yarn install
See the [help for `yarn link`](https://classic.yarnpkg.com/docs/cli/link) for
more details about this.
-Running tests
-=============
+### Running tests
Ensure you've followed the above development instructions and then:
@@ -177,7 +183,32 @@ Ensure you've followed the above development instructions and then:
yarn test
```
-## End-to-End tests
+### Running lint
-Make sure you've got your Element development server running (by doing `yarn start` in element-web), and then in this project, run `yarn run e2etests`.
-See [`test/end-to-end-tests/README.md`](https://github.com/matrix-org/matrix-react-sdk/blob/develop/test/end-to-end-tests/README.md) for more information.
+To check your code complies with the project style, ensure you've followed the
+above development instructions and then:
+
+```bash
+yarn lint
+```
+
+### Dependency problems
+
+If you see errors (particularly "Cannot find module") running the lint or test
+commands, and `yarn install` doesn't fix them, it may be because
+yarn is not fetching git dependencies eagerly enough.
+
+Try running this:
+
+```bash
+yarn cache clean && yarn install --force
+```
+
+Now the yarn commands should work as normal.
+
+### End-to-End tests
+
+Make sure you've got your Element development server running (by doing `yarn
+start` in element-web), and then in this project, run `yarn run e2etests`. See
+[`test/end-to-end-tests/README.md`](https://github.com/matrix-org/matrix-react-sdk/blob/develop/test/end-to-end-tests/README.md)
+for more information.
diff --git a/cypress/fixtures/riot.png b/cypress/fixtures/riot.png
new file mode 100644
index 00000000000..ee42954c782
Binary files /dev/null and b/cypress/fixtures/riot.png differ
diff --git a/cypress/global.d.ts b/cypress/global.d.ts
index efbb255b081..a3e91a2b44c 100644
--- a/cypress/global.d.ts
+++ b/cypress/global.d.ts
@@ -16,7 +16,9 @@ limitations under the License.
import "matrix-js-sdk/src/@types/global";
import type { MatrixClient, ClientEvent } from "matrix-js-sdk/src/client";
+import type { MatrixScheduler, MemoryCryptoStore, MemoryStore, RoomStateEvent } from "matrix-js-sdk/src/matrix";
import type { RoomMemberEvent } from "matrix-js-sdk/src/models/room-member";
+import type { WebStorageSessionStore } from "matrix-js-sdk/src/store/session/webstorage";
import type { MatrixDispatcher } from "../src/dispatcher/dispatcher";
import type PerformanceMonitor from "../src/performance";
@@ -35,6 +37,11 @@ declare global {
MatrixClient: typeof MatrixClient;
ClientEvent: typeof ClientEvent;
RoomMemberEvent: typeof RoomMemberEvent;
+ RoomStateEvent: typeof RoomStateEvent;
+ MatrixScheduler: typeof MatrixScheduler;
+ MemoryStore: typeof MemoryStore;
+ MemoryCryptoStore: typeof MemoryCryptoStore;
+ WebStorageSessionStore: typeof WebStorageSessionStore;
};
}
}
diff --git a/cypress/integration/2-login/login.spec.ts b/cypress/integration/2-login/login.spec.ts
index 521eb66f25a..85d2866e498 100644
--- a/cypress/integration/2-login/login.spec.ts
+++ b/cypress/integration/2-login/login.spec.ts
@@ -59,4 +59,45 @@ describe("Login", () => {
cy.stopMeasuring("from-submit-to-home");
});
});
+
+ describe("logout", () => {
+ beforeEach(() => {
+ cy.initTestUser(synapse, "Erin");
+ });
+
+ it("should go to login page on logout", () => {
+ cy.get('[aria-label="User menu"]').click();
+
+ // give a change for the outstanding requests queue to settle before logging out
+ cy.wait(500);
+
+ cy.get(".mx_UserMenu_contextMenu").within(() => {
+ cy.get(".mx_UserMenu_iconSignOut").click();
+ });
+
+ cy.url().should("contain", "/#/login");
+ });
+
+ it("should respect logout_redirect_url", () => {
+ cy.tweakConfig({
+ // We redirect to decoder-ring because it's a predictable page that isn't Element itself.
+ // We could use example.org, matrix.org, or something else, however this puts dependency of external
+ // infrastructure on our tests. In the same vein, we don't really want to figure out how to ship a
+ // `test-landing.html` page when running with an uncontrolled Element (via `yarn start`).
+ // Using the decoder-ring is just as fine, and we can search for strategic names.
+ logout_redirect_url: "/decoder-ring/",
+ });
+
+ cy.get('[aria-label="User menu"]').click();
+
+ // give a change for the outstanding requests queue to settle before logging out
+ cy.wait(500);
+
+ cy.get(".mx_UserMenu_contextMenu").within(() => {
+ cy.get(".mx_UserMenu_iconSignOut").click();
+ });
+
+ cy.url().should("contains", "decoder-ring");
+ });
+ });
});
diff --git a/cypress/integration/3-user-menu/user-menu.spec.ts b/cypress/integration/3-user-menu/user-menu.spec.ts
index 671fd4eacf3..40b4a0cd74c 100644
--- a/cypress/integration/3-user-menu/user-menu.spec.ts
+++ b/cypress/integration/3-user-menu/user-menu.spec.ts
@@ -39,7 +39,7 @@ describe("User Menu", () => {
it("should contain our name & userId", () => {
cy.get('[aria-label="User menu"]').click();
- cy.get(".mx_ContextualMenu").within(() => {
+ cy.get(".mx_UserMenu_contextMenu").within(() => {
cy.get(".mx_UserMenu_contextMenu_displayName").should("contain", "Jeff");
cy.get(".mx_UserMenu_contextMenu_userId").should("contain", user.userId);
});
diff --git a/cypress/integration/5-threads/threads.spec.ts b/cypress/integration/5-threads/threads.spec.ts
index 43b0058bb11..226e63576d8 100644
--- a/cypress/integration/5-threads/threads.spec.ts
+++ b/cypress/integration/5-threads/threads.spec.ts
@@ -87,8 +87,8 @@ describe("Threads", () => {
cy.get(".mx_RoomView_body .mx_BasicMessageComposer_input").type("Hello Mr. Bot{enter}");
// Wait for message to send, get its ID and save as @threadId
- cy.get(".mx_RoomView_body .mx_EventTile").contains("Hello Mr. Bot")
- .closest(".mx_EventTile[data-scroll-tokens]").invoke("attr", "data-scroll-tokens").as("threadId");
+ cy.get(".mx_RoomView_body .mx_EventTile").contains(".mx_EventTile[data-scroll-tokens]", "Hello Mr. Bot")
+ .invoke("attr", "data-scroll-tokens").as("threadId");
// Bot starts thread
cy.get("@threadId").then(threadId => {
@@ -111,7 +111,7 @@ describe("Threads", () => {
cy.get(".mx_RoomView_body .mx_ThreadSummary .mx_ThreadSummary_content").should("contain", "Test");
// User reacts to message instead
- cy.get(".mx_ThreadView .mx_EventTile").contains("Hello there").closest(".mx_EventTile_line")
+ cy.get(".mx_ThreadView .mx_EventTile").contains(".mx_EventTile_line", "Hello there")
.find('[aria-label="React"]').click({ force: true }); // Cypress has no ability to hover
cy.get(".mx_EmojiPicker").within(() => {
cy.get('input[type="text"]').type("wave");
@@ -119,7 +119,7 @@ describe("Threads", () => {
});
// User redacts their prior response
- cy.get(".mx_ThreadView .mx_EventTile").contains("Test").closest(".mx_EventTile_line")
+ cy.get(".mx_ThreadView .mx_EventTile").contains(".mx_EventTile_line", "Test")
.find('[aria-label="Options"]').click({ force: true }); // Cypress has no ability to hover
cy.get(".mx_IconizedContextMenu").within(() => {
cy.get('[role="menuitem"]').contains("Remove").click();
@@ -166,7 +166,7 @@ describe("Threads", () => {
cy.get(".mx_RoomView_body .mx_ThreadSummary .mx_ThreadSummary_content").should("contain", "Great!");
// User edits & asserts
- cy.get(".mx_ThreadView .mx_EventTile_last").contains("Great!").closest(".mx_EventTile_line").within(() => {
+ cy.get(".mx_ThreadView .mx_EventTile_last").contains(".mx_EventTile_line", "Great!").within(() => {
cy.get('[aria-label="Edit"]').click({ force: true }); // Cypress has no ability to hover
cy.get(".mx_BasicMessageComposer_input").type(" How about yourself?{enter}");
});
diff --git a/cypress/integration/6-spaces/spaces.spec.ts b/cypress/integration/6-spaces/spaces.spec.ts
new file mode 100644
index 00000000000..e5c03229bf2
--- /dev/null
+++ b/cypress/integration/6-spaces/spaces.spec.ts
@@ -0,0 +1,244 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+///
+
+import type { MatrixClient } from "matrix-js-sdk/src/client";
+import type { ICreateRoomOpts } from "matrix-js-sdk/src/@types/requests";
+import { SynapseInstance } from "../../plugins/synapsedocker";
+import Chainable = Cypress.Chainable;
+import { UserCredentials } from "../../support/login";
+
+function openSpaceCreateMenu(): Chainable {
+ cy.get(".mx_SpaceButton_new").click();
+ return cy.get(".mx_SpaceCreateMenu_wrapper .mx_ContextualMenu");
+}
+
+function getSpacePanelButton(spaceName: string): Chainable {
+ return cy.get(`.mx_SpaceButton[aria-label="${spaceName}"]`);
+}
+
+function openSpaceContextMenu(spaceName: string): Chainable {
+ getSpacePanelButton(spaceName).rightclick();
+ return cy.get(".mx_SpacePanel_contextMenu");
+}
+
+function spaceCreateOptions(spaceName: string): ICreateRoomOpts {
+ return {
+ creation_content: {
+ type: "m.space",
+ },
+ initial_state: [{
+ type: "m.room.name",
+ content: {
+ name: spaceName,
+ },
+ }],
+ };
+}
+
+function spaceChildInitialState(roomId: string): ICreateRoomOpts["initial_state"]["0"] {
+ return {
+ type: "m.space.child",
+ state_key: roomId,
+ content: {
+ via: [roomId.split(":")[1]],
+ },
+ };
+}
+
+describe("Spaces", () => {
+ let synapse: SynapseInstance;
+ let user: UserCredentials;
+
+ beforeEach(() => {
+ cy.startSynapse("default").then(data => {
+ synapse = data;
+
+ cy.initTestUser(synapse, "Sue").then(_user => {
+ user = _user;
+ cy.mockClipboard();
+ });
+ });
+ });
+
+ afterEach(() => {
+ cy.stopSynapse(synapse);
+ });
+
+ it("should allow user to create public space", () => {
+ openSpaceCreateMenu().within(() => {
+ cy.get(".mx_SpaceCreateMenuType_public").click();
+ cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]')
+ .selectFile("cypress/fixtures/riot.png", { force: true });
+ cy.get('input[label="Name"]').type("Let's have a Riot");
+ cy.get('input[label="Address"]').should("have.value", "lets-have-a-riot");
+ cy.get('textarea[label="Description"]').type("This is a space to reminisce Riot.im!");
+ cy.get(".mx_AccessibleButton").contains("Create").click();
+ });
+
+ // Create the default General & Random rooms, as well as a custom "Jokes" room
+ cy.get('input[label="Room name"][value="General"]').should("exist");
+ cy.get('input[label="Room name"][value="Random"]').should("exist");
+ cy.get('input[placeholder="Support"]').type("Jokes");
+ cy.get(".mx_AccessibleButton").contains("Continue").click();
+
+ // Copy matrix.to link
+ cy.get(".mx_SpacePublicShare_shareButton").focus().realClick();
+ cy.getClipboardText().should("eq", "https://matrix.to/#/#lets-have-a-riot:localhost");
+
+ // Go to space home
+ cy.get(".mx_AccessibleButton").contains("Go to my first room").click();
+
+ // Assert rooms exist in the room list
+ cy.get(".mx_RoomTile").contains("General").should("exist");
+ cy.get(".mx_RoomTile").contains("Random").should("exist");
+ cy.get(".mx_RoomTile").contains("Jokes").should("exist");
+ });
+
+ it("should allow user to create private space", () => {
+ openSpaceCreateMenu().within(() => {
+ cy.get(".mx_SpaceCreateMenuType_private").click();
+ cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]')
+ .selectFile("cypress/fixtures/riot.png", { force: true });
+ cy.get('input[label="Name"]').type("This is not a Riot");
+ cy.get('input[label="Address"]').should("not.exist");
+ cy.get('textarea[label="Description"]').type("This is a private space of mourning Riot.im...");
+ cy.get(".mx_AccessibleButton").contains("Create").click();
+ });
+
+ cy.get(".mx_SpaceRoomView_privateScope_meAndMyTeammatesButton").click();
+
+ // Create the default General & Random rooms, as well as a custom "Projects" room
+ cy.get('input[label="Room name"][value="General"]').should("exist");
+ cy.get('input[label="Room name"][value="Random"]').should("exist");
+ cy.get('input[placeholder="Support"]').type("Projects");
+ cy.get(".mx_AccessibleButton").contains("Continue").click();
+
+ cy.get(".mx_SpaceRoomView").should("contain", "Invite your teammates");
+ cy.get(".mx_AccessibleButton").contains("Skip for now").click();
+
+ // Assert rooms exist in the room list
+ cy.get(".mx_RoomTile").contains("General").should("exist");
+ cy.get(".mx_RoomTile").contains("Random").should("exist");
+ cy.get(".mx_RoomTile").contains("Projects").should("exist");
+
+ // Assert rooms exist in the space explorer
+ cy.get(".mx_SpaceHierarchy_roomTile").contains("General").should("exist");
+ cy.get(".mx_SpaceHierarchy_roomTile").contains("Random").should("exist");
+ cy.get(".mx_SpaceHierarchy_roomTile").contains("Projects").should("exist");
+ });
+
+ it("should allow user to create just-me space", () => {
+ cy.createRoom({
+ name: "Sample Room",
+ });
+
+ openSpaceCreateMenu().within(() => {
+ cy.get(".mx_SpaceCreateMenuType_private").click();
+ cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]')
+ .selectFile("cypress/fixtures/riot.png", { force: true });
+ cy.get('input[label="Address"]').should("not.exist");
+ cy.get('textarea[label="Description"]').type("This is a personal space to mourn Riot.im...");
+ cy.get('input[label="Name"]').type("This is my Riot{enter}");
+ });
+
+ cy.get(".mx_SpaceRoomView_privateScope_justMeButton").click();
+
+ cy.get(".mx_AddExistingToSpace_entry").click();
+ cy.get(".mx_AccessibleButton").contains("Add").click();
+
+ cy.get(".mx_RoomTile").contains("Sample Room").should("exist");
+ cy.get(".mx_SpaceHierarchy_roomTile").contains("Sample Room").should("exist");
+ });
+
+ it("should allow user to invite another to a space", () => {
+ let bot: MatrixClient;
+ cy.getBot(synapse, "BotBob").then(_bot => {
+ bot = _bot;
+ });
+
+ cy.createSpace({
+ visibility: "public" as any,
+ room_alias_name: "space",
+ }).as("spaceId");
+
+ openSpaceContextMenu("#space:localhost").within(() => {
+ cy.get('.mx_SpacePanel_contextMenu_inviteButton[aria-label="Invite"]').click();
+ });
+
+ cy.get(".mx_SpacePublicShare").within(() => {
+ // Copy link first
+ cy.get(".mx_SpacePublicShare_shareButton").focus().realClick();
+ cy.getClipboardText().should("eq", "https://matrix.to/#/#space:localhost");
+ // Start Matrix invite flow
+ cy.get(".mx_SpacePublicShare_inviteButton").click();
+ });
+
+ cy.get(".mx_InviteDialog_other").within(() => {
+ cy.get('input[type="text"]').type(bot.getUserId());
+ cy.get(".mx_AccessibleButton").contains("Invite").click();
+ });
+
+ cy.get(".mx_InviteDialog_other").should("not.exist");
+ });
+
+ it("should show space invites at the top of the space panel", () => {
+ cy.createSpace({
+ name: "My Space",
+ });
+ getSpacePanelButton("My Space").should("exist");
+
+ cy.getBot(synapse, "BotBob").then({ timeout: 10000 }, async bot => {
+ const { room_id: roomId } = await bot.createRoom(spaceCreateOptions("Space Space"));
+ await bot.invite(roomId, user.userId);
+ });
+ // Assert that `Space Space` is above `My Space` due to it being an invite
+ getSpacePanelButton("Space Space").should("exist")
+ .parent().next().find('.mx_SpaceButton[aria-label="My Space"]').should("exist");
+ });
+
+ it("should include rooms in space home", () => {
+ cy.createRoom({
+ name: "Music",
+ }).as("roomId1");
+ cy.createRoom({
+ name: "Gaming",
+ }).as("roomId2");
+
+ const spaceName = "Spacey Mc. Space Space";
+ cy.all([
+ cy.get("@roomId1"),
+ cy.get("@roomId2"),
+ ]).then(([roomId1, roomId2]) => {
+ cy.createSpace({
+ name: spaceName,
+ initial_state: [
+ spaceChildInitialState(roomId1),
+ spaceChildInitialState(roomId2),
+ ],
+ }).as("spaceId");
+ });
+
+ cy.get("@spaceId").then(() => {
+ getSpacePanelButton(spaceName).dblclick(); // Open space home
+ });
+ cy.get(".mx_SpaceRoomView .mx_SpaceHierarchy_list").within(() => {
+ cy.get(".mx_SpaceHierarchy_roomTile").contains("Music").should("exist");
+ cy.get(".mx_SpaceHierarchy_roomTile").contains("Gaming").should("exist");
+ });
+ });
+});
diff --git a/cypress/integration/7-crypto/crypto.spec.ts b/cypress/integration/7-crypto/crypto.spec.ts
new file mode 100644
index 00000000000..2446e3bd2bb
--- /dev/null
+++ b/cypress/integration/7-crypto/crypto.spec.ts
@@ -0,0 +1,82 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+///
+
+import type { MatrixClient } from "matrix-js-sdk/src/matrix";
+import { SynapseInstance } from "../../plugins/synapsedocker";
+
+function waitForEncryption(cli: MatrixClient, roomId: string, win: Cypress.AUTWindow, resolve: () => void) {
+ cli.crypto.cryptoStore.getEndToEndRooms(null, (result) => {
+ if (result[roomId]) {
+ resolve();
+ } else {
+ cli.once(win.matrixcs.RoomStateEvent.Update, () => waitForEncryption(cli, roomId, win, resolve));
+ }
+ });
+}
+
+describe("Cryptography", () => {
+ beforeEach(() => {
+ cy.startSynapse("default").as('synapse').then(
+ synapse => cy.initTestUser(synapse, "Alice"),
+ );
+ });
+
+ afterEach(() => {
+ cy.get('@synapse').then(synapse => cy.stopSynapse(synapse));
+ });
+
+ it("should receive and decrypt encrypted messages", () => {
+ cy.get('@synapse').then(synapse => cy.getBot(synapse, "Beatrice").as('bot'));
+
+ cy.createRoom({
+ initial_state: [
+ {
+ type: "m.room.encryption",
+ state_key: '',
+ content: {
+ algorithm: "m.megolm.v1.aes-sha2",
+ },
+ },
+ ],
+ }).as('roomId');
+
+ cy.all([
+ cy.get('@bot'),
+ cy.get('@roomId'),
+ cy.window(),
+ ]).then(([bot, roomId, win]) => {
+ cy.inviteUser(roomId, bot.getUserId());
+ cy.visit("/#/room/" + roomId);
+ cy.wrap(
+ new Promise(resolve =>
+ waitForEncryption(bot, roomId, win, resolve),
+ ).then(() => bot.sendMessage(roomId, {
+ body: "Top secret message",
+ msgtype: "m.text",
+ })),
+ );
+ });
+
+ cy.get(".mx_RoomView_body .mx_cryptoEvent").should("contain", "Encryption enabled");
+
+ cy.get(".mx_EventTile_body")
+ .contains("Top secret message")
+ .closest(".mx_EventTile_line")
+ .should("not.have.descendants", ".mx_EventTile_e2eIcon_warning");
+ });
+});
diff --git a/cypress/integration/8-update/update.spec.ts b/cypress/integration/8-update/update.spec.ts
new file mode 100644
index 00000000000..75977763cc9
--- /dev/null
+++ b/cypress/integration/8-update/update.spec.ts
@@ -0,0 +1,53 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+///
+
+import { SynapseInstance } from "../../plugins/synapsedocker";
+
+describe("Update", () => {
+ let synapse: SynapseInstance;
+
+ beforeEach(() => {
+ cy.startSynapse("default").then(data => {
+ synapse = data;
+ });
+ });
+
+ afterEach(() => {
+ cy.stopSynapse(synapse);
+ });
+
+ it("should navigate to ?updated=$VERSION if realises it is immediately out of date on load", () => {
+ const NEW_VERSION = "some-new-version";
+
+ cy.intercept("/version*", {
+ statusCode: 200,
+ body: NEW_VERSION,
+ headers: {
+ "Content-Type": "test/plain",
+ },
+ }).as("version");
+
+ cy.initTestUser(synapse, "Ursa");
+
+ cy.wait("@version");
+ cy.url().should("contain", "updated=" + NEW_VERSION).then(href => {
+ const url = new URL(href);
+ expect(url.searchParams.get("updated")).to.equal(NEW_VERSION);
+ });
+ });
+});
diff --git a/cypress/plugins/synapsedocker/index.ts b/cypress/plugins/synapsedocker/index.ts
index 292c74ee670..7108ade904a 100644
--- a/cypress/plugins/synapsedocker/index.ts
+++ b/cypress/plugins/synapsedocker/index.ts
@@ -66,9 +66,6 @@ async function cfgDirFromTemplate(template: string): Promise {
}
const tempDir = await fse.mkdtemp(path.join(os.tmpdir(), 'react-sdk-synapsedocker-'));
- // change permissions on the temp directory so the docker container can see its contents
- await fse.chmod(tempDir, 0o777);
-
// copy the contents of the template dir, omitting homeserver.yaml as we'll template that
console.log(`Copy ${templateDir} -> ${tempDir}`);
await fse.copy(templateDir, tempDir, { filter: f => path.basename(f) !== 'homeserver.yaml' });
@@ -113,6 +110,7 @@ async function synapseStart(template: string): Promise {
console.log(`Starting synapse with config dir ${synCfg.configDir}...`);
const containerName = `react-sdk-cypress-synapse-${crypto.randomBytes(4).toString("hex")}`;
+ const userInfo = os.userInfo();
const synapseId = await new Promise((resolve, reject) => {
childProcess.execFile('docker', [
@@ -121,6 +119,8 @@ async function synapseStart(template: string): Promise {
"-d",
"-v", `${synCfg.configDir}:/data`,
"-p", `${synCfg.port}:8008/tcp`,
+ // We run the docker container as our uid:gid otherwise cleaning it up its media_store can be difficult
+ "-u", `${userInfo.uid}:${userInfo.gid}`,
"matrixdotorg/synapse:develop",
"run",
], (err, stdout) => {
@@ -129,8 +129,6 @@ async function synapseStart(template: string): Promise {
});
});
- synapses.set(synapseId, { synapseId, ...synCfg });
-
console.log(`Started synapse with id ${synapseId} on port ${synCfg.port}.`);
// Await Synapse healthcheck
@@ -150,7 +148,9 @@ async function synapseStart(template: string): Promise {
});
});
- return synapses.get(synapseId);
+ const synapse: SynapseInstance = { synapseId, ...synCfg };
+ synapses.set(synapseId, synapse);
+ return synapse;
}
async function synapseStop(id: string): Promise {
diff --git a/cypress/support/app.ts b/cypress/support/app.ts
new file mode 100644
index 00000000000..21321e2b56f
--- /dev/null
+++ b/cypress/support/app.ts
@@ -0,0 +1,43 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+///
+
+import "./client"; // XXX: without an (any) import here, types break down
+import Chainable = Cypress.Chainable;
+import AUTWindow = Cypress.AUTWindow;
+
+declare global {
+ // eslint-disable-next-line @typescript-eslint/no-namespace
+ namespace Cypress {
+ interface Chainable {
+ /**
+ * Applies tweaks to the config read from config.json
+ */
+ tweakConfig(tweaks: Record): Chainable;
+ }
+ }
+}
+
+Cypress.Commands.add("tweakConfig", (tweaks: Record): Chainable => {
+ return cy.window().then(win => {
+ // note: we can't *set* the object because the window version is effectively a pointer.
+ for (const [k, v] of Object.entries(tweaks)) {
+ // @ts-ignore - for some reason it's not picking up on global.d.ts types.
+ win.mxReactSdkConfig[k] = v;
+ }
+ });
+});
diff --git a/cypress/support/bot.ts b/cypress/support/bot.ts
index a2488c0081e..e3bdf49d312 100644
--- a/cypress/support/bot.ts
+++ b/cypress/support/bot.ts
@@ -20,6 +20,7 @@ import request from "browser-request";
import type { MatrixClient } from "matrix-js-sdk/src/client";
import { SynapseInstance } from "../plugins/synapsedocker";
+import { MockStorage } from "./storage";
import Chainable = Cypress.Chainable;
declare global {
@@ -47,6 +48,10 @@ Cypress.Commands.add("getBot", (synapse: SynapseInstance, displayName?: string):
deviceId: credentials.deviceId,
accessToken: credentials.accessToken,
request,
+ store: new win.matrixcs.MemoryStore(),
+ scheduler: new win.matrixcs.MatrixScheduler(),
+ cryptoStore: new win.matrixcs.MemoryCryptoStore(),
+ sessionStore: new win.matrixcs.WebStorageSessionStore(new MockStorage()),
});
cli.on(win.matrixcs.RoomMemberEvent.Membership, (event, member) => {
@@ -55,9 +60,12 @@ Cypress.Commands.add("getBot", (synapse: SynapseInstance, displayName?: string):
}
});
- cli.startClient();
-
- return cli;
+ return cy.wrap(
+ cli.initCrypto()
+ .then(() => cli.setGlobalErrorOnUnknownDevices(false))
+ .then(() => cli.startClient())
+ .then(() => cli),
+ );
});
});
});
diff --git a/cypress/support/client.ts b/cypress/support/client.ts
index 682f3ee426c..6a6a3932711 100644
--- a/cypress/support/client.ts
+++ b/cypress/support/client.ts
@@ -35,6 +35,12 @@ declare global {
* @return the ID of the newly created room
*/
createRoom(options: ICreateRoomOpts): Chainable;
+ /**
+ * Create a space with given options.
+ * @param options the options to apply when creating the space
+ * @return the ID of the newly created space (room)
+ */
+ createSpace(options: ICreateRoomOpts): Chainable;
/**
* Invites the given user to the given room.
* @param roomId the id of the room to invite to
@@ -71,6 +77,15 @@ Cypress.Commands.add("createRoom", (options: ICreateRoomOpts): Chainable
});
});
+Cypress.Commands.add("createSpace", (options: ICreateRoomOpts): Chainable => {
+ return cy.createRoom({
+ ...options,
+ creation_content: {
+ "type": "m.space",
+ },
+ });
+});
+
Cypress.Commands.add("inviteUser", (roomId: string, userId: string): Chainable<{}> => {
return cy.getClient().then(async (cli: MatrixClient) => {
return cli.invite(roomId, userId);
diff --git a/cypress/support/clipboard.ts b/cypress/support/clipboard.ts
new file mode 100644
index 00000000000..5e80ed8361d
--- /dev/null
+++ b/cypress/support/clipboard.ts
@@ -0,0 +1,57 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+///
+
+import Chainable = Cypress.Chainable;
+
+// Mock the clipboard, as only Electron gives the app permission to the clipboard API by default
+// Virtual clipboard
+let copyText: string;
+
+declare global {
+ // eslint-disable-next-line @typescript-eslint/no-namespace
+ namespace Cypress {
+ interface Chainable {
+ /**
+ * Mock the clipboard on the current window, ready for calling `getClipboardText`.
+ * Irreversible, refresh the window to restore mock.
+ */
+ mockClipboard(): Chainable;
+ /**
+ * Read text from the mocked clipboard.
+ * @return {string} the clipboard text
+ */
+ getClipboardText(): Chainable;
+ }
+ }
+}
+
+Cypress.Commands.add("mockClipboard", () => {
+ cy.window({ log: false }).then(win => {
+ win.navigator.clipboard.writeText = (text) => {
+ copyText = text;
+ return Promise.resolve();
+ };
+ });
+});
+
+Cypress.Commands.add("getClipboardText", (): Chainable => {
+ return cy.wrap(copyText);
+});
+
+// Needed to make this file a module
+export { };
diff --git a/cypress/support/index.ts b/cypress/support/index.ts
index dd8e5cab991..06d6efc252b 100644
--- a/cypress/support/index.ts
+++ b/cypress/support/index.ts
@@ -17,6 +17,7 @@ limitations under the License.
///
import "@percy/cypress";
+import "cypress-real-events";
import "./performance";
import "./synapse";
@@ -24,3 +25,6 @@ import "./login";
import "./client";
import "./settings";
import "./bot";
+import "./clipboard";
+import "./util";
+import "./app";
diff --git a/cypress/support/settings.ts b/cypress/support/settings.ts
index 11f48c2db26..4be44e27117 100644
--- a/cypress/support/settings.ts
+++ b/cypress/support/settings.ts
@@ -16,7 +16,6 @@ limitations under the License.
///
-import "./client"; // XXX: without an (any) import here, types break down
import Chainable = Cypress.Chainable;
declare global {
@@ -99,3 +98,6 @@ Cypress.Commands.add("leaveBeta", (name: string): Chainable>
return cy.get(".mx_BetaCard_buttons").contains("Leave the beta").click();
});
});
+
+// Needed to make this file a module
+export { };
diff --git a/cypress/support/storage.ts b/cypress/support/storage.ts
new file mode 100644
index 00000000000..d93e1188351
--- /dev/null
+++ b/cypress/support/storage.ts
@@ -0,0 +1,58 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+export class MockStorage implements Storage {
+ private data: Record = {};
+ private keys: string[] = [];
+ public length = 0;
+
+ constructor() {}
+
+ public setItem(k: string, v: string) {
+ this.data[k] = v;
+ this.recalc();
+ }
+
+ public getItem(k: string): string | null {
+ return this.data[k] || null;
+ }
+
+ public removeItem(k: string) {
+ delete this.data[k];
+ this.recalc();
+ }
+
+ public clear() {
+ this.data = {};
+ this.recalc();
+ }
+
+ public key(index: number): string {
+ return this.keys[index];
+ }
+
+ private recalc() {
+ const keys = [];
+ for (const k in this.data) {
+ if (!this.data.hasOwnProperty(k)) {
+ continue;
+ }
+ keys.push(k);
+ }
+ this.keys = keys;
+ this.length = keys.length;
+ }
+}
diff --git a/cypress/support/util.ts b/cypress/support/util.ts
new file mode 100644
index 00000000000..e8f48b4bcc1
--- /dev/null
+++ b/cypress/support/util.ts
@@ -0,0 +1,82 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+///
+
+// @see https://github.com/cypress-io/cypress/issues/915#issuecomment-475862672
+// Modified due to changes to `cy.queue` https://github.com/cypress-io/cypress/pull/17448
+// Note: this DOES NOT run Promises in parallel like `Promise.all` due to the nature
+// of Cypress promise-like objects and command queue. This only makes it convenient to use the same
+// API but runs the commands sequentially.
+
+declare global {
+ // eslint-disable-next-line @typescript-eslint/no-namespace
+ namespace Cypress {
+ type ChainableValue = T extends Cypress.Chainable ? V : T;
+
+ interface cy {
+ all(
+ commands: T
+ ): Cypress.Chainable<{ [P in keyof T]: ChainableValue }>;
+ queue: any;
+ }
+
+ interface Chainable {
+ chainerId: string;
+ }
+ }
+}
+
+const chainStart = Symbol("chainStart");
+
+/**
+ * @description Returns a single Chainable that resolves when all of the Chainables pass.
+ * @param {Cypress.Chainable[]} commands - List of Cypress.Chainable to resolve.
+ * @returns {Cypress.Chainable} Cypress when all Chainables are resolved.
+ */
+cy.all = function all(commands): Cypress.Chainable {
+ const chain = cy.wrap(null, { log: false });
+ const stopCommand = Cypress._.find(cy.queue.get(), {
+ attributes: { chainerId: chain.chainerId },
+ });
+ const startCommand = Cypress._.find(cy.queue.get(), {
+ attributes: { chainerId: commands[0].chainerId },
+ });
+ const p = chain.then(() => {
+ return cy.wrap(
+ // @see https://lodash.com/docs/4.17.15#lodash
+ Cypress._(commands)
+ .map(cmd => {
+ return cmd[chainStart]
+ ? cmd[chainStart].attributes
+ : Cypress._.find(cy.queue.get(), {
+ attributes: { chainerId: cmd.chainerId },
+ }).attributes;
+ })
+ .concat(stopCommand.attributes)
+ .slice(1)
+ .map(cmd => {
+ return cmd.prev.get("subject");
+ })
+ .value(),
+ );
+ });
+ p[chainStart] = startCommand;
+ return p;
+};
+
+// Needed to make this file a module
+export { };
diff --git a/package.json b/package.json
index 2745cf91fef..d092ba88d9b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "matrix-react-sdk",
- "version": "3.45.0",
+ "version": "3.46.0",
"description": "SDK for matrix.org using React",
"author": "matrix.org",
"repository": {
@@ -91,7 +91,7 @@
"matrix-analytics-events": "github:matrix-org/matrix-analytics-events.git#a0687ca6fbdb7258543d49b99fb88b9201e900b0",
"matrix-encrypt-attachment": "^1.0.3",
"matrix-events-sdk": "^0.0.1-beta.7",
- "matrix-js-sdk": "18.0.0",
+ "matrix-js-sdk": "18.1.0",
"matrix-widget-api": "^0.1.0-beta.18",
"minimist": "^1.2.5",
"opus-recorder": "^8.0.3",
@@ -170,6 +170,7 @@
"blob-polyfill": "^6.0.20211015",
"chokidar": "^3.5.1",
"cypress": "^9.6.1",
+ "cypress-real-events": "^1.7.0",
"enzyme": "^3.11.0",
"enzyme-to-json": "^3.6.2",
"eslint": "8.9.0",
@@ -188,7 +189,7 @@
"jest-mock": "^27.5.1",
"jest-raw-loader": "^1.0.1",
"jest-sonar-reporter": "^2.0.0",
- "matrix-mock-request": "^1.2.3",
+ "matrix-mock-request": "^2.0.0",
"matrix-react-test-utils": "^0.2.3",
"matrix-web-i18n": "^1.2.0",
"raw-loader": "^4.0.2",
diff --git a/release.sh b/release.sh
index 4742f00deab..8725c2b6131 100755
--- a/release.sh
+++ b/release.sh
@@ -2,7 +2,7 @@
#
# Script to perform a release of matrix-react-sdk.
#
-# Requires githib-changelog-generator; to install, do
+# Requires githib-changelog-generator; to install, do
# pip install git+https://github.com/matrix-org/github-changelog-generator.git
set -e
@@ -37,7 +37,7 @@ do
fi
done
-./node_modules/matrix-js-sdk/release.sh -z "$@"
+./node_modules/matrix-js-sdk/release.sh "$@"
release="${1#v}"
prerelease=0
diff --git a/res/css/_components.scss b/res/css/_components.scss
index 1b1b87b39d4..5d1a51e0b55 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -14,11 +14,13 @@
@import "./components/views/beacon/_LiveTimeRemaining.scss";
@import "./components/views/beacon/_OwnBeaconStatus.scss";
@import "./components/views/beacon/_RoomLiveShareWarning.scss";
+@import "./components/views/beacon/_ShareLatestLocation.scss";
@import "./components/views/beacon/_StyledLiveBeaconIcon.scss";
@import "./components/views/location/_EnableLiveShare.scss";
@import "./components/views/location/_LiveDurationDropdown.scss";
@import "./components/views/location/_LocationShareMenu.scss";
@import "./components/views/location/_MapError.scss";
+@import "./components/views/location/_MapFallback.scss";
@import "./components/views/location/_Marker.scss";
@import "./components/views/location/_ShareDialogButtons.scss";
@import "./components/views/location/_ShareType.scss";
@@ -133,7 +135,6 @@
@import "./views/dialogs/_UploadConfirmDialog.scss";
@import "./views/dialogs/_UserSettingsDialog.scss";
@import "./views/dialogs/_WidgetCapabilitiesPromptDialog.scss";
-@import "./views/dialogs/_WidgetOpenIDPermissionsDialog.scss";
@import "./views/dialogs/security/_AccessSecretStorageDialog.scss";
@import "./views/dialogs/security/_CreateCrossSigningDialog.scss";
@import "./views/dialogs/security/_CreateKeyBackupDialog.scss";
@@ -161,6 +162,7 @@
@import "./views/elements/_InlineSpinner.scss";
@import "./views/elements/_InteractiveTooltip.scss";
@import "./views/elements/_InviteReason.scss";
+@import "./views/elements/_LabelledCheckbox.scss";
@import "./views/elements/_ManageIntegsButton.scss";
@import "./views/elements/_MiniAvatarUploader.scss";
@import "./views/elements/_Pill.scss";
diff --git a/res/css/components/views/beacon/_BeaconListItem.scss b/res/css/components/views/beacon/_BeaconListItem.scss
index dd99192cf56..00f8bcbe5b6 100644
--- a/res/css/components/views/beacon/_BeaconListItem.scss
+++ b/res/css/components/views/beacon/_BeaconListItem.scss
@@ -36,6 +36,7 @@ limitations under the License.
margin-right: $spacing-8;
border: 2px solid $location-live-color;
+ border-radius: 50%;
}
.mx_BeaconListItem_info {
diff --git a/res/css/components/views/beacon/_BeaconStatusTooltip.scss b/res/css/components/views/beacon/_BeaconStatusTooltip.scss
index 07b3a43cc01..d6ed72e4552 100644
--- a/res/css/components/views/beacon/_BeaconStatusTooltip.scss
+++ b/res/css/components/views/beacon/_BeaconStatusTooltip.scss
@@ -21,11 +21,6 @@ limitations under the License.
height: 38px;
box-sizing: content-box;
padding-top: $spacing-8;
-
- // override copyable text style to make compact
- .mx_CopyableText_copyButton {
- margin-left: 0 !important;
- }
}
.mx_BeaconStatusTooltip_inner {
diff --git a/res/css/components/views/beacon/_BeaconViewDialog.scss b/res/css/components/views/beacon/_BeaconViewDialog.scss
index 6ad1a2a6139..0fff7210533 100644
--- a/res/css/components/views/beacon/_BeaconViewDialog.scss
+++ b/res/css/components/views/beacon/_BeaconViewDialog.scss
@@ -59,23 +59,6 @@ limitations under the License.
border-radius: 8px;
}
-.mx_BeaconViewDialog_mapFallback {
- box-sizing: border-box;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
-
- background: url('$(res)/img/location/map.svg');
- background-size: cover;
-}
-
-.mx_BeaconViewDialog_mapFallbackIcon {
- width: 65px;
- margin-bottom: $spacing-16;
- color: $quaternary-content;
-}
-
.mx_BeaconViewDialog_mapFallbackMessage {
color: $secondary-content;
margin-bottom: $spacing-16;
diff --git a/res/css/components/views/beacon/_DialogOwnBeaconStatus.scss b/res/css/components/views/beacon/_DialogOwnBeaconStatus.scss
index 791e276f050..1ed370919e9 100644
--- a/res/css/components/views/beacon/_DialogOwnBeaconStatus.scss
+++ b/res/css/components/views/beacon/_DialogOwnBeaconStatus.scss
@@ -46,6 +46,7 @@ limitations under the License.
box-sizing: border-box;
border: 2px solid $location-live-color;
+ border-radius: 50%;
margin: $spacing-8 0 $spacing-8 0;
}
diff --git a/res/css/views/dialogs/_WidgetOpenIDPermissionsDialog.scss b/res/css/components/views/beacon/_ShareLatestLocation.scss
similarity index 63%
rename from res/css/views/dialogs/_WidgetOpenIDPermissionsDialog.scss
rename to res/css/components/views/beacon/_ShareLatestLocation.scss
index a419c105a9a..5d037fdbd55 100644
--- a/res/css/views/dialogs/_WidgetOpenIDPermissionsDialog.scss
+++ b/res/css/components/views/beacon/_ShareLatestLocation.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2019 Travis Ralston
+Copyright 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,15 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_WidgetOpenIDPermissionsDialog .mx_SettingsFlag {
- .mx_ToggleSwitch {
- display: inline-block;
- vertical-align: middle;
- margin-right: 8px;
- }
+.mx_ShareLatestLocation_icon {
+ height: 13px;
+ width: 13px;
+ color: $secondary-content;
+}
- .mx_SettingsFlag_label {
- display: inline-block;
- vertical-align: middle;
+.mx_ShareLatestLocation_copy {
+ // override copyable text style to make compact
+ .mx_CopyableText_copyButton {
+ margin-left: $spacing-8 !important;
}
}
diff --git a/res/css/components/views/beacon/_StyledLiveBeaconIcon.scss b/res/css/components/views/beacon/_StyledLiveBeaconIcon.scss
index 9096c3c71f4..5f9a1920e8b 100644
--- a/res/css/components/views/beacon/_StyledLiveBeaconIcon.scss
+++ b/res/css/components/views/beacon/_StyledLiveBeaconIcon.scss
@@ -23,7 +23,7 @@ limitations under the License.
border-radius: 50%;
background-color: $location-live-color;
- border-color: $location-live-secondary-color;
+ border-color: $location-live-color;
padding: 2px;
// colors icon
color: white;
diff --git a/res/css/components/views/location/_MapFallback.scss b/res/css/components/views/location/_MapFallback.scss
new file mode 100644
index 00000000000..b40e98c6922
--- /dev/null
+++ b/res/css/components/views/location/_MapFallback.scss
@@ -0,0 +1,45 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_MapFallback {
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+ z-index: 0;
+
+ background-color: $system;
+}
+
+.mx_MapFallback_bg {
+ position: absolute;
+ top: 0;
+ left: 0;
+ min-height: 100%;
+ min-width: 100%;
+ color: $quinary-content;
+ z-index: -1;
+
+ pointer-events: none;
+}
+
+.mx_MapFallback_icon {
+ width: 65px;
+ margin-bottom: $spacing-16;
+ color: $quaternary-content;
+}
diff --git a/res/css/components/views/location/_ShareType.scss b/res/css/components/views/location/_ShareType.scss
index 458be106eb0..6b39f1a80a4 100644
--- a/res/css/components/views/location/_ShareType.scss
+++ b/res/css/components/views/location/_ShareType.scss
@@ -63,14 +63,6 @@ limitations under the License.
&:hover, &:focus {
border-color: $accent;
}
-
- // this style is only during active development
- // when lab is enabled but feature not fully implemented
- // pin drop option will be disabled
- &.mx_AccessibleButton_disabled {
- pointer-events: none;
- opacity: 0.4;
- }
}
.mx_ShareType_option-icon {
diff --git a/res/css/components/views/messages/_MBeaconBody.scss b/res/css/components/views/messages/_MBeaconBody.scss
index dc63d6676db..5654f14a057 100644
--- a/res/css/components/views/messages/_MBeaconBody.scss
+++ b/res/css/components/views/messages/_MBeaconBody.scss
@@ -26,30 +26,17 @@ limitations under the License.
.mx_MBeaconBody_map {
height: 100%;
width: 100%;
- z-index: 0; // keeps the entire map under the message action bar
+ z-index: 0; // keeps the entire map under the message action bars
- &:not(.mx_MBeaconBody_mapFallback) {
- cursor: pointer;
- }
+ cursor: pointer;
}
.mx_MBeaconBody_mapFallback {
- box-sizing: border-box;
- display: flex;
- justify-content: center;
- align-items: center;
-
// pushes spinner/icon up
// to appear more centered with the footer
padding-bottom: 50px;
- background: url('$(res)/img/location/map.svg');
- background-size: cover;
-}
-
-.mx_MBeaconBody_mapFallbackIcon {
- width: 65px;
- color: $quaternary-content;
+ cursor: default;
}
.mx_MBeaconBody_chin {
diff --git a/res/css/views/context_menus/_MessageContextMenu.scss b/res/css/views/context_menus/_MessageContextMenu.scss
index b92ce10d355..90a1c58ee36 100644
--- a/res/css/views/context_menus/_MessageContextMenu.scss
+++ b/res/css/views/context_menus/_MessageContextMenu.scss
@@ -109,4 +109,8 @@ limitations under the License.
.mx_MessageContextMenu_iconViewInRoom::before {
mask-image: url('$(res)/img/element-icons/view-in-room.svg');
}
+
+ .mx_MessageContextMenu_jumpToEvent::before {
+ mask-image: url('$(res)/img/element-icons/child-relationship.svg');
+ }
}
diff --git a/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.scss b/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.scss
index 8786defed38..c559467c9de 100644
--- a/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.scss
+++ b/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.scss
@@ -46,10 +46,6 @@ limitations under the License.
font-size: $font-12px;
.mx_ToggleSwitch {
- display: inline-block;
- vertical-align: middle;
- margin-right: 8px;
-
// downsize the switch + ball
width: $font-32px;
height: $font-15px;
@@ -64,10 +60,5 @@ limitations under the License.
border-radius: $font-15px;
}
}
-
- .mx_SettingsFlag_label {
- display: inline-block;
- vertical-align: middle;
- }
}
}
diff --git a/res/css/views/elements/_LabelledCheckbox.scss b/res/css/views/elements/_LabelledCheckbox.scss
new file mode 100644
index 00000000000..c97b1b341a1
--- /dev/null
+++ b/res/css/views/elements/_LabelledCheckbox.scss
@@ -0,0 +1,39 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_LabelledCheckbox {
+ display: flex;
+ flex-direction: row;
+
+ .mx_Checkbox {
+ margin-top: 3px; // visually align with label text
+ }
+
+ .mx_LabelledCheckbox_labels {
+ flex: 1;
+
+ .mx_LabelledCheckbox_label {
+ vertical-align: middle;
+ }
+
+ .mx_LabelledCheckbox_byline {
+ display: block;
+ padding-top: $spacing-4;
+ color: $muted-fg-color;
+ font-size: $font-11px;
+ }
+ }
+}
diff --git a/res/css/views/elements/_SettingsFlag.scss b/res/css/views/elements/_SettingsFlag.scss
index c6f4cf6ec5c..6d941e94eb5 100644
--- a/res/css/views/elements/_SettingsFlag.scss
+++ b/res/css/views/elements/_SettingsFlag.scss
@@ -24,6 +24,19 @@ limitations under the License.
.mx_ToggleSwitch {
flex: 0 0 auto;
}
+
+ &.mx_SettingsFlag_toggleInFront {
+ .mx_ToggleSwitch {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: 8px;
+ }
+
+ .mx_SettingsFlag_label {
+ display: inline-block;
+ vertical-align: middle;
+ }
+ }
}
.mx_SettingsFlag_label {
diff --git a/res/css/views/messages/_DisambiguatedProfile.scss b/res/css/views/messages/_DisambiguatedProfile.scss
index caef2fa4ad3..cb605726dd9 100644
--- a/res/css/views/messages/_DisambiguatedProfile.scss
+++ b/res/css/views/messages/_DisambiguatedProfile.scss
@@ -18,15 +18,18 @@ limitations under the License.
.mx_DisambiguatedProfile {
overflow: hidden;
text-overflow: ellipsis;
+ white-space: nowrap;
+ cursor: pointer;
.mx_DisambiguatedProfile_displayName {
font-weight: 600;
+ margin-inline-end: 0;
}
.mx_DisambiguatedProfile_mxid {
font-weight: 600;
font-size: 1.1rem;
- margin-left: 5px;
+ margin-inline-start: 5px;
opacity: 0.5; // Match mx_TextualEvent
color: $primary-content;
}
diff --git a/res/css/views/messages/_MImageBody.scss b/res/css/views/messages/_MImageBody.scss
index 0cbcbd46582..7cd34cba612 100644
--- a/res/css/views/messages/_MImageBody.scss
+++ b/res/css/views/messages/_MImageBody.scss
@@ -60,12 +60,6 @@ $timeline-image-border-radius: $border-radius-8px;
// Necessary for the border radius to apply correctly to the placeholder
overflow: hidden;
contain: paint;
-
- min-height: $font-44px;
- min-width: $font-44px;
- display: flex;
- justify-content: center;
- align-items: center;
}
.mx_MImageBody_thumbnail {
diff --git a/res/css/views/messages/_MImageReplyBody.scss b/res/css/views/messages/_MImageReplyBody.scss
index 2bdf571f0d1..3207443d65b 100644
--- a/res/css/views/messages/_MImageReplyBody.scss
+++ b/res/css/views/messages/_MImageReplyBody.scss
@@ -20,10 +20,6 @@ limitations under the License.
.mx_MImageBody_thumbnail_container {
flex: 1;
margin-right: 4px;
-
- .mx_MImageBody_banner {
- display: none;
- }
}
.mx_MImageReplyBody_info {
diff --git a/res/css/views/messages/_ReactionsRow.scss b/res/css/views/messages/_ReactionsRow.scss
index d4695888dfc..591abce1435 100644
--- a/res/css/views/messages/_ReactionsRow.scss
+++ b/res/css/views/messages/_ReactionsRow.scss
@@ -57,15 +57,16 @@ limitations under the License.
}
.mx_ReactionsRow_showAll {
- @mixin ButtonResetDefault;
- text-decoration: none;
- font-size: $font-12px;
- line-height: $font-20px;
- margin-left: 4px;
- vertical-align: middle;
color: $tertiary-content;
- &:hover {
- color: $primary-content;
+ &.mx_AccessibleButton_kind_link_inline {
+ font-size: $font-12px;
+ line-height: $font-20px;
+ margin-inline-start: $spacing-4;
+ vertical-align: middle;
+
+ &:hover {
+ color: $primary-content;
+ }
}
}
diff --git a/res/css/views/right_panel/_BaseCard.scss b/res/css/views/right_panel/_BaseCard.scss
index a615f5a8814..894138add20 100644
--- a/res/css/views/right_panel/_BaseCard.scss
+++ b/res/css/views/right_panel/_BaseCard.scss
@@ -16,6 +16,7 @@ limitations under the License.
.mx_BaseCard {
--BaseCard_EventTile_line-padding-block: 2px;
+ --BaseCard_EventTile-spacing-horizontal: 36px;
padding: 0 8px;
overflow: hidden;
@@ -24,7 +25,9 @@ limitations under the License.
flex: 1;
.mx_BaseCard_header {
- margin: 4px 0;
+ --BaseCard_header_button-margin: $spacing-12;
+
+ margin: $spacing-4 0;
> h2 {
margin: 0 44px;
@@ -35,12 +38,13 @@ limitations under the License.
white-space: nowrap;
}
- .mx_BaseCard_back, .mx_BaseCard_close {
+ .mx_BaseCard_back,
+ .mx_BaseCard_close {
position: absolute;
background-color: rgba(141, 151, 165, 0.2);
height: 20px;
width: 20px;
- margin: 12px;
+ margin: var(--BaseCard_header_button-margin);
top: 0;
border-radius: $border-radius-10px;
diff --git a/res/css/views/right_panel/_ThreadPanel.scss b/res/css/views/right_panel/_ThreadPanel.scss
index bab7c2e608c..ddc30fa8d9e 100644
--- a/res/css/views/right_panel/_ThreadPanel.scss
+++ b/res/css/views/right_panel/_ThreadPanel.scss
@@ -15,32 +15,38 @@ limitations under the License.
*/
.mx_ThreadPanel {
+ --ThreadPanel_header-button-size: 24px;
+
display: flex;
flex-direction: column;
height: 100px;
overflow: visible;
.mx_BaseCard_header {
- margin-bottom: 12px;
+ margin-bottom: $spacing-12;
.mx_BaseCard_close,
.mx_BaseCard_back {
- width: 24px;
- height: 24px;
+ width: var(--ThreadPanel_header-button-size);
+ height: var(--ThreadPanel_header-button-size);
}
.mx_BaseCard_back {
- left: -4px;
+ margin-inline-start: calc(var(--BaseCard_header_button-margin) - 4px);
}
.mx_BaseCard_close {
- right: -4px;
+ margin-inline-end: calc(var(--BaseCard_header_button-margin) - 4px);
}
}
.mx_BaseCard_back ~ .mx_ThreadPanel__header {
width: calc(100% - 60px);
- margin-left: 30px;
+ margin-inline-start: var(--ThreadPanel_header-button-size);
+
+ span {
+ margin-inline-start: 6px;
+ }
}
.mx_ThreadPanel__header {
@@ -68,42 +74,16 @@ limitations under the License.
}
.mx_MessageActionBar_maskButton {
- --size: 24px;
- width: var(--size);
- height: var(--size);
+ width: var(--ThreadPanel_header-button-size);
+ height: var(--ThreadPanel_header-button-size);
&::after {
- mask-size: var(--size);
+ mask-size: var(--ThreadPanel_header-button-size);
mask-image: url("$(res)/img/element-icons/message/overflow-large.svg");
}
}
}
- .mx_ThreadPanel_button {
- width: 20px;
- height: 20px;
- margin-top: -3px;
- margin-bottom: auto;
- position: relative;
-
- &::before {
- top: 2px;
- left: 2px;
- content: '';
- width: 16px;
- height: 16px;
- position: absolute;
- mask-position: center;
- mask-size: contain;
- mask-repeat: no-repeat;
- background: $primary-content;
- }
-
- &.mx_ThreadPanel_OptionsButton::before {
- mask-image: url('$(res)/img/element-icons/context-menu.svg');
- }
- }
-
.mx_AutoHideScrollbar,
.mx_RoomView_messagePanelSpinner {
background-color: $background;
@@ -139,13 +119,29 @@ limitations under the License.
}
}
- &.mx_ThreadView .mx_ThreadView_timelinePanelWrapper {
- position: relative;
- min-height: 0; // don't displace the composer
- flex-grow: 1;
+ &.mx_ThreadView {
+ max-height: 100%;
+
+ // Inside a thread timeline only
+ .mx_GenericEventListSummary {
+ &:not([data-layout=bubble]) > .mx_EventTile_line {
+ padding-inline-start: var(--ThreadView_group_spacing-start); // align summary text with message text
+ padding-inline-end: var(--ThreadView_group_spacing-end); // align summary text with message text
+ }
+ }
+
+ .mx_ThreadView_timelinePanelWrapper {
+ position: relative;
+ min-height: 0; // don't displace the composer
+ flex-grow: 1;
- .mx_FileDropTarget {
- border-radius: 8px;
+ .mx_FileDropTarget {
+ border-radius: 8px;
+ }
+ }
+
+ .mx_MessageComposer_sendMessage {
+ margin-right: 0;
}
}
@@ -166,22 +162,6 @@ limitations under the License.
// Account for scrollbar when hovering
padding-top: 0;
- .mx_ThreadSummary {
- position: relative;
- padding-right: 11px;
-
- &::after {
- content: '';
- display: block;
- position: absolute;
- left: 0;
- bottom: -16px;
- height: 1px;
- width: 100%;
- border-bottom: 1px solid $message-action-bar-border-color;
- }
- }
-
.mx_DateSeparator {
display: none;
}
@@ -191,16 +171,6 @@ limitations under the License.
}
}
- .mx_GenericEventListSummary {
- &[data-layout=bubble] > .mx_EventTile_line {
- padding-left: 30px !important; // Override main timeline styling - align summary text with message text
- }
-
- &:not([data-layout=bubble]) > .mx_EventTile_line {
- padding-inline-start: var(--ThreadView_group_spacing-start); // align summary text with message text
- }
- }
-
.mx_MessageComposer {
background-color: $background;
border-radius: 8px;
@@ -346,6 +316,8 @@ limitations under the License.
bottom: 0;
left: 0;
padding: 20px;
+ box-sizing: border-box; // Include padding and border
+ width: 100%;
h2 {
color: $primary-content;
diff --git a/res/css/views/right_panel/_TimelineCard.scss b/res/css/views/right_panel/_TimelineCard.scss
index 6b4c0d23610..3bc71040811 100644
--- a/res/css/views/right_panel/_TimelineCard.scss
+++ b/res/css/views/right_panel/_TimelineCard.scss
@@ -43,8 +43,8 @@ limitations under the License.
}
.mx_NewRoomIntro {
- margin-inline-start: 36px; // TODO: Use a variable
- margin-inline-end: 36px; // TODO: Use a variable
+ margin-inline-start: var(--BaseCard_EventTile-spacing-horizontal);
+ margin-inline-end: var(--BaseCard_EventTile-spacing-horizontal);
}
.mx_EventTile_content {
@@ -52,13 +52,9 @@ limitations under the License.
}
.mx_EventTile:not([data-layout="bubble"]) {
- $left-gutter: 36px;
-
+ &.mx_EventTile_info .mx_EventTile_line,
.mx_EventTile_line {
- padding-inline-start: $left-gutter;
- padding-inline-end: 36px;
- padding-top: var(--BaseCard_EventTile_line-padding-block);
- padding-bottom: var(--BaseCard_EventTile_line-padding-block);
+ padding: var(--BaseCard_EventTile_line-padding-block) var(--BaseCard_EventTile-spacing-horizontal);
.mx_EventTile_e2eIcon {
inset-inline-start: 8px;
@@ -68,7 +64,7 @@ limitations under the License.
.mx_DisambiguatedProfile,
.mx_ReactionsRow,
.mx_ThreadSummary {
- margin-inline-start: $left-gutter;
+ margin-inline-start: var(--BaseCard_EventTile-spacing-horizontal);
}
.mx_ReactionsRow {
@@ -100,16 +96,31 @@ limitations under the License.
}
&.mx_EventTile_info {
- .mx_EventTile_line {
- padding-left: $left-gutter;
- }
-
.mx_EventTile_avatar {
left: 18px;
}
}
}
+ .mx_EventTile,
+ .mx_GenericEventListSummary {
+ .mx_ThreadSummary {
+ position: relative;
+ padding-right: 11px;
+
+ &::after {
+ content: '';
+ display: block;
+ position: absolute;
+ left: 0;
+ bottom: -16px;
+ height: 1px;
+ width: 100%;
+ border-bottom: 1px solid $message-action-bar-border-color;
+ }
+ }
+ }
+
.mx_CallEvent_wrapper {
justify-content: center;
margin: auto 5px;
@@ -118,9 +129,12 @@ limitations under the License.
}
}
- .mx_GenericEventListSummary:not([data-layout=bubble]) .mx_EventTile_line,
- .mx_GenericEventListSummary:not([data-layout=bubble]) > .mx_GenericEventListSummary_unstyledList > .mx_EventTile_info .mx_EventTile_avatar ~ .mx_EventTile_line {
- padding-left: 36px;
+ .mx_GenericEventListSummary:not([data-layout=bubble]) {
+ .mx_EventTile_line,
+ > .mx_GenericEventListSummary_unstyledList > .mx_EventTile_info .mx_EventTile_avatar ~ .mx_EventTile_line {
+ padding-inline-start: var(--BaseCard_EventTile-spacing-horizontal);
+ padding-inline-end: var(--BaseCard_EventTile-spacing-horizontal);
+ }
}
.mx_ReadReceiptGroup {
diff --git a/res/css/views/right_panel/_UserInfo.scss b/res/css/views/right_panel/_UserInfo.scss
index 3e6c31059af..12e93395f5b 100644
--- a/res/css/views/right_panel/_UserInfo.scss
+++ b/res/css/views/right_panel/_UserInfo.scss
@@ -30,7 +30,7 @@ limitations under the License.
top: 0;
border-radius: $border-radius-4px;
background-color: $dark-panel-bg-color;
- margin: 9px;
+ margin: 9px; // TODO: Use a variable
z-index: 1; // render on top of the right panel
div {
@@ -47,11 +47,24 @@ limitations under the License.
h2 {
font-size: $font-18px;
font-weight: 600;
- margin: 18px 0 0 0;
+ margin: 18px 0 0 0; // TODO: Use a variable
}
.mx_UserInfo_container {
- padding: 8px 16px;
+ padding: $spacing-8 $spacing-16;
+
+ &:not(.mx_UserInfo_separator) {
+ padding-top: $spacing-16;
+ padding-bottom: 0;
+
+ > :not(h3) {
+ margin-inline-start: $spacing-8;
+ display: flex;
+ flex-flow: column;
+ align-items: flex-start;
+ row-gap: $spacing-8;
+ }
+ }
.mx_UserInfo_container_verifyButton {
margin-top: $spacing-8;
@@ -65,7 +78,7 @@ limitations under the License.
.mx_UserInfo_memberDetailsContainer {
padding-top: 0;
padding-bottom: 0;
- margin-bottom: 8px;
+ margin-bottom: $spacing-8;
}
.mx_RoomTile_titleContainer {
@@ -81,52 +94,54 @@ limitations under the License.
}
.mx_UserInfo_avatar {
- margin: 24px 32px 0 32px;
- }
-
- .mx_UserInfo_avatar > div {
- max-width: 30vh;
- margin: 0 auto;
- transition: 0.5s;
- }
-
- .mx_UserInfo_avatar > div > div {
- /* use padding-top instead of height to make this element square,
- as the % in padding is a % of the width (including margin,
- that's why we had to put the margin to center on a parent div),
- and not a % of the parent height. */
- padding-top: 100%;
- position: relative;
- }
-
- .mx_UserInfo_avatar > div > div * {
- border-radius: 100%;
- position: absolute;
- top: 0;
- left: 0;
- width: 100% !important;
- height: 100% !important;
- }
-
- .mx_UserInfo_avatar .mx_BaseAvatar_initial {
- z-index: 1;
- display: flex;
- align-items: center;
- justify-content: center;
-
- // override the calculated sizes so that the letter isn't HUGE
- font-size: 6rem !important;
- width: 100% !important;
- transition: font-size 0.5s;
- }
-
- .mx_UserInfo_avatar .mx_BaseAvatar {
- .mx_BaseAvatar_initial + .mx_BaseAvatar_image {
- cursor: default;
- }
+ margin: $spacing-24 $spacing-32 0 $spacing-32;
+
+ .mx_UserInfo_avatar_transition {
+ max-width: 30vh;
+ margin: 0 auto;
+ transition: 0.5s;
+
+ .mx_UserInfo_avatar_transition_child {
+ /* use padding-top instead of height to make this element square,
+ as the % in padding is a % of the width (including margin,
+ that's why we had to put the margin to center on a parent div),
+ and not a % of the parent height. */
+ padding-top: 100%;
+ position: relative;
+
+ .mx_BaseAvatar,
+ .mx_BaseAvatar_initial,
+ .mx_BaseAvatar_image {
+ border-radius: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100% !important;
+ height: 100% !important;
+ }
- &.mx_BaseAvatar_image {
- cursor: zoom-in;
+ .mx_BaseAvatar {
+ &.mx_BaseAvatar_image {
+ cursor: zoom-in;
+ }
+
+ .mx_BaseAvatar_initial {
+ z-index: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ // override the calculated sizes so that the letter isn't HUGE
+ font-size: 6rem !important;
+ width: 100% !important;
+ transition: font-size 0.5s;
+
+ & + .mx_BaseAvatar_image {
+ cursor: default;
+ }
+ }
+ }
+ }
}
}
@@ -135,11 +150,11 @@ limitations under the License.
color: $tertiary-content;
font-weight: 600;
font-size: $font-12px;
- margin: 4px 0;
+ margin: $spacing-4 0;
}
p {
- margin: 5px 0;
+ margin: 5px 0; // TODO: Use a variable
}
.mx_UserInfo_profile {
@@ -165,34 +180,36 @@ limitations under the License.
}
.mx_E2EIcon {
- margin-top: 3px; // visual vertical centering to the top line of text
- margin-right: 4px; // margin from displyname
+ margin-top: 3px; // visual vertical centering to the top line of text. TODO: Use a variable
+ margin-inline-end: $spacing-4; // margin from displayName
min-width: 18px; // convince flexbox to not collapse it
}
}
.mx_UserInfo_profileStatus {
- margin-top: 12px;
+ margin-top: $spacing-12;
}
}
- .mx_UserInfo_memberDetails .mx_UserInfo_profileField {
- display: flex;
- justify-content: center;
- align-items: center;
-
- margin: 6px 0;
-
- .mx_UserInfo_roleDescription {
+ .mx_UserInfo_memberDetails {
+ .mx_UserInfo_profileField {
display: flex;
justify-content: center;
align-items: center;
- // try to make it the same height as the dropdown
- margin: 11px 0 12px 0;
- }
- .mx_Field {
- margin: 0;
+ margin: 6px 0; // TODO: Use a variable
+
+ .mx_UserInfo_roleDescription {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ // try to make it the same height as the dropdown
+ margin: 11px 0 12px 0;
+ }
+
+ .mx_Field {
+ margin: 0;
+ }
}
}
@@ -224,19 +241,6 @@ limitations under the License.
flex: 1 1 0;
}
- .mx_UserInfo_container:not(.mx_UserInfo_separator) {
- padding-top: 16px;
- padding-bottom: 0;
-
- > :not(h3) {
- margin-inline-start: $spacing-8;
- display: flex;
- flex-flow: column;
- align-items: flex-start;
- row-gap: $spacing-8;
- }
- }
-
.mx_UserInfo_devices {
.mx_UserInfo_device {
display: flex;
@@ -272,17 +276,24 @@ limitations under the License.
.mx_UserInfo_expand {
column-gap: 5px; // cf: mx_UserInfo_device_name
margin-bottom: 11px;
+ align-items: initial; // Cancel the default property
}
}
-}
-.mx_UserInfo.mx_UserInfo_smallAvatar {
- .mx_UserInfo_avatar > div {
- max-width: 72px;
- margin: 0 auto;
- }
+ &.mx_UserInfo_smallAvatar {
+ .mx_UserInfo_avatar {
+ .mx_UserInfo_avatar_transition {
+ max-width: 72px;
+ margin: 0 auto;
+ }
- .mx_UserInfo_avatar .mx_BaseAvatar_initial {
- font-size: 40px !important; // override the other override because here the avatar is smaller
+ .mx_UserInfo_avatar_transition_child {
+ .mx_BaseAvatar {
+ .mx_BaseAvatar_initial {
+ font-size: 40px !important; // override the other override because here the avatar is smaller
+ }
+ }
+ }
+ }
}
}
diff --git a/res/css/views/rooms/_EditMessageComposer.scss b/res/css/views/rooms/_EditMessageComposer.scss
index f4c15dac5ef..b639ec22de4 100644
--- a/res/css/views/rooms/_EditMessageComposer.scss
+++ b/res/css/views/rooms/_EditMessageComposer.scss
@@ -18,12 +18,11 @@ limitations under the License.
.mx_EditMessageComposer {
display: flex;
flex-direction: column;
+ max-width: 100%; // disable overflow
+ width: auto;
gap: 5px;
padding: 3px;
- // Make sure the formatting bar is visible
- overflow: visible !important; // override mx_EventTile_content
-
.mx_BasicMessageComposer_input {
border-radius: $border-radius-4px;
border: solid 1px $primary-hairline-color;
@@ -38,12 +37,15 @@ limitations under the License.
.mx_EditMessageComposer_buttons {
display: flex;
- flex-direction: row;
+ flex-flow: row wrap-reverse; // display "Save" over "Cancel"
justify-content: flex-end;
gap: 5px;
+ margin-inline-start: auto;
.mx_AccessibleButton {
- padding: 5px 40px;
+ flex: 1;
+ box-sizing: border-box;
+ min-width: 100px; // magic number to align the edge of the button with the input area
}
}
}
diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss
index bbc4d3c53fa..75071366fac 100644
--- a/res/css/views/rooms/_EventBubbleTile.scss
+++ b/res/css/views/rooms/_EventBubbleTile.scss
@@ -111,10 +111,29 @@ limitations under the License.
.mx_DisambiguatedProfile,
.mx_EventTile_line {
+ --EventBubbleTile_line-max-width: 70%;
+
width: fit-content;
- max-width: 70%;
- // fixed line height to prevent emoji from being taller than text
- line-height: $font-18px;
+ max-width: var(--EventBubbleTile_line-max-width); // Align message bubble and displayName
+ line-height: $font-18px; // fixed line height to prevent emoji from being taller than text
+ }
+
+ // other users profile on bubble layout
+ > .mx_DisambiguatedProfile {
+ white-space: normal; // display mxid
+
+ .mx_DisambiguatedProfile_displayName {
+ white-space: nowrap; // truncate long display names
+ margin-inline-end: 5px;
+
+ // For RTL displayName
+ unicode-bidi: embed;
+ direction: ltr;
+ }
+
+ .mx_DisambiguatedProfile_mxid {
+ margin-inline-start: 0; // Align mxid with truncated displayName inside mx_EventTile[data-layout=bubble]
+ }
}
// inside mx_RoomView_MessageList, outside of mx_ReplyTile
@@ -138,9 +157,12 @@ limitations under the License.
padding-right: 48px;
}
- .mx_MImageBody_thumbnail_container {
- min-height: calc(1.8rem + var(--gutterSize) + var(--gutterSize));
- min-width: calc(1.8rem + var(--gutterSize) + var(--gutterSize));
+ .mx_MImageBody {
+ .mx_MImageBody_thumbnail_container {
+ justify-content: center;
+ min-height: calc(1.8rem + var(--gutterSize) + var(--gutterSize));
+ min-width: calc(1.8rem + var(--gutterSize) + var(--gutterSize));
+ }
}
.mx_CallEvent {
@@ -243,10 +265,12 @@ limitations under the License.
}
.mx_EventTile_line {
+ --EventBubbleTile_line-margin-inline-end: -12px;
+
position: relative;
display: flex;
gap: 5px;
- margin: 0 -12px 0 -9px;
+ margin: 0 var(--EventBubbleTile_line-margin-inline-end) 0 -9px;
border-top-left-radius: var(--cornerRadius);
border-top-right-radius: var(--cornerRadius);
@@ -261,29 +285,37 @@ limitations under the License.
z-index: 3; // above media and location share maps
}
- &.mx_EventTile_mediaLine .mx_MVoiceMessageBody {
- // allow the event to be collapsed, this causes the waveform to get cropped
- min-width: 0;
- }
+ &.mx_EventTile_mediaLine {
+ // TODO: Use a common class name instead
+ .mx_MFileBody,
+ .mx_MAudioBody {
+ max-width: 100%; // avoid overflow
+ }
- // we put the timestamps for media (other than stickers) atop the media
- // for images we also apply a linear gradient and change the timestamp colour to aid readability
- &.mx_EventTile_mediaLine.mx_EventTile_image {
- .mx_MessageTimestamp {
- color: #ffffff; // regardless of theme, always visible on the below gradient
+ .mx_MVoiceMessageBody {
+ // allow the event to be collapsed, this causes the waveform to get cropped
+ min-width: 0;
}
- // linear gradient to make the timestamp more visible
- .mx_MImageBody::before {
- content: "";
- position: absolute;
- background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.2) 100%);
- z-index: 1;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- pointer-events: none;
+ // we put the timestamps for media (other than stickers) atop the media
+ // for images we also apply a linear gradient and change the timestamp colour to aid readability
+ &.mx_EventTile_image {
+ .mx_MessageTimestamp {
+ color: #ffffff; // regardless of theme, always visible on the below gradient
+ }
+
+ // linear gradient to make the timestamp more visible
+ .mx_MImageBody::before {
+ content: "";
+ position: absolute;
+ background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.2) 100%);
+ z-index: 1;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ pointer-events: none;
+ }
}
}
@@ -454,25 +486,54 @@ limitations under the License.
margin-left: -9px;
}
- /* Special layout scenario for "Unable To Decrypt (UTD)" events */
- &.mx_EventTile_bad > .mx_EventTile_line {
- display: grid;
- grid-template:
- "reply reply" auto
- "shield body" auto
- "shield link" auto
- / auto 1fr;
- .mx_EventTile_e2eIcon {
- grid-area: shield;
- }
- .mx_UnknownBody {
- grid-area: body;
- }
- .mx_EventTile_keyRequestInfo {
- grid-area: link;
+ &.mx_EventTile_bad {
+ /* Special layout scenario for "Unable To Decrypt (UTD)" events */
+ .mx_EventTile_line {
+ display: grid;
+ grid-template:
+ "reply reply" auto
+ "shield body" auto
+ "shield link" auto
+ / auto 1fr;
+
+ .mx_UnknownBody,
+ .mx_EventTile_keyRequestInfo,
+ .mx_ReplyChain_wrapper,
+ .mx_ViewSourceEvent {
+ min-width: 0; // Prevent a grid blowout
+ }
+
+ .mx_EventTile_e2eIcon {
+ grid-area: shield;
+ }
+
+ .mx_UnknownBody {
+ grid-area: body;
+ }
+
+ .mx_EventTile_keyRequestInfo {
+ grid-area: link;
+ }
+
+ .mx_ReplyChain_wrapper {
+ grid-area: reply;
+ }
}
- .mx_ReplyChain_wrapper {
- grid-area: reply;
+
+ &.mx_EventTile_info {
+ // "Unable To Decrypt" layout for hidden events
+ .mx_EventTile_line {
+ gap: 0 9px; // 9px: margin value of E2E icon
+ align-items: center;
+ grid-template:
+ "shield source" auto
+ "shield link" auto
+ / auto 1fr;
+
+ .mx_ViewSourceEvent {
+ grid-area: source;
+ }
+ }
}
}
@@ -606,44 +667,44 @@ limitations under the License.
content: "";
clear: both;
}
-}
-.mx_GenericEventListSummary[data-expanded=false][data-layout=bubble] {
- // Align with left edge of bubble tiles
- padding: 0 49px;
-}
+ &[data-expanded=false] {
+ // Align with left edge of bubble tiles
+ padding: 0 49px;
-// ideally we'd use display=contents here for the layout to all work regardless of the *ELS but
-// that breaks ScrollPanel's reliance upon offsetTop so we have to have a bit more finesse.
-.mx_GenericEventListSummary[data-expanded=true][data-layout=bubble] {
- display: flex;
- flex-direction: column;
- margin: 0;
+ // increase margin between ELS and the next Event to not have our user avatar overlap the expand/collapse button
+ + .mx_EventTile[data-layout=bubble][data-self=true] {
+ margin-top: 20px;
+ }
+ }
- .mx_EventTile_info {
- padding: 2px 0;
- margin-right: 0;
+ // ideally we'd use display=contents here for the layout to all work regardless of the *ELS but
+ // that breaks ScrollPanel's reliance upon offsetTop so we have to have a bit more finesse.
+ &[data-expanded=true] {
+ display: flex;
+ flex-direction: column;
+ margin: 0;
- .mx_MessageActionBar {
- inset-inline-start: initial; // Reset .mx_EventTile[data-layout="bubble"][data-self="false"] .mx_MessageActionBar
- right: 48px; // align with that of right-column bubbles
- }
+ .mx_EventTile_info {
+ padding: 2px 0;
+ margin-right: 0;
- .mx_ReadReceiptGroup {
- right: -18px; // match alignment to RRs of chat bubbles
- }
+ .mx_MessageActionBar {
+ inset-inline-start: initial; // Reset .mx_EventTile[data-layout="bubble"][data-self="false"] .mx_MessageActionBar
+ right: 48px; // align with that of right-column bubbles
+ }
- &::before {
- right: 0; // match alignment of the hover background to that of chat bubbles
+ .mx_ReadReceiptGroup {
+ right: -18px; // match alignment to RRs of chat bubbles
+ }
+
+ &::before {
+ right: 0; // match alignment of the hover background to that of chat bubbles
+ }
}
}
}
-// increase margin between ELS and the next Event to not have our user avatar overlap the expand/collapse button
-.mx_GenericEventListSummary[data-layout=bubble][data-expanded=false] + .mx_EventTile[data-layout=bubble][data-self=true] {
- margin-top: 20px;
-}
-
/* events that do not require bubble layout */
.mx_GenericEventListSummary[data-layout=bubble],
.mx_EventTile.mx_EventTile_bad[data-layout=bubble] {
diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss
index 11799641638..e7e79ab299b 100644
--- a/res/css/views/rooms/_EventTile.scss
+++ b/res/css/views/rooms/_EventTile.scss
@@ -51,6 +51,20 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
mask-image: url('$(res)/img/element-icons/circle-sending.svg');
}
+ .mx_EventTile_content {
+ &.mx_EditMessageComposer {
+ // Make sure the formatting bar is visible
+ overflow: visible;
+ }
+ }
+
+ .mx_MImageBody {
+ .mx_MImageBody_thumbnail_container {
+ display: flex;
+ align-items: center; // on every layout
+ }
+ }
+
&[data-layout=group] {
.mx_EventTile_line {
line-height: var(--GroupLayout-EventTile-line-height);
@@ -65,25 +79,6 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
font-size: $font-14px;
position: relative;
- &[data-shape=ThreadsList][data-notification]::before {
- content: "";
- position: absolute;
- width: 10px;
- height: 10px;
- border-radius: 50%;
- right: -25px; // center it in the gutter (16px margin + 4px padding + half 10px width)
- top: 4px;
- left: auto;
- }
-
- &[data-shape=ThreadsList][data-notification=total]::before {
- background-color: $room-icon-unread-color;
- }
-
- &[data-shape=ThreadsList][data-notification=highlight]::before {
- background-color: $alert;
- }
-
.mx_ThreadSummary,
.mx_ThreadSummaryIcon {
margin-left: 64px;
@@ -131,14 +126,9 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
color: $primary-content;
font-size: $font-14px;
display: inline-block;
- /* anti-zalgo, with overflow hidden */
- overflow: hidden;
padding-bottom: 0px;
padding-top: 0px;
margin: 0px;
- /* the next three lines, along with overflow hidden, truncate long display names */
- white-space: nowrap;
- text-overflow: ellipsis;
max-width: calc(100% - $left-gutter);
}
@@ -263,6 +253,12 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
.mx_MImageBody {
margin-right: 34px;
+
+ .mx_MImageBody_thumbnail_container {
+ justify-content: flex-start;
+ min-height: $font-44px;
+ min-width: $font-44px;
+ }
}
.mx_EventTile_e2eIcon {
@@ -294,34 +290,128 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
padding-left: calc($left-gutter + 20px); // override padding-left $left-gutter
}
-/* all the overflow-y: hidden; are to trap Zalgos -
- but they introduce an implicit overflow-x: auto.
- so make that explicitly hidden too to avoid random
- horizontal scrollbars occasionally appearing, like in
- https://github.com/vector-im/vector-web/issues/1154 */
.mx_EventTile_content {
+ /*
+ all the overflow-y: hidden; are to trap Zalgos -
+ but they introduce an implicit overflow-x: auto.
+ so make that explicitly hidden too to avoid random
+ horizontal scrollbars occasionally appearing, like in
+ https://github.com/vector-im/vector-web/issues/1154
+ */
overflow-y: hidden;
overflow-x: hidden;
margin-right: 34px;
+
+ .mx_EventTile_edited,
+ .mx_EventTile_pendingModeration {
+ user-select: none;
+ font-size: $font-12px;
+ color: $roomtopic-color;
+ display: inline-block;
+ margin-left: 9px;
+ }
+
+ .mx_EventTile_edited {
+ cursor: pointer;
+ }
+
+ .markdown-body {
+ font-family: inherit !important;
+ white-space: normal !important;
+ line-height: inherit !important;
+ color: inherit; // inherit the colour from the dark or light theme by default (but not for code blocks)
+ font-size: $font-14px;
+
+ pre,
+ code {
+ font-family: $monospace-font-family !important;
+ background-color: $codeblock-background-color;
+ }
+
+ code {
+ white-space: pre-wrap; // don't collapse spaces in inline code blocks
+ }
+
+ pre {
+ // have to use overlay rather than auto otherwise Linux and Windows
+ // Chrome gets very confused about vertical spacing:
+ // https://github.com/vector-im/vector-web/issues/754
+ overflow-x: overlay;
+ overflow-y: visible;
+
+ &::-webkit-scrollbar-corner {
+ background: transparent;
+ }
+
+ code {
+ white-space: pre; // we want code blocks to be scrollable and not wrap
+
+ > * {
+ display: inline;
+ }
+ }
+ }
+
+ h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6 {
+ font-family: inherit !important;
+ color: inherit;
+ }
+
+ /* Make h1 and h2 the same size as h3. */
+ h1,
+ h2 {
+ font-size: 1.5em;
+ border-bottom: none !important; // override GFM
+ }
+
+ a {
+ color: $accent-alt;
+ }
+
+ blockquote {
+ color: unset;
+ margin: 0 0 16px;
+ padding: 2px 10px;
+ border-left: 2px solid $blockquote-bar-color;
+ line-height: $font-18px;
+ }
+
+ /*
+ // actually, removing the Italic TTF provides
+ // better results seemingly
+
+ // compensate for Nunito italics being terrible
+ // https://github.com/google/fonts/issues/1726
+ em {
+ transform: skewX(-14deg);
+ display: inline-block;
+ }
+ */
+ }
}
/* Spoiler stuff */
.mx_EventTile_spoiler {
cursor: pointer;
-}
-.mx_EventTile_spoiler_reason {
- color: $event-timestamp-color;
- font-size: $font-11px;
-}
+ .mx_EventTile_spoiler_reason {
+ color: $event-timestamp-color;
+ font-size: $font-11px;
+ }
-.mx_EventTile_spoiler_content {
- filter: blur(5px) saturate(0.1) sepia(1);
- transition-duration: 0.5s;
-}
+ .mx_EventTile_spoiler_content {
+ filter: blur(5px) saturate(0.1) sepia(1);
+ transition-duration: 0.5s;
+ }
-.mx_EventTile_spoiler.visible > .mx_EventTile_spoiler_content {
- filter: none;
+ &.visible > .mx_EventTile_spoiler_content {
+ filter: none;
+ }
}
.mx_RoomView_timeline_rr_enabled {
@@ -343,10 +433,6 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
// on ELS we need the margin to allow interaction with the expand/collapse button which is normally in the RR gutter
}
-.mx_DisambiguatedProfile {
- cursor: pointer;
-}
-
.mx_EventTile_bubbleContainer {
display: grid;
grid-template-columns: 1fr 100px;
@@ -389,23 +475,6 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
}
}
-.mx_EventTile_content .mx_EventTile_edited {
- user-select: none;
- font-size: $font-12px;
- color: $roomtopic-color;
- display: inline-block;
- margin-left: 9px;
- cursor: pointer;
-}
-
-.mx_EventTile_content .mx_EventTile_pendingModeration {
- user-select: none;
- font-size: $font-12px;
- color: $roomtopic-color;
- display: inline-block;
- margin-left: 9px;
-}
-
.mx_EventTile_e2eIcon {
position: relative;
width: 14px;
@@ -430,28 +499,23 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
}
&::before {
- mask-repeat: no-repeat;
- mask-position: center;
mask-size: 80%;
}
-}
-.mx_EventTile_e2eIcon_warning {
- &::after {
+ &.mx_EventTile_e2eIcon_warning,
+ &.mx_EventTile_e2eIcon_normal {
+ opacity: 1;
+ }
+
+ &.mx_EventTile_e2eIcon_warning::after {
mask-image: url('$(res)/img/e2e/warning.svg');
background-color: $alert;
}
- opacity: 1;
-}
-
-.mx_EventTile_e2eIcon_normal {
- &::after {
+ &.mx_EventTile_e2eIcon_normal::after {
mask-image: url('$(res)/img/e2e/normal.svg');
background-color: $header-panel-text-primary-color;
}
-
- opacity: 1;
}
/* Various markdown overrides */
@@ -482,49 +546,6 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
}
}
-.mx_EventTile_content .markdown-body {
- font-family: inherit !important;
- white-space: normal !important;
- line-height: inherit !important;
- color: inherit; // inherit the colour from the dark or light theme by default (but not for code blocks)
- font-size: $font-14px;
-
- pre,
- code {
- font-family: $monospace-font-family !important;
- background-color: $codeblock-background-color;
- }
-
- // this selector wrongly applies to code blocks too but we will unset it in the next one
- code {
- white-space: pre-wrap; // don't collapse spaces in inline code blocks
- }
-
- pre code {
- white-space: pre; // we want code blocks to be scrollable and not wrap
-
- >* {
- display: inline;
- }
- }
-
- pre {
- // have to use overlay rather than auto otherwise Linux and Windows
- // Chrome gets very confused about vertical spacing:
- // https://github.com/vector-im/vector-web/issues/754
- overflow-x: overlay;
- overflow-y: visible;
-
- code {
- background-color: transparent;
- }
-
- &::-webkit-scrollbar-corner {
- background: transparent;
- }
- }
-}
-
.mx_EventTile_lineNumbers {
float: left;
margin: 0 0.5em 0 -1.5em;
@@ -537,134 +558,101 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
}
}
-.mx_EventTile_collapsedCodeBlock {
- max-height: 30vh;
-}
-
.mx_EventTile:hover .mx_EventTile_body pre,
.mx_EventTile.focus-visible:focus-within .mx_EventTile_body pre {
border: 1px solid $tertiary-content;
}
-.mx_EventTile_pre_container {
- // For correct positioning of _copyButton (See TextualBody)
- position: relative;
-}
-
-// Inserted adjacent to blocks, (See TextualBody)
.mx_EventTile_button {
- position: absolute;
display: inline-block;
- visibility: hidden;
cursor: pointer;
- top: 8px;
- right: 8px;
- width: 19px;
- height: 19px;
- background-color: $message-action-bar-fg-color;
-}
-
-.mx_EventTile_buttonBottom {
- top: 33px;
}
.mx_EventTile_copyButton {
mask-image: url($copy-button-url);
}
-.mx_EventTile_collapseButton {
- mask-size: 75%;
+.mx_EventTile_collapseButton,
+.mx_EventTile_expandButton {
mask-position: center;
mask-repeat: no-repeat;
+}
+
+.mx_EventTile_collapseButton {
mask-image: url("$(res)/img/element-icons/minimise-collapse.svg");
}
.mx_EventTile_expandButton {
- mask-size: 75%;
- mask-position: center;
- mask-repeat: no-repeat;
mask-image: url("$(res)/img/element-icons/maximise-expand.svg");
}
-.mx_EventTile_body .mx_EventTile_pre_container:focus-within .mx_EventTile_copyButton,
-.mx_EventTile_body .mx_EventTile_pre_container:hover .mx_EventTile_copyButton,
-.mx_EventTile_body .mx_EventTile_pre_container:focus-within .mx_EventTile_collapseButton,
-.mx_EventTile_body .mx_EventTile_pre_container:hover .mx_EventTile_collapseButton,
-.mx_EventTile_body .mx_EventTile_pre_container:focus-within .mx_EventTile_expandButton,
-.mx_EventTile_body .mx_EventTile_pre_container:hover .mx_EventTile_expandButton {
- visibility: visible;
-}
-
-.mx_EventTile_content .markdown-body h1,
-.mx_EventTile_content .markdown-body h2,
-.mx_EventTile_content .markdown-body h3,
-.mx_EventTile_content .markdown-body h4,
-.mx_EventTile_content .markdown-body h5,
-.mx_EventTile_content .markdown-body h6 {
- font-family: inherit !important;
- color: inherit;
-}
+.mx_EventTile_body .mx_EventTile_pre_container {
+ // For correct positioning of _copyButton (See TextualBody)
+ position: relative;
-/* Make h1 and h2 the same size as h3. */
-.mx_EventTile_content .markdown-body h1,
-.mx_EventTile_content .markdown-body h2 {
- font-size: 1.5em;
- border-bottom: none !important; // override GFM
-}
+ &:focus-within,
+ &:hover {
+ .mx_EventTile_button {
+ visibility: visible;
+ }
+ }
-.mx_EventTile_content .markdown-body a {
- color: $accent-alt;
-}
+ .mx_EventTile_collapsedCodeBlock {
+ max-height: 30vh;
+ }
-.mx_EventTile_content .markdown-body blockquote {
- color: unset;
- margin: 0 0 16px;
- padding: 2px 10px;
- border-left: 2px solid $blockquote-bar-color;
- line-height: $font-18px;
-}
+ // Inserted adjacent to blocks, (See TextualBody)
+ .mx_EventTile_button {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ width: 19px;
+ height: 19px;
+ visibility: hidden;
+ background-color: $message-action-bar-fg-color;
-/*
-// actually, removing the Italic TTF provides
-// better results seemingly
+ &.mx_EventTile_buttonBottom {
+ top: 33px;
+ }
-// compensate for Nunito italics being terrible
-// https://github.com/google/fonts/issues/1726
-.mx_EventTile_content .markdown-body em {
- transform: skewX(-14deg);
- display: inline-block;
+ &.mx_EventTile_collapseButton,
+ &.mx_EventTile_expandButton {
+ mask-size: 75%;
+ }
+ }
}
-*/
/* end of overrides */
.mx_EventTile_keyRequestInfo {
font-size: $font-12px;
-}
-.mx_EventTile_keyRequestInfo_text {
- opacity: 0.5;
-}
+ .mx_EventTile_keyRequestInfo_text {
+ opacity: 0.5;
-.mx_EventTile_keyRequestInfo_text .mx_AccessibleButton {
- @mixin ButtonResetDefault;
- color: $primary-content;
- text-decoration: underline;
- cursor: pointer;
+ .mx_AccessibleButton {
+ color: $primary-content;
+ text-decoration: underline;
+
+ &.mx_AccessibleButton_kind_link_inline {
+ padding: 0;
+ }
+ }
+ }
}
.mx_EventTile_keyRequestInfo_tooltip_contents p {
text-align: auto;
margin-left: 3px;
margin-right: 3px;
-}
-.mx_EventTile_keyRequestInfo_tooltip_contents p:first-child {
- margin-top: 0px;
-}
+ &:first-child {
+ margin-top: 0px;
+ }
-.mx_EventTile_keyRequestInfo_tooltip_contents p:last-child {
- margin-bottom: 0px;
+ &:last-child {
+ margin-bottom: 0px;
+ }
}
.mx_EventTile_tileError {
@@ -785,12 +773,23 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
&::before {
content: "";
position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- /* enough to cover all sibling elements */
- z-index: 10;
+ inset: 0;
+ }
+
+ // Display notification dot
+ &[data-notification]::before {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ inset: 14px 8px auto auto; // 14px: align the dot with the timestamp row
+ }
+
+ &[data-notification=total]::before {
+ background-color: $room-icon-unread-color;
+ }
+
+ &[data-notification=highlight]::before {
+ background-color: $alert;
}
&:last-child {
@@ -851,15 +850,7 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
.mx_ThreadView {
--ThreadView_group_spacing-start: 56px; // 56px: 64px - 8px (padding)
-
- display: flex;
- flex-direction: column;
- max-height: 100%;
-
- .mx_ThreadView_List {
- flex: 1;
- overflow: scroll;
- }
+ --ThreadView_group_spacing-end: 8px; // same as padding
.mx_EventTile_roomName {
display: none;
@@ -870,20 +861,21 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
flex-direction: column;
.mx_EventTile_line {
- padding-top: 2px;
- padding-bottom: 2px;
- padding-left: 0;
- order: 10 !important;
+ padding-top: var(--BaseCard_EventTile_line-padding-block);
+ padding-bottom: var(--BaseCard_EventTile_line-padding-block);
}
- .mx_MessageTimestamp {
- font-size: $font-10px;
+ .mx_EventTile_line,
+ .mx_ReactionsRow {
+ padding-inline-start: 0; // Cancel inherited padding value for event message and reactions row
}
.mx_ReactionsRow {
- order: 999;
- padding-left: 0;
- padding-right: 0;
+ padding-inline-end: 0;
+ }
+
+ .mx_MessageTimestamp {
+ font-size: $font-10px;
}
&:not([data-layout=bubble]) {
@@ -892,28 +884,31 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
.mx_EventTile_line {
padding-top: var(--BaseCard_EventTile_line-padding-block);
padding-bottom: var(--BaseCard_EventTile_line-padding-block);
+
+ .mx_EventTile_content {
+ &.mx_EditMessageComposer {
+ padding-inline-start: 0; // align start of first letter with that of the event body
+ }
+ }
}
}
- }
-
- .mx_EventTile[data-layout=bubble] {
- margin-left: 36px;
- margin-right: 36px;
- .mx_EventTile_line.mx_EventTile_mediaLine {
- padding: 0 !important;
- max-width: 100%;
+ &[data-layout=bubble] {
+ margin-inline-start: var(--BaseCard_EventTile-spacing-horizontal);
+ margin-inline-end: var(--BaseCard_EventTile-spacing-horizontal);
- .mx_MFileBody {
- width: 100%;
+ .mx_EventTile_line.mx_EventTile_mediaLine {
+ padding-block: 0;
+ padding-inline-start: 0;
+ max-width: var(--EventBubbleTile_line-max-width);
}
- }
- &[data-self=true] {
- align-items: flex-end;
+ &[data-self=true] {
+ align-items: flex-end;
- .mx_EventTile_line.mx_EventTile_mediaLine {
- margin: 0 -13px 0 0; // align with normal messages
+ .mx_EventTile_line.mx_EventTile_mediaLine {
+ margin: 0 var(--EventBubbleTile_line-margin-inline-end) 0 0; // align with normal messages
+ }
}
}
}
@@ -930,7 +925,7 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
.mx_ReplyChain_wrapper,
.mx_ReactionsRow {
margin-inline-start: var(--ThreadView_group_spacing-start);
- margin-right: 8px;
+ margin-inline-end: var(--ThreadView_group_spacing-end);
.mx_EventTile_content,
.mx_HiddenBody,
@@ -941,9 +936,23 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
}
.mx_ReplyChain_wrapper {
- .mx_MLocationBody {
- margin-inline-start: 0;
- margin-inline-end: 0;
+ .mx_MLocationBody,
+ .mx_UnknownBody { // Error message inside ReplyTile
+ margin-inline: unset;
+ }
+ }
+
+ .mx_EventTile_mediaLine {
+ // such as MImageBody
+ > div,
+ > span {
+ margin-inline-start: var(--ThreadView_group_spacing-start);
+ margin-inline-end: var(--ThreadView_group_spacing-end);
+ }
+
+ // such as MAudioBody and MFileBody
+ > span {
+ display: block; // Apply the margin declarations to span element
}
}
@@ -970,32 +979,5 @@ $threadInfoLineHeight: calc(2 * $font-12px); // See: _commons.scss
}
}
}
-
- .mx_EventTile_mediaLine {
- padding-inline-start: var(--ThreadView_group_spacing-start);
- }
- }
-
- .mx_EventTile_mediaLine {
- padding-left: 36px;
- padding-right: 50px;
-
- .mx_MImageBody {
- margin: 0;
- padding: 0;
- }
- }
-
- .mx_MessageComposer_sendMessage {
- margin-right: 0;
- }
-
- .mx_EditMessageComposer {
- margin-left: 30px !important; // align start of first letter with that of the event body
- }
-
- .mx_EditMessageComposer_buttons {
- padding-right: 11px; // align with right edge of input
- margin-right: 0; // align with right edge of background
}
}
diff --git a/res/css/views/rooms/_ReplyTile.scss b/res/css/views/rooms/_ReplyTile.scss
index 6bada1e998f..9b54b449941 100644
--- a/res/css/views/rooms/_ReplyTile.scss
+++ b/res/css/views/rooms/_ReplyTile.scss
@@ -112,10 +112,5 @@ limitations under the License.
padding: 0;
margin: 0;
margin-bottom: $font-3px;
-
- // truncate long display names
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
}
}
diff --git a/res/css/views/voip/CallView/_CallViewButtons.scss b/res/css/views/voip/CallView/_CallViewButtons.scss
index 4c375ee2222..91d173bc072 100644
--- a/res/css/views/voip/CallView/_CallViewButtons.scss
+++ b/res/css/views/voip/CallView/_CallViewButtons.scss
@@ -24,6 +24,8 @@ limitations under the License.
}
.mx_CallViewButtons {
+ --CallViewButtons_dropdownButton-size: 16px;
+
position: absolute;
display: flex;
justify-content: center;
@@ -65,8 +67,8 @@ limitations under the License.
}
&.mx_CallViewButtons_dropdownButton {
- width: 16px;
- height: 16px;
+ width: var(--CallViewButtons_dropdownButton-size);
+ height: var(--CallViewButtons_dropdownButton-size);
position: absolute;
right: 0;
diff --git a/res/css/views/voip/_CallView.scss b/res/css/views/voip/_CallView.scss
index e31f42727a0..c83e143b1b8 100644
--- a/res/css/views/voip/_CallView.scss
+++ b/res/css/views/voip/_CallView.scss
@@ -165,6 +165,11 @@ border-radius: $border-radius-8px;
width: 34px;
height: 34px;
+ &.mx_CallViewButtons_dropdownButton {
+ width: var(--CallViewButtons_dropdownButton-size);
+ height: var(--CallViewButtons_dropdownButton-size);
+ }
+
&::before {
width: 22px;
height: 22px;
diff --git a/res/img/element-icons/child-relationship.svg b/res/img/element-icons/child-relationship.svg
new file mode 100644
index 00000000000..5a848c0d972
--- /dev/null
+++ b/res/img/element-icons/child-relationship.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/res/img/external-link.svg b/res/img/external-link.svg
index 459e790fe31..cae1446a687 100644
--- a/res/img/external-link.svg
+++ b/res/img/external-link.svg
@@ -1,5 +1,5 @@
-
+
diff --git a/res/img/location/map.svg b/res/img/location/map.svg
index 67be3a35ad4..9719d8f6142 100644
--- a/res/img/location/map.svg
+++ b/res/img/location/map.svg
@@ -1,9 +1,9 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/themes/legacy-light/css/_legacy-light.scss b/res/themes/legacy-light/css/_legacy-light.scss
index 3825b9bd987..5c3231f1d80 100644
--- a/res/themes/legacy-light/css/_legacy-light.scss
+++ b/res/themes/legacy-light/css/_legacy-light.scss
@@ -1,16 +1,33 @@
-// XXX: check this?
-/* Nunito lacks combining diacritics, so these will fall through
- to the next font. Helevetica's diacritics however do not combine
+/* Nunito and Inter lacks combining diacritics, so these will fall through
+ to the next font. Helevetica's diacritics sometimes do not combine
nicely (on OSX, at least) and result in a huge horizontal mess.
- Arial empirically gets it right, hence prioritising Arial here. */
+ Arial empirically gets it right, hence prioritising Arial here.
+ We also include STIXGeneral explicitly to support a wider range
+ of combining diacritics (Chrome fails without it, as per
+ https://bugs.chromium.org/p/chromium/issues/detail?id=1328898) */
/* We fall through to Twemoji for emoji rather than falling through
to native Emoji fonts (if any) to ensure cross-browser consistency */
/* Noto Color Emoji contains digits, in fixed-width, therefore causing
digits in flowed text to stand out.
TODO: Consider putting all emoji fonts to the end rather than the front. */
-$font-family: 'Inter', 'Twemoji', 'Apple Color Emoji', 'Segoe UI Emoji', 'Arial', 'Helvetica', sans-serif, 'Noto Color Emoji';
-
-$monospace-font-family: 'Inconsolata', 'Twemoji', 'Apple Color Emoji', 'Segoe UI Emoji', 'Courier', monospace, 'Noto Color Emoji';
+$font-family: 'Inter',
+'Twemoji',
+'Apple Color Emoji',
+'Segoe UI Emoji',
+'STIXGeneral',
+'Arial',
+'Helvetica',
+sans-serif,
+'Noto Color Emoji';
+
+$monospace-font-family: 'Inconsolata',
+'Twemoji',
+'Apple Color Emoji',
+'Segoe UI Emoji',
+'STIXGeneral',
+'Courier',
+monospace,
+'Noto Color Emoji';
// unified palette
// try to use these colors when possible
diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss
index 1b32d971396..5ba40729baa 100644
--- a/res/themes/light/css/_light.scss
+++ b/res/themes/light/css/_light.scss
@@ -1,8 +1,10 @@
-// XXX: check this?
-/* Nunito lacks combining diacritics, so these will fall through
- to the next font. Helevetica's diacritics however do not combine
+/* Nunito and Inter lacks combining diacritics, so these will fall through
+ to the next font. Helevetica's diacritics sometimes do not combine
nicely (on OSX, at least) and result in a huge horizontal mess.
- Arial empirically gets it right, hence prioritising Arial here. */
+ Arial empirically gets it right, hence prioritising Arial here.
+ We also include STIXGeneral explicitly to support a wider range
+ of combining diacritics (Chrome fails without it, as per
+ https://bugs.chromium.org/p/chromium/issues/detail?id=1328898) */
/* We fall through to Twemoji for emoji rather than falling through
to native Emoji fonts (if any) to ensure cross-browser consistency */
/* Noto Color Emoji contains digits, in fixed-width, therefore causing
@@ -12,6 +14,7 @@ $font-family: 'Inter',
'Twemoji',
'Apple Color Emoji',
'Segoe UI Emoji',
+'STIXGeneral',
'Arial',
'Helvetica',
sans-serif,
@@ -21,6 +24,7 @@ $monospace-font-family: 'Inconsolata',
'Twemoji',
'Apple Color Emoji',
'Segoe UI Emoji',
+'STIXGeneral',
'Courier',
monospace,
'Noto Color Emoji';
diff --git a/src/Analytics.tsx b/src/Analytics.tsx
index 639950574df..0249c6ad1a2 100644
--- a/src/Analytics.tsx
+++ b/src/Analytics.tsx
@@ -18,6 +18,7 @@ limitations under the License.
import React from 'react';
import { logger } from "matrix-js-sdk/src/logger";
import { Optional } from "matrix-events-sdk";
+import { randomString } from 'matrix-js-sdk/src/randomstring';
import { getCurrentLanguage, _t, _td, IVariables } from './languageHandler';
import PlatformPeg from './PlatformPeg';
@@ -155,9 +156,9 @@ const LAST_VISIT_TS_KEY = "mx_Riot_Analytics_lvts";
function getUid(): string {
try {
- let data = localStorage && localStorage.getItem(UID_KEY);
+ let data = localStorage?.getItem(UID_KEY);
if (!data && localStorage) {
- localStorage.setItem(UID_KEY, data = [...Array(16)].map(() => Math.random().toString(16)[2]).join(''));
+ localStorage.setItem(UID_KEY, data = randomString(16));
}
return data;
} catch (e) {
diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts
index 95f34597635..9de1122430b 100644
--- a/src/BasePlatform.ts
+++ b/src/BasePlatform.ts
@@ -70,7 +70,7 @@ export default abstract class BasePlatform {
protected onAction = (payload: ActionPayload) => {
switch (payload.action) {
case 'on_client_not_viable':
- case 'on_logged_out':
+ case Action.OnLoggedOut:
this.setNotificationCount(0);
break;
}
@@ -291,6 +291,18 @@ export default abstract class BasePlatform {
throw new Error("Unimplemented");
}
+ public supportsTogglingHardwareAcceleration(): boolean {
+ return false;
+ }
+
+ public async getHardwareAccelerationEnabled(): Promise {
+ return true;
+ }
+
+ public async setHardwareAccelerationEnabled(enabled: boolean): Promise {
+ throw new Error("Unimplemented");
+ }
+
/**
* Get our platform specific EventIndexManager.
*
diff --git a/src/ContentMessages.ts b/src/ContentMessages.ts
index 7cb0ad1db9c..f7b12f53e3f 100644
--- a/src/ContentMessages.ts
+++ b/src/ContentMessages.ts
@@ -23,7 +23,7 @@ import encrypt from "matrix-encrypt-attachment";
import extractPngChunks from "png-chunks-extract";
import { IAbortablePromise, IImageInfo } from "matrix-js-sdk/src/@types/partials";
import { logger } from "matrix-js-sdk/src/logger";
-import { IEventRelation, ISendEventResponse, MatrixEvent } from "matrix-js-sdk/src/matrix";
+import { IEventRelation, ISendEventResponse, MatrixError, MatrixEvent } from "matrix-js-sdk/src/matrix";
import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread";
import { IEncryptedFile, IMediaEventInfo } from "./customisations/models/IMediaEventContent";
@@ -64,10 +64,7 @@ interface IMediaConfig {
interface IContent {
body: string;
msgtype: string;
- info: {
- size: number;
- mimetype?: string;
- };
+ info: IMediaEventInfo;
file?: string;
url?: string;
}
@@ -129,6 +126,9 @@ const IMAGE_THUMBNAIL_MIN_REDUCTION_PERCENT = 0.1; // 10%
// We don't apply these thresholds to video thumbnails as a poster image is always useful
// and videos tend to be much larger.
+// Image mime types for which to always include a thumbnail for even if it is larger than the input for wider support.
+const ALWAYS_INCLUDE_THUMBNAIL = ["image/avif", "image/webp"];
+
/**
* Read the metadata for an image file and create and upload a thumbnail of the image.
*
@@ -137,7 +137,11 @@ const IMAGE_THUMBNAIL_MIN_REDUCTION_PERCENT = 0.1; // 10%
* @param {File} imageFile The image to read and thumbnail.
* @return {Promise} A promise that resolves with the attachment info.
*/
-async function infoForImageFile(matrixClient: MatrixClient, roomId: string, imageFile: File) {
+async function infoForImageFile(
+ matrixClient: MatrixClient,
+ roomId: string,
+ imageFile: File,
+): Promise> {
let thumbnailType = "image/png";
if (imageFile.type === "image/jpeg") {
thumbnailType = "image/jpeg";
@@ -149,7 +153,7 @@ async function infoForImageFile(matrixClient: MatrixClient, roomId: string, imag
const imageInfo = result.info;
// For lesser supported image types, always include the thumbnail even if it is larger
- if (!["image/avif", "image/webp"].includes(imageFile.type)) {
+ if (!ALWAYS_INCLUDE_THUMBNAIL.includes(imageFile.type)) {
// we do all sizing checks here because we still rely on thumbnail generation for making a blurhash from.
const sizeDifference = imageFile.size - imageInfo.thumbnail_info.size;
if (
@@ -178,7 +182,7 @@ async function infoForImageFile(matrixClient: MatrixClient, roomId: string, imag
* @param {File} videoFile The file to load in an video element.
* @return {Promise} A promise that resolves with the video image element.
*/
-function loadVideoElement(videoFile): Promise {
+function loadVideoElement(videoFile: File): Promise {
return new Promise((resolve, reject) => {
// Load the file into an html element
const video = document.createElement("video");
@@ -224,7 +228,11 @@ function loadVideoElement(videoFile): Promise {
* @param {File} videoFile The video to read and thumbnail.
* @return {Promise} A promise that resolves with the attachment info.
*/
-function infoForVideoFile(matrixClient, roomId, videoFile) {
+function infoForVideoFile(
+ matrixClient: MatrixClient,
+ roomId: string,
+ videoFile: File,
+): Promise> {
const thumbnailType = "image/jpeg";
let videoInfo: Partial;
@@ -449,7 +457,7 @@ export default class ContentMessages {
});
}
- public cancelUpload(promise: Promise, matrixClient: MatrixClient): void {
+ public cancelUpload(promise: IAbortablePromise, matrixClient: MatrixClient): void {
const upload = this.inprogress.find(item => item.promise === promise);
if (upload) {
upload.canceled = true;
@@ -466,12 +474,12 @@ export default class ContentMessages {
replyToEvent: MatrixEvent | undefined,
promBefore: Promise,
) {
- const content: IContent = {
+ const content: Omit & { info: Partial } = {
body: file.name || 'Attachment',
info: {
size: file.size,
},
- msgtype: "", // set later
+ msgtype: MsgType.File, // set more specifically later
};
attachRelation(content, relation);
@@ -497,6 +505,7 @@ export default class ContentMessages {
Object.assign(content.info, imageInfo);
resolve();
}, (e) => {
+ // Failed to thumbnail, fall back to uploading an m.file
logger.error(e);
content.msgtype = MsgType.File;
resolve();
@@ -510,6 +519,8 @@ export default class ContentMessages {
Object.assign(content.info, videoInfo);
resolve();
}, (e) => {
+ // Failed to thumbnail, fall back to uploading an m.file
+ logger.error(e);
content.msgtype = MsgType.File;
resolve();
});
@@ -541,8 +552,8 @@ export default class ContentMessages {
dis.dispatch({ action: Action.UploadProgress, upload });
}
- let error;
- return prom.then(function() {
+ let error: MatrixError;
+ return prom.then(() => {
if (upload.canceled) throw new UploadCanceledError();
// XXX: upload.promise must be the promise that
// is returned by uploadFile as it has an abort()
@@ -567,11 +578,11 @@ export default class ContentMessages {
});
}
return prom;
- }, function(err) {
+ }, function(err: MatrixError) {
error = err;
if (!upload.canceled) {
let desc = _t("The file '%(fileName)s' failed to upload.", { fileName: upload.fileName });
- if (err.http_status === 413) {
+ if (err.httpStatus === 413) {
desc = _t(
"The file '%(fileName)s' exceeds this homeserver's size limit for uploads",
{ fileName: upload.fileName },
@@ -593,7 +604,7 @@ export default class ContentMessages {
// 413: File was too big or upset the server in some way:
// clear the media size limit so we fetch it again next time
// we try to upload
- if (error && error.http_status === 413) {
+ if (error?.httpStatus === 413) {
this.mediaConfig = null;
}
dis.dispatch({ action: Action.UploadFailed, upload, error });
@@ -613,7 +624,7 @@ export default class ContentMessages {
return true;
}
- private ensureMediaConfigFetched(matrixClient: MatrixClient) {
+ private ensureMediaConfigFetched(matrixClient: MatrixClient): Promise {
if (this.mediaConfig !== null) return;
logger.log("[Media Config] Fetching");
diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts
index adba51d1352..cf9af5befc4 100644
--- a/src/DeviceListener.ts
+++ b/src/DeviceListener.ts
@@ -18,6 +18,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { logger } from "matrix-js-sdk/src/logger";
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
import { ClientEvent, EventType, RoomStateEvent } from "matrix-js-sdk/src/matrix";
+import { SyncState } from "matrix-js-sdk/src/sync";
import { MatrixClientPeg } from './MatrixClientPeg';
import dis from "./dispatcher/dispatcher";
@@ -58,13 +59,15 @@ export default class DeviceListener {
private ourDeviceIdsAtStart: Set = null;
// The set of device IDs we're currently displaying toasts for
private displayingToastsForDeviceIds = new Set();
+ private running = false;
- static sharedInstance() {
+ public static sharedInstance() {
if (!window.mxDeviceListener) window.mxDeviceListener = new DeviceListener();
return window.mxDeviceListener;
}
- start() {
+ public start() {
+ this.running = true;
MatrixClientPeg.get().on(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices);
MatrixClientPeg.get().on(CryptoEvent.DevicesUpdated, this.onDevicesUpdated);
MatrixClientPeg.get().on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
@@ -77,7 +80,8 @@ export default class DeviceListener {
this.recheck();
}
- stop() {
+ public stop() {
+ this.running = false;
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices);
MatrixClientPeg.get().removeListener(CryptoEvent.DevicesUpdated, this.onDevicesUpdated);
@@ -109,7 +113,7 @@ export default class DeviceListener {
*
* @param {String[]} deviceIds List of device IDs to dismiss notifications for
*/
- async dismissUnverifiedSessions(deviceIds: Iterable) {
+ public async dismissUnverifiedSessions(deviceIds: Iterable) {
logger.log("Dismissing unverified sessions: " + Array.from(deviceIds).join(','));
for (const d of deviceIds) {
this.dismissed.add(d);
@@ -118,7 +122,7 @@ export default class DeviceListener {
this.recheck();
}
- dismissEncryptionSetup() {
+ public dismissEncryptionSetup() {
this.dismissedThisDeviceToast = true;
this.recheck();
}
@@ -179,8 +183,10 @@ export default class DeviceListener {
}
};
- private onSync = (state, prevState) => {
- if (state === 'PREPARED' && prevState === null) this.recheck();
+ private onSync = (state: SyncState, prevState?: SyncState) => {
+ if (state === 'PREPARED' && prevState === null) {
+ this.recheck();
+ }
};
private onRoomStateEvents = (ev: MatrixEvent) => {
@@ -192,7 +198,7 @@ export default class DeviceListener {
};
private onAction = ({ action }: ActionPayload) => {
- if (action !== "on_logged_in") return;
+ if (action !== Action.OnLoggedIn) return;
this.recheck();
};
@@ -217,6 +223,7 @@ export default class DeviceListener {
}
private async recheck() {
+ if (!this.running) return; // we have been stopped
const cli = MatrixClientPeg.get();
if (!(await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing"))) return;
diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts
index 5d864cc1cc7..e663a410461 100644
--- a/src/Lifecycle.ts
+++ b/src/Lifecycle.ts
@@ -168,7 +168,7 @@ export async function loadSession(opts: ILoadSessionOpts = {}): Promise
* Gets the user ID of the persisted session, if one exists. This does not validate
* that the user's credentials still work, just that they exist and that a user ID
* is associated with them. The session is not loaded.
- * @returns {[String, bool]} The persisted session's owner and whether the stored
+ * @returns {[string, boolean]} The persisted session's owner and whether the stored
* session is for a guest user, if an owner exists. If there is no stored session,
* return [null, null].
*/
@@ -494,7 +494,7 @@ async function handleLoadSessionFailure(e: Error): Promise {
* Also stops the old MatrixClient and clears old credentials/etc out of
* storage before starting the new client.
*
- * @param {MatrixClientCreds} credentials The credentials to use
+ * @param {IMatrixClientCreds} credentials The credentials to use
*
* @returns {Promise} promise which resolves to the new MatrixClient once it has been started
*/
@@ -525,7 +525,7 @@ export async function setLoggedIn(credentials: IMatrixClientCreds): Promise onLoggedOut());
return;
}
@@ -739,19 +739,17 @@ export function logout(): void {
_isLoggingOut = true;
const client = MatrixClientPeg.get();
PlatformPeg.get().destroyPickleKey(client.getUserId(), client.getDeviceId());
- client.logout().then(onLoggedOut,
- (err) => {
- // Just throwing an error here is going to be very unhelpful
- // if you're trying to log out because your server's down and
- // you want to log into a different server, so just forget the
- // access token. It's annoying that this will leave the access
- // token still valid, but we should fix this by having access
- // tokens expire (and if you really think you've been compromised,
- // change your password).
- logger.log("Failed to call logout API: token will not be invalidated");
- onLoggedOut();
- },
- );
+ client.logout(undefined, true).then(onLoggedOut, (err) => {
+ // Just throwing an error here is going to be very unhelpful
+ // if you're trying to log out because your server's down and
+ // you want to log into a different server, so just forget the
+ // access token. It's annoying that this will leave the access
+ // token still valid, but we should fix this by having access
+ // tokens expire (and if you really think you've been compromised,
+ // change your password).
+ logger.warn("Failed to call logout API: token will not be invalidated", err);
+ onLoggedOut();
+ });
}
export function softLogout(): void {
@@ -856,21 +854,25 @@ async function startMatrixClient(startSyncing = true): Promise {
* storage. Used after a session has been logged out.
*/
export async function onLoggedOut(): Promise {
- _isLoggingOut = false;
- // Ensure that we dispatch a view change **before** stopping the client so
- // so that React components unmount first. This avoids React soft crashes
+ // Ensure that we dispatch a view change **before** stopping the client,
+ // that React components unmount first. This avoids React soft crashes
// that can occur when components try to use a null client.
- dis.dispatch({ action: 'on_logged_out' }, true);
+ dis.fire(Action.OnLoggedOut, true);
stopMatrixClient();
await clearStorage({ deleteEverything: true });
LifecycleCustomisations.onLoggedOutAndStorageCleared?.();
- // Do this last so we can make sure all storage has been cleared and all
+ // Do this last, so we can make sure all storage has been cleared and all
// customisations got the memo.
if (SdkConfig.get().logout_redirect_url) {
logger.log("Redirecting to external provider to finish logout");
- window.location.href = SdkConfig.get().logout_redirect_url;
+ // XXX: Defer this so that it doesn't race with MatrixChat unmounting the world by going to /#/login
+ setTimeout(() => {
+ window.location.href = SdkConfig.get().logout_redirect_url;
+ }, 100);
}
+ // Do this last to prevent racing `stopMatrixClient` and `on_logged_out` with MatrixChat handling Session.logged_out
+ _isLoggingOut = false;
}
/**
@@ -908,9 +910,7 @@ async function clearStorage(opts?: { deleteEverything?: boolean }): Promise, roomId: string): void {
const widgetUrl = event.data.url;
const widgetName = event.data.name; // optional
const widgetData = event.data.data; // optional
+ const widgetAvatarUrl = event.data.avatar_url; // optional
const userWidget = event.data.userWidget;
// both adding/removing widgets need these checks
@@ -337,6 +339,14 @@ function setWidget(event: MessageEvent, roomId: string): void {
sendError(event, _t("Unable to create widget."), new Error("Optional field 'data' must be an Object."));
return;
}
+ if (widgetAvatarUrl !== undefined && typeof widgetAvatarUrl !== 'string') {
+ sendError(
+ event,
+ _t("Unable to create widget."),
+ new Error("Optional field 'avatar_url' must be a string."),
+ );
+ return;
+ }
if (typeof widgetType !== 'string') {
sendError(event, _t("Unable to create widget."), new Error("Field 'type' must be a string."));
return;
@@ -364,13 +374,14 @@ function setWidget(event: MessageEvent, roomId: string): void {
if (!roomId) {
sendError(event, _t('Missing roomId.'), null);
}
- WidgetUtils.setRoomWidget(roomId, widgetId, widgetType, widgetUrl, widgetName, widgetData).then(() => {
- sendResponse(event, {
- success: true,
+ WidgetUtils.setRoomWidget(roomId, widgetId, widgetType, widgetUrl, widgetName, widgetData, widgetAvatarUrl)
+ .then(() => {
+ sendResponse(event, {
+ success: true,
+ });
+ }, (err) => {
+ sendError(event, _t('Failed to send request.'), err);
});
- }, (err) => {
- sendError(event, _t('Failed to send request.'), err);
- });
}
}
diff --git a/src/SecurityManager.ts b/src/SecurityManager.ts
index c67e8ec8d96..50b5f0c950a 100644
--- a/src/SecurityManager.ts
+++ b/src/SecurityManager.ts
@@ -257,7 +257,7 @@ async function onSecretRequested(
if (userId !== client.getUserId()) {
return;
}
- if (!deviceTrust || !deviceTrust.isVerified()) {
+ if (!deviceTrust?.isVerified()) {
logger.log(`Ignoring secret request from untrusted device ${deviceId}`);
return;
}
@@ -296,7 +296,7 @@ export const crossSigningCallbacks: ICryptoCallbacks = {
};
export async function promptForBackupPassphrase(): Promise {
- let key;
+ let key: Uint8Array;
const { finished } = Modal.createTrackedDialog('Restore Backup', '', RestoreKeyBackupDialog, {
showSummary: false, keyCallback: k => key = k,
diff --git a/src/actions/MatrixActionCreators.ts b/src/actions/MatrixActionCreators.ts
index b8893763361..a307e5b25ed 100644
--- a/src/actions/MatrixActionCreators.ts
+++ b/src/actions/MatrixActionCreators.ts
@@ -18,6 +18,7 @@ import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client";
import { MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event";
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import { IRoomTimelineData } from "matrix-js-sdk/src/models/event-timeline-set";
+import { RoomState, RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import dis from "../dispatcher/dispatcher";
import { ActionPayload } from "../dispatcher/payloads";
@@ -175,6 +176,21 @@ export interface IRoomTimelineActionPayload extends Pick {
+ action: 'MatrixActions.RoomState.events';
+ event: MatrixEvent;
+ state: RoomState;
+ lastStateEvent: MatrixEvent | null;
+}
+
/**
* Create a MatrixActions.Room.timeline action that represents a
* MatrixClient `Room.timeline` matrix event, emitted when an event
@@ -210,6 +226,31 @@ function createRoomTimelineAction(
};
}
+/**
+ * Create a MatrixActions.Room.timeline action that represents a
+ * MatrixClient `Room.timeline` matrix event, emitted when an event
+ * is added to or removed from a timeline of a room.
+ *
+ * @param {MatrixClient} matrixClient the matrix client.
+ * @param {MatrixEvent} event the state event received
+ * @param {RoomState} state the room state into which the event was applied
+ * @param {MatrixEvent | null} lastStateEvent the previous value for this (event-type, state-key) tuple in room state
+ * @returns {IRoomStateEventsActionPayload} an action of type `MatrixActions.RoomState.events`.
+ */
+function createRoomStateEventsAction(
+ matrixClient: MatrixClient,
+ event: MatrixEvent,
+ state: RoomState,
+ lastStateEvent: MatrixEvent | null,
+): IRoomStateEventsActionPayload {
+ return {
+ action: 'MatrixActions.RoomState.events',
+ event,
+ state,
+ lastStateEvent,
+ };
+}
+
/**
* @typedef RoomMembershipAction
* @type {Object}
@@ -312,6 +353,7 @@ export default {
addMatrixClientListener(matrixClient, RoomEvent.Timeline, createRoomTimelineAction);
addMatrixClientListener(matrixClient, RoomEvent.MyMembership, createSelfMembershipAction);
addMatrixClientListener(matrixClient, MatrixEventEvent.Decrypted, createEventDecryptedAction);
+ addMatrixClientListener(matrixClient, RoomStateEvent.Events, createRoomStateEventsAction);
},
/**
diff --git a/src/actions/RoomListActions.ts b/src/actions/RoomListActions.ts
index 7860e1b2eee..696403aca82 100644
--- a/src/actions/RoomListActions.ts
+++ b/src/actions/RoomListActions.ts
@@ -90,9 +90,9 @@ export default class RoomListActions {
return Rooms.guessAndSetDMRoom(
room, newTag === DefaultTagID.DM,
).catch((err) => {
- logger.error("Failed to set direct chat tag " + err);
- Modal.createTrackedDialog('Failed to set direct chat tag', '', ErrorDialog, {
- title: _t('Failed to set direct chat tag'),
+ logger.error("Failed to set DM tag " + err);
+ Modal.createTrackedDialog('Failed to set direct message tag', '', ErrorDialog, {
+ title: _t('Failed to set direct message tag'),
description: ((err && err.message) ? err.message : _t('Operation failed')),
});
});
diff --git a/src/components/structures/InteractiveAuth.tsx b/src/components/structures/InteractiveAuth.tsx
index b42e65d57fb..4342355c74c 100644
--- a/src/components/structures/InteractiveAuth.tsx
+++ b/src/components/structures/InteractiveAuth.tsx
@@ -31,6 +31,17 @@ import Spinner from "../views/elements/Spinner";
export const ERROR_USER_CANCELLED = new Error("User cancelled auth session");
+type InteractiveAuthCallbackSuccess = (
+ success: true,
+ response: IAuthData,
+ extra?: { emailSid?: string, clientSecret?: string }
+) => void;
+type InteractiveAuthCallbackFailure = (
+ success: false,
+ response: IAuthData | Error,
+) => void;
+export type InteractiveAuthCallback = InteractiveAuthCallbackSuccess & InteractiveAuthCallbackFailure;
+
interface IProps {
// matrix client to use for UI auth requests
matrixClient: MatrixClient;
@@ -66,11 +77,7 @@ interface IProps {
// the auth session.
// * clientSecret {string} The client secret used in auth
// sessions with the ID server.
- onAuthFinished(
- status: boolean,
- result: IAuthData | Error,
- extra?: { emailSid?: string, clientSecret?: string },
- ): void;
+ onAuthFinished: InteractiveAuthCallback;
// As js-sdk interactive-auth
requestEmailToken?(email: string, secret: string, attempt: number, session: string): Promise<{ sid: string }>;
// Called when the stage changes, or the stage's phase changes. First
diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx
index 18061855506..87137ef050c 100644
--- a/src/components/structures/MatrixChat.tsx
+++ b/src/components/structures/MatrixChat.tsx
@@ -132,6 +132,7 @@ import { IConfigOptions } from "../../IConfigOptions";
import { SnakedObject } from "../../utils/SnakedObject";
import { leaveRoomBehaviour } from "../../utils/leave-behaviour";
import VideoChannelStore from "../../stores/VideoChannelStore";
+import { IRoomStateEventsActionPayload } from "../../actions/MatrixActionCreators";
// legacy export
export { default as Views } from "../../Views";
@@ -652,6 +653,20 @@ export default class MatrixChat extends React.PureComponent {
case 'view_user_info':
this.viewUser(payload.userId, payload.subAction);
break;
+ case "MatrixActions.RoomState.events": {
+ const event = (payload as IRoomStateEventsActionPayload).event;
+ if (event.getType() === EventType.RoomCanonicalAlias &&
+ event.getRoomId() === this.state.currentRoomId
+ ) {
+ // re-view the current room so we can update alias/id in the URL properly
+ this.viewRoom({
+ action: Action.ViewRoom,
+ room_id: this.state.currentRoomId,
+ metricsTrigger: undefined, // room doesn't change
+ });
+ }
+ break;
+ }
case Action.ViewRoom: {
// Takes either a room ID or room alias: if switching to a room the client is already
// known to be in (eg. user clicks on a room in the recents panel), supply the ID
@@ -744,7 +759,7 @@ export default class MatrixChat extends React.PureComponent {
case Action.OpenDialPad:
Modal.createTrackedDialog('Dial pad', '', DialPadModal, {}, "mx_Dialog_dialPadWrapper");
break;
- case 'on_logged_in':
+ case Action.OnLoggedIn:
if (
// Skip this handling for token login as that always calls onLoggedIn itself
!this.tokenLogin &&
@@ -760,7 +775,7 @@ export default class MatrixChat extends React.PureComponent {
case 'on_client_not_viable':
this.onSoftLogout();
break;
- case 'on_logged_out':
+ case Action.OnLoggedOut:
this.onLoggedOut();
break;
case 'will_start_client':
@@ -892,9 +907,7 @@ export default class MatrixChat extends React.PureComponent {
// Store this as the ID of the last room accessed. This is so that we can
// persist which room is being stored across refreshes and browser quits.
- if (localStorage) {
- localStorage.setItem('mx_last_room_id', room.roomId);
- }
+ localStorage?.setItem('mx_last_room_id', room.roomId);
}
// If we are redirecting to a Room Alias and it is for the room we already showing then replace history item
diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx
index c87e168456f..67ff0448c7f 100644
--- a/src/components/structures/RoomView.tsx
+++ b/src/components/structures/RoomView.tsx
@@ -927,6 +927,8 @@ export class RoomView extends React.Component {
if (payload.composerType) break;
let timelineRenderingType: TimelineRenderingType = payload.timelineRenderingType;
+ // ThreadView handles Action.ComposerInsert itself due to it having its own editState
+ if (timelineRenderingType === TimelineRenderingType.Thread) break;
if (this.state.timelineRenderingType === TimelineRenderingType.Search &&
payload.timelineRenderingType === TimelineRenderingType.Search
) {
@@ -1217,15 +1219,6 @@ export class RoomView extends React.Component {
if (!this.state.room || this.state.room.roomId !== state.roomId) return;
switch (ev.getType()) {
- case EventType.RoomCanonicalAlias:
- // re-view the room so MatrixChat can manage the alias in the URL properly
- dis.dispatch({
- action: Action.ViewRoom,
- room_id: this.state.room.roomId,
- metricsTrigger: undefined, // room doesn't change
- });
- break;
-
case EventType.RoomTombstone:
this.setState({ tombstone: this.getRoomTombstone() });
break;
diff --git a/src/components/structures/SpaceHierarchy.tsx b/src/components/structures/SpaceHierarchy.tsx
index 9d3bf54730b..80e35d5f5ef 100644
--- a/src/components/structures/SpaceHierarchy.tsx
+++ b/src/components/structures/SpaceHierarchy.tsx
@@ -524,8 +524,13 @@ export const useRoomHierarchy = (space: Room): {
setRooms(hierarchy.rooms);
}, [error, hierarchy]);
- const loading = hierarchy?.loading ?? true;
- return { loading, rooms, hierarchy, loadMore, error };
+ return {
+ loading: hierarchy?.loading ?? true,
+ rooms,
+ hierarchy: hierarchy?.root === space ? hierarchy : undefined,
+ loadMore,
+ error,
+ };
};
const useIntersectionObserver = (callback: () => void) => {
diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx
index ff77789802f..4f7c8019241 100644
--- a/src/components/structures/SpaceRoomView.tsx
+++ b/src/components/structures/SpaceRoomView.tsx
@@ -60,7 +60,7 @@ import {
defaultDmsRenderer,
defaultRoomsRenderer,
} from "../views/dialogs/AddExistingToSpaceDialog";
-import AccessibleButton from "../views/elements/AccessibleButton";
+import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton";
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
import ErrorBoundary from "../views/elements/ErrorBoundary";
import Field from "../views/elements/Field";
@@ -295,7 +295,7 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
/>;
});
- const onNextClick = async (ev) => {
+ const onNextClick = async (ev: ButtonEvent) => {
ev.preventDefault();
if (busy) return;
setError("");
@@ -326,7 +326,7 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
setBusy(false);
};
- let onClick = (ev) => {
+ let onClick = (ev: ButtonEvent) => {
ev.preventDefault();
onFinished();
};
diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx
index 55dd32bd529..120a604b828 100644
--- a/src/components/structures/ThreadView.tsx
+++ b/src/components/structures/ThreadView.tsx
@@ -53,6 +53,7 @@ import PosthogTrackers from "../../PosthogTrackers";
import { ButtonEvent } from "../views/elements/AccessibleButton";
import { RoomViewStore } from '../../stores/RoomViewStore';
import Spinner from "../views/elements/Spinner";
+import { ComposerInsertPayload, ComposerType } from "../../dispatcher/payloads/ComposerInsertPayload";
interface IProps {
room: Room;
@@ -136,6 +137,18 @@ export default class ThreadView extends React.Component {
this.setupThread(payload.event);
}
switch (payload.action) {
+ case Action.ComposerInsert: {
+ if (payload.composerType) break;
+ if (payload.timelineRenderingType !== TimelineRenderingType.Thread) break;
+
+ // re-dispatch to the correct composer
+ dis.dispatch({
+ ...(payload as ComposerInsertPayload),
+ composerType: this.state.editState ? ComposerType.Edit : ComposerType.Send,
+ });
+ break;
+ }
+
case Action.EditEvent:
// Quit early if it's not a thread context
if (payload.timelineRenderingType !== TimelineRenderingType.Thread) return;
diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx
index 21a418897a1..f75edfffe13 100644
--- a/src/components/structures/TimelinePanel.tsx
+++ b/src/components/structures/TimelinePanel.tsx
@@ -419,7 +419,7 @@ class TimelinePanel extends React.Component {
// matrix-js-sdk.
let serializedEventIdsFromTimelineSets: { [key: string]: string[] }[];
let serializedEventIdsFromThreadsTimelineSets: { [key: string]: string[] }[];
- const serializedThreadsMap: { [key: string]: string[] } = {};
+ const serializedThreadsMap: { [key: string]: any } = {};
if (room) {
const timelineSets = room.getTimelineSets();
const threadsTimelineSets = room.threadsTimelineSets;
@@ -430,7 +430,15 @@ class TimelinePanel extends React.Component {
// Serialize all threads in the room from theadId -> event IDs in the thread
room.getThreads().forEach((thread) => {
- serializedThreadsMap[thread.id] = thread.events.map(ev => ev.getId());
+ serializedThreadsMap[thread.id] = {
+ events: thread.events.map(ev => ev.getId()),
+ numTimelines: thread.timelineSet.getTimelines().length,
+ liveTimeline: thread.timelineSet.getLiveTimeline().getEvents().length,
+ prevTimeline: thread.timelineSet.getLiveTimeline().getNeighbouringTimeline(Direction.Backward)
+ ?.getEvents().length,
+ nextTimeline: thread.timelineSet.getLiveTimeline().getNeighbouringTimeline(Direction.Forward)
+ ?.getEvents().length,
+ };
});
}
diff --git a/src/components/structures/auth/Registration.tsx b/src/components/structures/auth/Registration.tsx
index 7515a4f0d90..d349205ab92 100644
--- a/src/components/structures/auth/Registration.tsx
+++ b/src/components/structures/auth/Registration.tsx
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import { createClient } from 'matrix-js-sdk/src/matrix';
+import { AuthType, createClient } from 'matrix-js-sdk/src/matrix';
import React, { Fragment, ReactNode } from 'react';
import { MatrixClient } from "matrix-js-sdk/src/client";
import classNames from "classnames";
@@ -34,10 +34,17 @@ import RegistrationForm from '../../views/auth/RegistrationForm';
import AccessibleButton from '../../views/elements/AccessibleButton';
import AuthBody from "../../views/auth/AuthBody";
import AuthHeader from "../../views/auth/AuthHeader";
-import InteractiveAuth from "../InteractiveAuth";
+import InteractiveAuth, { InteractiveAuthCallback } from "../InteractiveAuth";
import Spinner from "../../views/elements/Spinner";
import { AuthHeaderDisplay } from './header/AuthHeaderDisplay';
import { AuthHeaderProvider } from './header/AuthHeaderProvider';
+import SettingsStore from '../../../settings/SettingsStore';
+
+const debuglog = (...args: any[]) => {
+ if (SettingsStore.getValue("debug_registration")) {
+ logger.log.call(console, "Registration debuglog:", ...args);
+ }
+};
interface IProps {
serverConfig: ValidatedServerConfig;
@@ -287,9 +294,10 @@ export default class Registration extends React.Component {
);
};
- private onUIAuthFinished = async (success: boolean, response: any) => {
+ private onUIAuthFinished: InteractiveAuthCallback = async (success, response) => {
+ debuglog("Registration: ui authentication finished: ", { success, response });
if (!success) {
- let errorText = response.message || response.toString();
+ let errorText: ReactNode = response.message || response.toString();
// can we give a better error message?
if (response.errcode === 'M_RESOURCE_LIMIT_EXCEEDED') {
const errorTop = messageForResourceLimitError(
@@ -312,10 +320,10 @@ export default class Registration extends React.Component {
{ errorTop }
{ errorDetail }
;
- } else if (response.required_stages && response.required_stages.indexOf('m.login.msisdn') > -1) {
+ } else if (response.required_stages && response.required_stages.includes(AuthType.Msisdn)) {
let msisdnAvailable = false;
for (const flow of response.available_flows) {
- msisdnAvailable = msisdnAvailable || flow.stages.includes('m.login.msisdn');
+ msisdnAvailable = msisdnAvailable || flow.stages.includes(AuthType.Msisdn);
}
if (!msisdnAvailable) {
errorText = _t('This server does not support authentication with a phone number.');
@@ -351,14 +359,31 @@ export default class Registration extends React.Component {
// starting the registration process. This isn't perfect since it's possible
// the user had a separate guest session they didn't actually mean to replace.
const [sessionOwner, sessionIsGuest] = await Lifecycle.getStoredSessionOwner();
- if (sessionOwner && !sessionIsGuest && sessionOwner !== response.userId) {
+ if (sessionOwner && !sessionIsGuest && sessionOwner !== response.user_id) {
logger.log(
- `Found a session for ${sessionOwner} but ${response.userId} has just registered.`,
+ `Found a session for ${sessionOwner} but ${response.user_id} has just registered.`,
);
newState.differentLoggedInUserId = sessionOwner;
}
- if (response.access_token) {
+ // if we don't have an email at all, only one client can be involved in this flow, and we can directly log in.
+ //
+ // if we've got an email, it needs to be verified. in that case, two clients can be involved in this flow, the
+ // original client starting the process and the client that submitted the verification token. After the token
+ // has been submitted, it can not be used again.
+ //
+ // we can distinguish them based on whether the client has form values saved (if so, it's the one that started
+ // the registration), or whether it doesn't have any form values saved (in which case it's the client that
+ // verified the email address)
+ //
+ // as the client that started registration may be gone by the time we've verified the email, and only the client
+ // that verified the email is guaranteed to exist, we'll always do the login in that client.
+ const hasEmail = Boolean(this.state.formVals.email);
+ const hasAccessToken = Boolean(response.access_token);
+ debuglog("Registration: ui auth finished:", { hasEmail, hasAccessToken });
+ if (!hasEmail && hasAccessToken) {
+ // we'll only try logging in if we either have no email to verify at all or we're the client that verified
+ // the email, not the client that started the registration flow
await this.props.onLoggedIn({
userId: response.user_id,
deviceId: response.device_id,
@@ -416,26 +441,17 @@ export default class Registration extends React.Component {
};
private makeRegisterRequest = auth => {
- // We inhibit login if we're trying to register with an email address: this
- // avoids a lot of complex race conditions that can occur if we try to log
- // the user in one one or both of the tabs they might end up with after
- // clicking the email link.
- let inhibitLogin = Boolean(this.state.formVals.email);
-
- // Only send inhibitLogin if we're sending username / pw params
- // (Since we need to send no params at all to use the ones saved in the
- // session).
- if (!this.state.formVals.password) inhibitLogin = null;
-
const registerParams = {
username: this.state.formVals.username,
password: this.state.formVals.password,
initial_device_display_name: this.props.defaultDeviceDisplayName,
auth: undefined,
+ // we still want to avoid the race conditions involved with multiple clients handling registration, but
+ // we'll handle these after we've received the access_token in onUIAuthFinished
inhibit_login: undefined,
};
if (auth) registerParams.auth = auth;
- if (inhibitLogin !== undefined && inhibitLogin !== null) registerParams.inhibit_login = inhibitLogin;
+ debuglog("Registration: sending registration request:", auth);
return this.state.matrixClient.registerRequest(registerParams);
};
@@ -597,22 +613,22 @@ export default class Registration extends React.Component {
{ _t("Continue with previous account") }
;
- } else if (this.state.formVals.password) {
- // We're the client that started the registration
- regDoneText = { _t(
- "Log in to your new account.", {},
- {
- a: (sub) => { sub } ,
- },
- ) } ;
} else {
- // We're not the original client: the user probably got to us by clicking the
- // email validation link. We can't offer a 'go straight to your account' link
- // as we don't have the original creds.
+ // regardless of whether we're the client that started the registration or not, we should
+ // try our credentials anyway
regDoneText = { _t(
- "You can now close this window or log in to your new account.", {},
+ "Log in to your new account.", {},
{
- a: (sub) => { sub } ,
+ a: (sub) => {
+ const sessionLoaded = await this.onLoginClickWithCheck(event);
+ if (sessionLoaded) {
+ dis.dispatch({ action: "view_home_page" });
+ }
+ }}
+ >{ sub } ,
},
) } ;
}
diff --git a/src/components/views/beacon/BeaconListItem.tsx b/src/components/views/beacon/BeaconListItem.tsx
index eda1580700e..bcfb4971766 100644
--- a/src/components/views/beacon/BeaconListItem.tsx
+++ b/src/components/views/beacon/BeaconListItem.tsx
@@ -23,10 +23,10 @@ import { useEventEmitterState } from '../../../hooks/useEventEmitter';
import { humanizeTime } from '../../../utils/humanize';
import { _t } from '../../../languageHandler';
import MemberAvatar from '../avatars/MemberAvatar';
-import CopyableText from '../elements/CopyableText';
import BeaconStatus from './BeaconStatus';
import { BeaconDisplayStatus } from './displayStatus';
import StyledLiveBeaconIcon from './StyledLiveBeaconIcon';
+import ShareLatestLocation from './ShareLatestLocation';
interface Props {
beacon: Beacon;
@@ -69,10 +69,7 @@ const BeaconListItem: React.FC = ({ beacon }) => {
label={beaconMember?.name || beacon.beaconInfo.description || beacon.beaconInfoOwner}
displayStatus={BeaconDisplayStatus.Active}
>
- latestLocationState?.uri}
- />
+
{ _t("Updated %(humanizedUpdateTime)s", { humanizedUpdateTime }) }
diff --git a/src/components/views/beacon/BeaconStatusTooltip.tsx b/src/components/views/beacon/BeaconStatusTooltip.tsx
index bc9f3609395..688abc510aa 100644
--- a/src/components/views/beacon/BeaconStatusTooltip.tsx
+++ b/src/components/views/beacon/BeaconStatusTooltip.tsx
@@ -19,9 +19,9 @@ import { Beacon } from 'matrix-js-sdk/src/matrix';
import { LocationAssetType } from 'matrix-js-sdk/src/@types/location';
import MatrixClientContext from '../../../contexts/MatrixClientContext';
-import CopyableText from '../elements/CopyableText';
import BeaconStatus from './BeaconStatus';
import { BeaconDisplayStatus } from './displayStatus';
+import ShareLatestLocation from './ShareLatestLocation';
interface Props {
beacon: Beacon;
@@ -50,10 +50,7 @@ const BeaconStatusTooltip: React.FC = ({ beacon }) => {
displayLiveTimeRemaining
className='mx_BeaconStatusTooltip_inner'
>
- beacon.latestLocationState?.uri}
- />
+
;
};
diff --git a/src/components/views/beacon/BeaconViewDialog.tsx b/src/components/views/beacon/BeaconViewDialog.tsx
index a7cdb242d37..f3e2fd12a17 100644
--- a/src/components/views/beacon/BeaconViewDialog.tsx
+++ b/src/components/views/beacon/BeaconViewDialog.tsx
@@ -32,12 +32,12 @@ import ZoomButtons from '../location/ZoomButtons';
import BeaconMarker from './BeaconMarker';
import { Bounds, getBeaconBounds } from '../../../utils/beacon/bounds';
import { getGeoUri } from '../../../utils/beacon';
-import { Icon as LocationIcon } from '../../../../res/img/element-icons/location.svg';
import { _t } from '../../../languageHandler';
import AccessibleButton from '../elements/AccessibleButton';
import DialogSidebar from './DialogSidebar';
import DialogOwnBeaconStatus from './DialogOwnBeaconStatus';
import BeaconStatusTooltip from './BeaconStatusTooltip';
+import MapFallback from '../location/MapFallback';
interface IProps extends IDialogProps {
roomId: Room['roomId'];
@@ -110,11 +110,10 @@ const BeaconViewDialog: React.FC = ({
>
}
:
-
-
{ _t('No live locations') }
= ({
>
{ _t('Close') }
-
+
}
{ isSidebarOpen ?
setSidebarOpen(false)} /> :
diff --git a/src/components/views/beacon/ShareLatestLocation.tsx b/src/components/views/beacon/ShareLatestLocation.tsx
new file mode 100644
index 00000000000..09c179f6d62
--- /dev/null
+++ b/src/components/views/beacon/ShareLatestLocation.tsx
@@ -0,0 +1,66 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React, { useEffect, useState } from 'react';
+import { BeaconLocationState } from 'matrix-js-sdk/src/content-helpers';
+
+import { Icon as ExternalLinkIcon } from '../../../../res/img/external-link.svg';
+import { _t } from '../../../languageHandler';
+import { makeMapSiteLink, parseGeoUri } from '../../../utils/location';
+import CopyableText from '../elements/CopyableText';
+import TooltipTarget from '../elements/TooltipTarget';
+
+interface Props {
+ latestLocationState?: BeaconLocationState;
+}
+
+const ShareLatestLocation: React.FC = ({ latestLocationState }) => {
+ const [coords, setCoords] = useState(null);
+ useEffect(() => {
+ if (!latestLocationState) {
+ return;
+ }
+ const coords = parseGeoUri(latestLocationState.uri);
+ setCoords(coords);
+ }, [latestLocationState]);
+
+ if (!latestLocationState || !coords) {
+ return null;
+ }
+
+ const latLonString = `${coords.latitude},${coords.longitude}`;
+ const mapLink = makeMapSiteLink(coords);
+
+ return <>
+
+
+
+
+
+ latLonString}
+ />
+ >;
+};
+
+export default ShareLatestLocation;
diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx
index 86e9d9cc306..8372ca14bfb 100644
--- a/src/components/views/context_menus/MessageContextMenu.tsx
+++ b/src/components/views/context_menus/MessageContextMenu.tsx
@@ -50,7 +50,7 @@ import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { GetRelationsForEvent, IEventTileOps } from "../rooms/EventTile";
import { OpenForwardDialogPayload } from "../../../dispatcher/payloads/OpenForwardDialogPayload";
import { OpenReportEventDialogPayload } from "../../../dispatcher/payloads/OpenReportEventDialogPayload";
-import { createMapSiteLink } from '../../../utils/location';
+import { createMapSiteLinkFromEvent } from '../../../utils/location';
interface IProps extends IPosition {
chevronFace: ChevronFace;
@@ -155,6 +155,15 @@ export default class MessageContextMenu extends React.Component
this.closeMenu();
};
+ private onJumpToRelatedEventClick = (relatedEventId: string): void => {
+ dis.dispatch({
+ action: "view_room",
+ room_id: this.props.mxEvent.getRoomId(),
+ event_id: relatedEventId,
+ highlighted: true,
+ });
+ };
+
private onReportEventClick = (): void => {
dis.dispatch({
action: Action.OpenReportEventDialog,
@@ -351,7 +360,7 @@ export default class MessageContextMenu extends React.Component
let openInMapSiteButton: JSX.Element;
if (this.canOpenInMapSite(mxEvent)) {
- const mapSiteLink = createMapSiteLink(mxEvent);
+ const mapSiteLink = createMapSiteLinkFromEvent(mxEvent);
openInMapSiteButton = (
);
}
+ let jumpToRelatedEventButton: JSX.Element;
+ const relatedEventId = mxEvent.getWireContent()?.["m.relates_to"]?.event_id;
+ if (relatedEventId && SettingsStore.getValue("developerMode")) {
+ jumpToRelatedEventButton = (
+ this.onJumpToRelatedEventClick(relatedEventId)}
+ />
+ );
+ }
+
let reportEventButton: JSX.Element;
if (mxEvent.getSender() !== me) {
reportEventButton = (
@@ -608,6 +629,7 @@ export default class MessageContextMenu extends React.Component
{ permalinkButton }
{ reportEventButton }
{ externalURLButton }
+ { jumpToRelatedEventButton }
{ unhidePreviewButton }
{ viewSourceButton }
{ resendReactionsButton }
diff --git a/src/components/views/dialogs/DeactivateAccountDialog.tsx b/src/components/views/dialogs/DeactivateAccountDialog.tsx
index dbdc3b3639a..55251025fb7 100644
--- a/src/components/views/dialogs/DeactivateAccountDialog.tsx
+++ b/src/components/views/dialogs/DeactivateAccountDialog.tsx
@@ -22,7 +22,7 @@ import { logger } from "matrix-js-sdk/src/logger";
import Analytics from '../../../Analytics';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
-import InteractiveAuth, { ERROR_USER_CANCELLED } from "../../structures/InteractiveAuth";
+import InteractiveAuth, { ERROR_USER_CANCELLED, InteractiveAuthCallback } from "../../structures/InteractiveAuth";
import { DEFAULT_PHASE, PasswordAuthEntry, SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents";
import StyledCheckbox from "../elements/StyledCheckbox";
import BaseDialog from "./BaseDialog";
@@ -104,7 +104,7 @@ export default class DeactivateAccountDialog extends React.Component {
+ private onUIAuthFinished: InteractiveAuthCallback = (success, result) => {
if (success) return; // great! makeRequest() will be called too.
if (result === ERROR_USER_CANCELLED) {
diff --git a/src/components/views/dialogs/InteractiveAuthDialog.tsx b/src/components/views/dialogs/InteractiveAuthDialog.tsx
index 46bad5fd0e1..6f10790811e 100644
--- a/src/components/views/dialogs/InteractiveAuthDialog.tsx
+++ b/src/components/views/dialogs/InteractiveAuthDialog.tsx
@@ -22,7 +22,7 @@ import { IAuthData } from "matrix-js-sdk/src/interactive-auth";
import { _t } from '../../../languageHandler';
import AccessibleButton from '../elements/AccessibleButton';
-import InteractiveAuth, { ERROR_USER_CANCELLED } from "../../structures/InteractiveAuth";
+import InteractiveAuth, { ERROR_USER_CANCELLED, InteractiveAuthCallback } from "../../structures/InteractiveAuth";
import { SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents";
import BaseDialog from "./BaseDialog";
import { IDialogProps } from "./IDialogProps";
@@ -117,7 +117,7 @@ export default class InteractiveAuthDialog extends React.Component {
+ private onAuthFinished: InteractiveAuthCallback = (success, result): void => {
if (success) {
this.props.onFinished(true, result);
} else {
diff --git a/src/components/views/dialogs/ReportEventDialog.tsx b/src/components/views/dialogs/ReportEventDialog.tsx
index 7a2d51889f8..929c33b128e 100644
--- a/src/components/views/dialogs/ReportEventDialog.tsx
+++ b/src/components/views/dialogs/ReportEventDialog.tsx
@@ -1,5 +1,6 @@
/*
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
+Copyright 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -30,6 +31,7 @@ import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons";
import Field from "../elements/Field";
import Spinner from "../elements/Spinner";
+import LabelledCheckbox from "../elements/LabelledCheckbox";
interface IProps extends IDialogProps {
mxEvent: MatrixEvent;
@@ -42,6 +44,7 @@ interface IState {
err?: string;
// If we know it, the nature of the abuse, as specified by MSC3215.
nature?: ExtendedNature;
+ ignoreUserToo: boolean; // if true, user will be ignored/blocked on submit
}
const MODERATED_BY_STATE_EVENT_TYPE = [
@@ -160,9 +163,14 @@ export default class ReportEventDialog extends React.Component {
err: null,
// If specified, the nature of the abuse, as specified by MSC3215.
nature: null,
+ ignoreUserToo: false, // default false, for now. Could easily be argued as default true
};
}
+ private onIgnoreUserTooChanged = (newVal: boolean): void => {
+ this.setState({ ignoreUserToo: newVal });
+ };
+
// The user has written down a freeform description of the abuse.
private onReasonChange = ({ target: { value: reason } }): void => {
this.setState({ reason });
@@ -232,6 +240,15 @@ export default class ReportEventDialog extends React.Component {
// Report to homeserver admin through the dedicated Matrix API.
await client.reportEvent(ev.getRoomId(), ev.getId(), -100, this.state.reason.trim());
}
+
+ // if the user should also be ignored, do that
+ if (this.state.ignoreUserToo) {
+ await client.setIgnoredUsers([
+ ...client.getIgnoredUsers(),
+ ev.getSender(),
+ ]);
+ }
+
this.props.onFinished(true);
} catch (e) {
logger.error(e);
@@ -242,7 +259,7 @@ export default class ReportEventDialog extends React.Component {
}
};
- render() {
+ public render() {
let error = null;
if (this.state.err) {
error =
@@ -259,6 +276,14 @@ export default class ReportEventDialog extends React.Component {
);
}
+ const ignoreUserCheckbox = ;
+
const adminMessageMD = SdkConfig
.getObject("report_event")?.get("admin_message_md", "adminMessageMD");
let adminMessage;
@@ -387,6 +412,7 @@ export default class ReportEventDialog extends React.Component {
/>
{ progress }
{ error }
+ { ignoreUserCheckbox }
{
/>
{ progress }
{ error }
+ { ignoreUserCheckbox }
string;
border?: boolean;
+ className?: string;
}
-const CopyableText: React.FC = ({ children, getTextToCopy, border=true }) => {
+const CopyableText: React.FC = ({ children, getTextToCopy, border=true, className }) => {
const [tooltip, setTooltip] = useState(undefined);
const onCopyClickInternal = async (e: ButtonEvent) => {
@@ -44,11 +45,11 @@ const CopyableText: React.FC = ({ children, getTextToCopy, border=true }
}
};
- const className = classNames("mx_CopyableText", {
+ const combinedClassName = classNames("mx_CopyableText", className, {
mx_CopyableText_border: border,
});
- return
+ return
{ children }
= ({ value, label, byline, disabled, onChange }) => {
+ return
+ onChange(e.target.checked)} />
+
+ { label }
+ { byline ? { byline } : null }
+
+ ;
+};
+
+export default LabelledCheckbox;
diff --git a/src/components/views/elements/LabelledToggleSwitch.tsx b/src/components/views/elements/LabelledToggleSwitch.tsx
index 952c92ac427..6df972440a9 100644
--- a/src/components/views/elements/LabelledToggleSwitch.tsx
+++ b/src/components/views/elements/LabelledToggleSwitch.tsx
@@ -1,5 +1,5 @@
/*
-Copyright 2019 - 2021 The Matrix.org Foundation C.I.C.
+Copyright 2019 - 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@ limitations under the License.
*/
import React from "react";
+import classNames from "classnames";
import ToggleSwitch from "./ToggleSwitch";
@@ -35,7 +36,7 @@ interface IProps {
}
export default class LabelledToggleSwitch extends React.PureComponent {
- render() {
+ public render() {
// This is a minimal version of a SettingsFlag
let firstPart = { this.props.label } ;
@@ -52,7 +53,9 @@ export default class LabelledToggleSwitch extends React.PureComponent {
secondPart = temp;
}
- const classes = `mx_SettingsFlag ${this.props.className || ""}`;
+ const classes = classNames("mx_SettingsFlag", this.props.className, {
+ "mx_SettingsFlag_toggleInFront": this.props.toggleInFront,
+ });
return (
{ firstPart }
diff --git a/src/components/views/location/MapFallback.tsx b/src/components/views/location/MapFallback.tsx
new file mode 100644
index 00000000000..75545d5e0fd
--- /dev/null
+++ b/src/components/views/location/MapFallback.tsx
@@ -0,0 +1,39 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React from 'react';
+import classNames from 'classnames';
+
+import { Icon as LocationMarkerIcon } from '../../../../res/img/element-icons/location.svg';
+import { Icon as MapFallbackImage } from '../../../../res/img/location/map.svg';
+import Spinner from '../elements/Spinner';
+
+interface Props extends React.HTMLAttributes
{
+ className?: string;
+ isLoading?: boolean;
+ children?: React.ReactNode | React.ReactNodeArray;
+}
+
+const MapFallback: React.FC = ({ className, isLoading, children, ...rest }) => {
+ return
+
+ { /*
*/ }
+ { isLoading ?
:
}
+ { children }
+
;
+};
+
+export default MapFallback;
diff --git a/src/components/views/messages/MBeaconBody.tsx b/src/components/views/messages/MBeaconBody.tsx
index fb82cff29e2..bd581d1bce8 100644
--- a/src/components/views/messages/MBeaconBody.tsx
+++ b/src/components/views/messages/MBeaconBody.tsx
@@ -19,7 +19,6 @@ import { Beacon, BeaconEvent, MatrixEvent } from 'matrix-js-sdk/src/matrix';
import { BeaconLocationState } from 'matrix-js-sdk/src/content-helpers';
import { randomString } from 'matrix-js-sdk/src/randomstring';
-import { Icon as LocationMarkerIcon } from '../../../../res/img/element-icons/location.svg';
import MatrixClientContext from '../../../contexts/MatrixClientContext';
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
import { _t } from '../../../languageHandler';
@@ -28,8 +27,8 @@ import { useBeacon } from '../../../utils/beacon';
import { isSelfLocation } from '../../../utils/location';
import { BeaconDisplayStatus, getBeaconDisplayStatus } from '../beacon/displayStatus';
import BeaconStatus from '../beacon/BeaconStatus';
-import Spinner from '../elements/Spinner';
import Map from '../location/Map';
+import MapFallback from '../location/MapFallback';
import SmartMarker from '../location/SmartMarker';
import OwnBeaconStatus from '../beacon/OwnBeaconStatus';
import BeaconViewDialog from '../beacon/BeaconViewDialog';
@@ -134,12 +133,10 @@ const MBeaconBody: React.FC = React.forwardRef(({ mxEvent }, ref) =>
/>
}
- :
- { displayStatus === BeaconDisplayStatus.Loading ?
- :
-
- }
-
+ :
}
{ isOwnBeacon ?
{
}
}
+ protected getBanner(content: IMediaEventContent): JSX.Element {
+ // Hide it for the threads list & the file panel where we show it as text anyway.
+ if ([
+ TimelineRenderingType.ThreadsList,
+ TimelineRenderingType.File,
+ ].includes(this.context.timelineRenderingType)) {
+ return null;
+ }
+
+ return (
+
+ { presentableTextForFile(content, _t("Image"), true, true) }
+
+ );
+ }
+
protected messageContent(
contentUrl: string,
thumbUrl: string,
@@ -448,18 +464,8 @@ export default class MImageBody extends React.Component {
}
let banner: JSX.Element;
- const isTimeline = [
- TimelineRenderingType.Room,
- TimelineRenderingType.Search,
- TimelineRenderingType.Thread,
- TimelineRenderingType.Notification,
- ].includes(this.context.timelineRenderingType);
- if (this.state.showImage && this.state.hover && isTimeline) {
- banner = (
-
- { presentableTextForFile(content, _t("Image"), true, true) }
-
- );
+ if (this.state.showImage && this.state.hover) {
+ banner = this.getBanner(content);
}
const classes = classNames({
diff --git a/src/components/views/messages/MImageReplyBody.tsx b/src/components/views/messages/MImageReplyBody.tsx
index 9edbcec304d..b36438741d0 100644
--- a/src/components/views/messages/MImageReplyBody.tsx
+++ b/src/components/views/messages/MImageReplyBody.tsx
@@ -40,6 +40,10 @@ export default class MImageReplyBody extends MImageBody {
return presentableTextForFile(this.props.mxEvent.getContent(), sticker ? _t("Sticker") : _t("Image"), !sticker);
}
+ protected getBanner(content: IMediaEventContent): JSX.Element {
+ return null; // we don't need a banner, nor have space for one
+ }
+
render() {
if (this.state.error) {
return super.render();
diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx
index ff87af1dc3a..f5cdf3a969c 100644
--- a/src/components/views/messages/MLocationBody.tsx
+++ b/src/components/views/messages/MLocationBody.tsx
@@ -16,6 +16,7 @@ limitations under the License.
import React from 'react';
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
+import { randomString } from 'matrix-js-sdk/src/randomstring';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';
@@ -45,10 +46,9 @@ export default class MLocationBody extends React.Component {
constructor(props: IBodyProps) {
super(props);
- const randomString = Math.random().toString(16).slice(2, 10);
// multiple instances of same map might be in document
// eg thread and main timeline, reply
- const idSuffix = `${props.mxEvent.getId()}_${randomString}`;
+ const idSuffix = `${props.mxEvent.getId()}_${randomString(8)}`;
this.mapId = `mx_MLocationBody_${idSuffix}`;
this.state = {
diff --git a/src/components/views/messages/MStickerBody.tsx b/src/components/views/messages/MStickerBody.tsx
index 62e2b2ea69e..40c43d73f00 100644
--- a/src/components/views/messages/MStickerBody.tsx
+++ b/src/components/views/messages/MStickerBody.tsx
@@ -19,6 +19,7 @@ import React from 'react';
import MImageBody from './MImageBody';
import { BLURHASH_FIELD } from "../../../utils/image-media";
import Tooltip from "../elements/Tooltip";
+import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent";
export default class MStickerBody extends MImageBody {
// Mostly empty to prevent default behaviour of MImageBody
@@ -70,4 +71,8 @@ export default class MStickerBody extends MImageBody {
protected getFileBody() {
return null;
}
+
+ protected getBanner(content: IMediaEventContent): JSX.Element {
+ return null; // we don't need a banner, we have a tooltip
+ }
}
diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx
index 85ea8387555..7bd7fd719e8 100644
--- a/src/components/views/messages/MessageActionBar.tsx
+++ b/src/components/views/messages/MessageActionBar.tsx
@@ -76,6 +76,17 @@ const OptionsButton: React.FC = ({
onFocusChange(menuDisplayed);
}, [onFocusChange, menuDisplayed]);
+ const onOptionsClick = (e: React.MouseEvent): void => {
+ // Don't open the regular browser or our context menu on right-click
+ e.preventDefault();
+ e.stopPropagation();
+ openMenu();
+ // when the context menu is opened directly, e.g. via mouse click, the onFocus handler which tracks
+ // the element that is currently focused is skipped. So we want to call onFocus manually to keep the
+ // position in the page even when someone is clicking around.
+ onFocus();
+ };
+
let contextMenu: ReactElement | null;
if (menuDisplayed) {
const tile = getTile && getTile();
@@ -97,13 +108,7 @@ const OptionsButton: React.FC = ({
{
- openMenu();
- // when the context menu is opened directly, e.g. via mouse click, the onFocus handler which tracks
- // the element that is currently focused is skipped. So we want to call onFocus manually to keep the
- // position in the page even when someone is clicking around.
- onFocus();
- }}
+ onClick={onOptionsClick}
isExpanded={menuDisplayed}
inputRef={ref}
onFocus={onFocus}
diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx
index f1c956bb8f3..6a12792e27f 100644
--- a/src/components/views/right_panel/UserInfo.tsx
+++ b/src/components/views/right_panel/UserInfo.tsx
@@ -1428,8 +1428,8 @@ const UserInfoHeader: React.FC<{
const avatarElement = (
-
-
+
+
{
this.setState({ localAliasesLoading: true });
try {
const mxClient = this.context;
+
let localAliases = [];
- if (await mxClient.doesServerSupportUnstableFeature("org.matrix.msc2432")) {
- const response = await mxClient.unstableGetLocalAliases(this.props.roomId);
- if (Array.isArray(response.aliases)) {
- localAliases = response.aliases;
- }
+ const response = await mxClient.getLocalAliases(this.props.roomId);
+ if (Array.isArray(response?.aliases)) {
+ localAliases = response.aliases;
}
this.setState({ localAliases });
diff --git a/src/components/views/rooms/BasicMessageComposer.tsx b/src/components/views/rooms/BasicMessageComposer.tsx
index 667d5a42a4e..fd3f5eed3dc 100644
--- a/src/components/views/rooms/BasicMessageComposer.tsx
+++ b/src/components/views/rooms/BasicMessageComposer.tsx
@@ -354,7 +354,8 @@ export default class BasicMessageEditor extends React.Component
this.modifiedFlag = true;
const range = getRangeForSelection(this.editorRef.current, model, document.getSelection());
- if (plainText && range.length > 0 && linkify.test(plainText)) {
+ // If the user is pasting a link, and has a range selected which is not a link, wrap the range with the link
+ if (plainText && range.length > 0 && linkify.test(plainText) && !linkify.test(range.text)) {
formatRangeAsLink(range, plainText);
} else {
replaceRangeAndMoveCaret(range, parts);
@@ -448,12 +449,11 @@ export default class BasicMessageEditor extends React.Component
const selection = document.getSelection();
if (this.hasTextSelected && selection.isCollapsed) {
this.hasTextSelected = false;
- if (this.formatBarRef.current) {
- this.formatBarRef.current.hide();
- }
+ this.formatBarRef.current?.hide();
} else if (!selection.isCollapsed && !isEmpty) {
this.hasTextSelected = true;
- if (this.formatBarRef.current && this.state.useMarkdown) {
+ const range = getRangeForSelection(this.editorRef.current, this.props.model, selection);
+ if (this.formatBarRef.current && this.state.useMarkdown && !!range.text.trim()) {
const selectionRect = selection.getRangeAt(0).getBoundingClientRect();
this.formatBarRef.current.showAt(selectionRect);
}
diff --git a/src/components/views/rooms/ReadReceiptGroup.tsx b/src/components/views/rooms/ReadReceiptGroup.tsx
index fc4c6796faa..34891810e33 100644
--- a/src/components/views/rooms/ReadReceiptGroup.tsx
+++ b/src/components/views/rooms/ReadReceiptGroup.tsx
@@ -209,10 +209,12 @@ export function ReadReceiptGroup(
return (
-
+
{
const cli = this.context;
- if (await cli.doesServerSupportUnstableFeature("org.matrix.msc2432")) {
- const response = await cli.unstableGetLocalAliases(this.props.roomId);
- const localAliases = response.aliases;
- return Array.isArray(localAliases) && localAliases.length !== 0;
- } else {
- const room = cli.getRoom(this.props.roomId);
- const aliasEvents = room.currentState.getStateEvents(EventType.RoomAliases) || [];
- const hasAliases = !!aliasEvents.find((ev) => (ev.getContent().aliases || []).length > 0);
- return hasAliases;
- }
+ const response = await cli.getLocalAliases(this.props.roomId);
+ const localAliases = response.aliases;
+ return Array.isArray(localAliases) && localAliases.length !== 0;
}
private renderJoinRule() {
diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx
index 4e25fb9ddc9..2ec7fcd81fa 100644
--- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx
@@ -29,6 +29,7 @@ import dis from "../../../../../dispatcher/dispatcher";
import { UserTab } from "../../../dialogs/UserTab";
import { OpenToTabPayload } from "../../../../../dispatcher/payloads/OpenToTabPayload";
import { Action } from "../../../../../dispatcher/actions";
+import SdkConfig from "../../../../../SdkConfig";
interface IProps {
closeSettingsFn(success: boolean): void;
@@ -43,6 +44,8 @@ interface IState {
alwaysShowMenuBar: boolean;
minimizeToTraySupported: boolean;
minimizeToTray: boolean;
+ togglingHardwareAccelerationSupported: boolean;
+ enableHardwareAcceleration: boolean;
autocompleteDelay: string;
readMarkerInViewThresholdMs: string;
readMarkerOutOfViewThresholdMs: string;
@@ -121,6 +124,8 @@ export default class PreferencesUserSettingsTab extends React.Component this.setState({ minimizeToTray: checked }));
};
+ private onHardwareAccelerationChange = (checked: boolean) => {
+ PlatformPeg.get().setHardwareAccelerationEnabled(checked).then(
+ () => this.setState({ enableHardwareAcceleration: checked }));
+ };
+
private onAutocompleteDelayChange = (e: React.ChangeEvent) => {
this.setState({ autocompleteDelay: e.target.value });
SettingsStore.setValue("autocompleteDelay", null, SettingLevel.DEVICE, e.target.value);
@@ -250,6 +268,17 @@ export default class PreferencesUserSettingsTab extends React.Component ;
}
+ let hardwareAccelerationOption = null;
+ if (this.state.togglingHardwareAccelerationSupported) {
+ const appName = SdkConfig.get().brand;
+ hardwareAccelerationOption = ;
+ }
+
return (
{ _t("Preferences") }
@@ -307,6 +336,7 @@ export default class PreferencesUserSettingsTab extends React.Component
{ _t("General") }
{ this.renderGroup(PreferencesUserSettingsTab.GENERAL_SETTINGS) }
{ minimizeToTrayOption }
+ { hardwareAccelerationOption }
{ autoHideMenuOption }
{ autoLaunchOption }
{ warnBeforeExitOption }
diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts
index 27f0b423c07..95c08075730 100644
--- a/src/dispatcher/actions.ts
+++ b/src/dispatcher/actions.ts
@@ -317,5 +317,15 @@ export enum Action {
/**
* Show current room topic
*/
- ShowRoomTopic = "show_room_topic"
+ ShowRoomTopic = "show_room_topic",
+
+ /**
+ * Fired when the client was logged out. No additional payload information required.
+ */
+ OnLoggedOut = "on_logged_out",
+
+ /**
+ * Fired when the client was logged in. No additional payload information required.
+ */
+ OnLoggedIn = "on_logged_in",
}
diff --git a/src/editor/parts.ts b/src/editor/parts.ts
index 0d5d6a6613e..c1f729017d1 100644
--- a/src/editor/parts.ts
+++ b/src/editor/parts.ts
@@ -95,6 +95,7 @@ abstract class BasePart {
this._text = text;
}
+ // chr can also be a grapheme cluster
protected acceptsInsertion(chr: string, offset: number, inputType: string): boolean {
return true;
}
@@ -130,14 +131,20 @@ abstract class BasePart {
// append str, returns the remaining string if a character was rejected.
public appendUntilRejected(str: string, inputType: string): string | undefined {
const offset = this.text.length;
- for (let i = 0; i < str.length; ++i) {
- const chr = str.charAt(i);
- if (!this.acceptsInsertion(chr, offset + i, inputType)) {
- this._text = this._text + str.slice(0, i);
- return str.slice(i);
+ // Take a copy as we will be taking chunks off the start of the string as we process them
+ // To only need to grapheme split the bits of the string we're working on.
+ let buffer = str;
+ while (buffer) {
+ // We use lodash's grapheme splitter to avoid breaking apart compound emojis
+ const [char] = split(buffer, "", 2);
+ if (!this.acceptsInsertion(char, offset + str.length - buffer.length, inputType)) {
+ break;
}
+ buffer = buffer.slice(char.length);
}
- this._text = this._text + str;
+
+ this._text += str.slice(0, str.length - buffer.length);
+ return buffer || undefined;
}
// inserts str at offset if all the characters in str were accepted, otherwise don't do anything
@@ -363,7 +370,7 @@ class NewlinePart extends BasePart implements IBasePart {
}
}
-class EmojiPart extends BasePart implements IBasePart {
+export class EmojiPart extends BasePart implements IBasePart {
protected acceptsInsertion(chr: string, offset: number): boolean {
return EMOJIBASE_REGEX.test(chr);
}
@@ -585,7 +592,8 @@ export class PartCreator {
case "\n":
return new NewlinePart();
default:
- if (EMOJIBASE_REGEX.test(input[0])) {
+ // We use lodash's grapheme splitter to avoid breaking apart compound emojis
+ if (EMOJIBASE_REGEX.test(split(input, "", 2)[0])) {
return new EmojiPart();
}
return new PlainPart();
diff --git a/src/hooks/usePublicRoomDirectory.ts b/src/hooks/usePublicRoomDirectory.ts
new file mode 100644
index 00000000000..24cc8f541a1
--- /dev/null
+++ b/src/hooks/usePublicRoomDirectory.ts
@@ -0,0 +1,164 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { useCallback, useEffect, useState } from "react";
+import { IProtocol, IPublicRoomsChunkRoom } from "matrix-js-sdk/src/client";
+import { IRoomDirectoryOptions } from "matrix-js-sdk/src/@types/requests";
+
+import { MatrixClientPeg } from "../MatrixClientPeg";
+import SdkConfig from "../SdkConfig";
+import SettingsStore from "../settings/SettingsStore";
+import { Protocols } from "../utils/DirectoryUtils";
+
+export const ALL_ROOMS = "ALL_ROOMS";
+const LAST_SERVER_KEY = "mx_last_room_directory_server";
+const LAST_INSTANCE_KEY = "mx_last_room_directory_instance";
+
+export interface IPublicRoomsOpts {
+ limit: number;
+ query?: string;
+}
+
+let thirdParty: Protocols;
+
+export const usePublicRoomDirectory = () => {
+ const [publicRooms, setPublicRooms] = useState([]);
+
+ const [roomServer, setRoomServer] = useState(undefined);
+ const [instanceId, setInstanceId] = useState(undefined);
+ const [protocols, setProtocols] = useState(null);
+
+ const [ready, setReady] = useState(false);
+ const [loading, setLoading] = useState(false);
+
+ async function initProtocols() {
+ if (!MatrixClientPeg.get()) {
+ // We may not have a client yet when invoked from welcome page
+ setReady(true);
+ } else if (thirdParty) {
+ setProtocols(thirdParty);
+ } else {
+ const response = await MatrixClientPeg.get().getThirdpartyProtocols();
+ thirdParty = response;
+ setProtocols(response);
+ }
+ }
+
+ function setConfig(server: string, instanceId?: string) {
+ if (!ready) {
+ throw new Error("public room configuration not initialised yet");
+ } else {
+ setRoomServer(server);
+ setInstanceId(instanceId ?? null);
+ }
+ }
+
+ const search = useCallback(async ({
+ limit = 20,
+ query,
+ }: IPublicRoomsOpts): Promise => {
+ if (!query?.length) {
+ setPublicRooms([]);
+ return true;
+ }
+
+ const opts: IRoomDirectoryOptions = { limit };
+
+ if (roomServer != MatrixClientPeg.getHomeserverName()) {
+ opts.server = roomServer;
+ }
+
+ if (instanceId === ALL_ROOMS) {
+ opts.include_all_networks = true;
+ } else if (instanceId) {
+ opts.third_party_instance_id = instanceId;
+ }
+
+ if (query) {
+ opts.filter = {
+ generic_search_term: query,
+ };
+ }
+
+ try {
+ setLoading(true);
+ const { chunk } = await MatrixClientPeg.get().publicRooms(opts);
+ setPublicRooms(chunk);
+ return true;
+ } catch (e) {
+ console.error("Could not fetch public rooms for params", opts, e);
+ setPublicRooms([]);
+ return false;
+ } finally {
+ setLoading(false);
+ }
+ }, [roomServer, instanceId]);
+
+ useEffect(() => {
+ initProtocols();
+ }, []);
+
+ useEffect(() => {
+ if (protocols === null) {
+ return;
+ }
+
+ const myHomeserver = MatrixClientPeg.getHomeserverName();
+ const lsRoomServer = localStorage.getItem(LAST_SERVER_KEY);
+ const lsInstanceId = localStorage.getItem(LAST_INSTANCE_KEY);
+
+ let roomServer = myHomeserver;
+ if (
+ SdkConfig.getObject("room_directory")?.get("servers")?.includes(lsRoomServer) ||
+ SettingsStore.getValue("room_directory_servers")?.includes(lsRoomServer)
+ ) {
+ roomServer = lsRoomServer;
+ }
+
+ let instanceId: string | null = null;
+ if (roomServer === myHomeserver && (
+ lsInstanceId === ALL_ROOMS ||
+ Object.values(protocols).some((p: IProtocol) => {
+ p.instances.some(i => i.instance_id === lsInstanceId);
+ })
+ )) {
+ instanceId = lsInstanceId;
+ }
+
+ setReady(true);
+ setInstanceId(instanceId);
+ setRoomServer(roomServer);
+ }, [protocols]);
+
+ useEffect(() => {
+ localStorage.setItem(LAST_SERVER_KEY, roomServer);
+ }, [roomServer]);
+
+ useEffect(() => {
+ localStorage.setItem(LAST_INSTANCE_KEY, instanceId);
+ }, [instanceId]);
+
+ return {
+ ready,
+ loading,
+ publicRooms,
+ protocols,
+ roomServer,
+ instanceId,
+ search,
+ setConfig,
+ } as const;
+};
diff --git a/src/hooks/useUserDirectory.ts b/src/hooks/useUserDirectory.ts
new file mode 100644
index 00000000000..cb7307af2ac
--- /dev/null
+++ b/src/hooks/useUserDirectory.ts
@@ -0,0 +1,64 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { useCallback, useState } from "react";
+
+import { MatrixClientPeg } from "../MatrixClientPeg";
+import { DirectoryMember } from "../utils/direct-messages";
+
+export interface IUserDirectoryOpts {
+ limit: number;
+ query?: string;
+}
+
+export const useUserDirectory = () => {
+ const [users, setUsers] = useState([]);
+
+ const [loading, setLoading] = useState(false);
+
+ const search = useCallback(async ({
+ limit = 20,
+ query: term,
+ }: IUserDirectoryOpts): Promise => {
+ if (!term?.length) {
+ setUsers([]);
+ return true;
+ }
+
+ try {
+ setLoading(true);
+ const { results } = await MatrixClientPeg.get().searchUserDirectory({
+ limit,
+ term,
+ });
+ setUsers(results.map(user => new DirectoryMember(user)));
+ return true;
+ } catch (e) {
+ console.error("Could not fetch user in user directory for params", { limit, term }, e);
+ setUsers([]);
+ return false;
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ return {
+ ready: true,
+ loading,
+ users,
+ search,
+ } as const;
+};
diff --git a/src/rageshake/rageshake.ts b/src/rageshake/rageshake.ts
index 44a60acd08c..e8461eef763 100644
--- a/src/rageshake/rageshake.ts
+++ b/src/rageshake/rageshake.ts
@@ -39,6 +39,7 @@ limitations under the License.
// the frequency with which we flush to indexeddb
import { logger } from "matrix-js-sdk/src/logger";
+import { randomString } from "matrix-js-sdk/src/randomstring";
import { getCircularReplacer } from "../utils/JSON";
@@ -81,7 +82,7 @@ export class ConsoleLogger {
this.originalFunctions[fnName](...args);
}
- private log(level: string, ...args: (Error | DOMException | object | string)[]): void {
+ public log(level: string, ...args: (Error | DOMException | object | string)[]): void {
// We don't know what locale the user may be running so use ISO strings
const ts = new Date().toISOString();
@@ -140,7 +141,7 @@ export class IndexedDBLogStore {
private indexedDB: IDBFactory,
private logger: ConsoleLogger,
) {
- this.id = "instance-" + Math.random() + Date.now();
+ this.id = "instance-" + randomString(16);
}
/**
diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx
index a5ca0dbf843..e5cf0b998c2 100644
--- a/src/settings/Settings.tsx
+++ b/src/settings/Settings.tsx
@@ -45,6 +45,7 @@ import { ImageSize } from "./enums/ImageSize";
import { MetaSpace } from "../stores/spaces";
import SdkConfig from "../SdkConfig";
import ThreadBetaController from './controllers/ThreadBetaController';
+import { FontWatcher } from "./watchers/FontWatcher";
// These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
const LEVELS_ROOM_SETTINGS = [
@@ -434,7 +435,7 @@ export const SETTINGS: {[setting: string]: ISetting} = {
"baseFontSize": {
displayName: _td("Font size"),
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
- default: 10,
+ default: FontWatcher.DEFAULT_SIZE,
controller: new FontSizeController(),
},
"useCustomFontSize": {
@@ -1003,6 +1004,10 @@ export const SETTINGS: {[setting: string]: ISetting} = {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
default: false,
},
+ "debug_registration": {
+ supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
+ default: false,
+ },
"audioInputMuted": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
default: false,
diff --git a/src/settings/watchers/FontWatcher.ts b/src/settings/watchers/FontWatcher.ts
index c70dd78349f..cacbcb6862a 100644
--- a/src/settings/watchers/FontWatcher.ts
+++ b/src/settings/watchers/FontWatcher.ts
@@ -20,9 +20,12 @@ import IWatcher from "./Watcher";
import { toPx } from '../../utils/units';
import { Action } from '../../dispatcher/actions';
import { SettingLevel } from "../SettingLevel";
+import { UpdateSystemFontPayload } from "../../dispatcher/payloads/UpdateSystemFontPayload";
+import { ActionPayload } from "../../dispatcher/payloads";
export class FontWatcher implements IWatcher {
public static readonly MIN_SIZE = 8;
+ public static readonly DEFAULT_SIZE = 10;
public static readonly MAX_SIZE = 15;
// Externally we tell the user the font is size 15. Internally we use 10.
public static readonly SIZE_DIFF = 5;
@@ -34,11 +37,7 @@ export class FontWatcher implements IWatcher {
}
public start() {
- this.setRootFontSize(SettingsStore.getValue("baseFontSize"));
- this.setSystemFont({
- useSystemFont: SettingsStore.getValue("useSystemFont"),
- font: SettingsStore.getValue("systemFont"),
- });
+ this.updateFont();
this.dispatcherRef = dis.register(this.onAction);
}
@@ -46,15 +45,33 @@ export class FontWatcher implements IWatcher {
dis.unregister(this.dispatcherRef);
}
- private onAction = (payload) => {
+ private updateFont() {
+ this.setRootFontSize(SettingsStore.getValue("baseFontSize"));
+ this.setSystemFont({
+ useSystemFont: SettingsStore.getValue("useSystemFont"),
+ font: SettingsStore.getValue("systemFont"),
+ });
+ }
+
+ private onAction = (payload: ActionPayload) => {
if (payload.action === Action.UpdateFontSize) {
this.setRootFontSize(payload.size);
} else if (payload.action === Action.UpdateSystemFont) {
- this.setSystemFont(payload);
+ this.setSystemFont(payload as UpdateSystemFontPayload);
+ } else if (payload.action === Action.OnLoggedOut) {
+ // Clear font overrides when logging out
+ this.setRootFontSize(FontWatcher.DEFAULT_SIZE);
+ this.setSystemFont({
+ useSystemFont: false,
+ font: "",
+ });
+ } else if (payload.action === Action.OnLoggedIn) {
+ // Font size can be saved on the account, so grab value when logging in
+ this.updateFont();
}
};
- private setRootFontSize = (size) => {
+ private setRootFontSize = (size: number) => {
const fontSize = Math.max(Math.min(FontWatcher.MAX_SIZE, size), FontWatcher.MIN_SIZE);
if (fontSize !== size) {
@@ -63,7 +80,21 @@ export class FontWatcher implements IWatcher {
document.querySelector(":root").style.fontSize = toPx(fontSize);
};
- private setSystemFont = ({ useSystemFont, font }) => {
- document.body.style.fontFamily = useSystemFont ? font : "";
+ private setSystemFont = ({ useSystemFont, font }: Pick) => {
+ if (useSystemFont) {
+ // Make sure that fonts with spaces in their names get interpreted properly
+ document.body.style.fontFamily = font
+ .split(',')
+ .map(font => {
+ font = font.trim();
+ if (!font.startsWith('"') && !font.endsWith('"')) {
+ font = `"${font}"`;
+ }
+ return font;
+ })
+ .join(',');
+ } else {
+ document.body.style.fontFamily = "";
+ }
};
}
diff --git a/src/stores/LifecycleStore.ts b/src/stores/LifecycleStore.ts
index 618f4b4162f..5d10ed3e396 100644
--- a/src/stores/LifecycleStore.ts
+++ b/src/stores/LifecycleStore.ts
@@ -71,7 +71,7 @@ class LifecycleStore extends Store {
break;
}
case 'on_client_not_viable':
- case 'on_logged_out':
+ case Action.OnLoggedOut:
this.reset();
break;
}
diff --git a/src/stores/ReadyWatchingStore.ts b/src/stores/ReadyWatchingStore.ts
index c44664a08e7..a142693e62c 100644
--- a/src/stores/ReadyWatchingStore.ts
+++ b/src/stores/ReadyWatchingStore.ts
@@ -22,6 +22,7 @@ import { EventEmitter } from "events";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { ActionPayload } from "../dispatcher/payloads";
import { IDestroyable } from "../utils/IDestroyable";
+import { Action } from "../dispatcher/actions";
export abstract class ReadyWatchingStore extends EventEmitter implements IDestroyable {
protected matrixClient: MatrixClient;
@@ -83,7 +84,7 @@ export abstract class ReadyWatchingStore extends EventEmitter implements IDestro
this.matrixClient = payload.matrixClient;
await this.onReady();
}
- } else if (payload.action === 'on_client_not_viable' || payload.action === 'on_logged_out') {
+ } else if (payload.action === 'on_client_not_viable' || payload.action === Action.OnLoggedOut) {
if (this.matrixClient) {
await this.onNotReady();
this.matrixClient = null;
diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx
index f9871c57528..d8259097a2a 100644
--- a/src/stores/RoomViewStore.tsx
+++ b/src/stores/RoomViewStore.tsx
@@ -241,7 +241,7 @@ export class RoomViewStore extends Store {
break;
}
case 'on_client_not_viable':
- case 'on_logged_out':
+ case Action.OnLoggedOut:
this.reset();
break;
case 'reply_to_event':
diff --git a/src/stores/SetupEncryptionStore.ts b/src/stores/SetupEncryptionStore.ts
index b5df05b2ff4..38ba0bd9b0a 100644
--- a/src/stores/SetupEncryptionStore.ts
+++ b/src/stores/SetupEncryptionStore.ts
@@ -89,9 +89,7 @@ export class SetupEncryptionStore extends EventEmitter {
return;
}
this.started = false;
- if (this.verificationRequest) {
- this.verificationRequest.off(VerificationRequestEvent.Change, this.onVerificationRequestChange);
- }
+ this.verificationRequest?.off(VerificationRequestEvent.Change, this.onVerificationRequestChange);
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener(CryptoEvent.VerificationRequest, this.onVerificationRequest);
MatrixClientPeg.get().removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged);
@@ -99,6 +97,7 @@ export class SetupEncryptionStore extends EventEmitter {
}
public async fetchKeyInfo(): Promise {
+ if (!this.started) return; // bail if we were stopped
const cli = MatrixClientPeg.get();
const keys = await cli.isSecretStored('m.cross_signing.master');
if (keys === null || Object.keys(keys).length === 0) {
@@ -270,6 +269,7 @@ export class SetupEncryptionStore extends EventEmitter {
}
private async setActiveVerificationRequest(request: VerificationRequest): Promise {
+ if (!this.started) return; // bail if we were stopped
if (request.otherUserId !== MatrixClientPeg.get().getUserId()) return;
if (this.verificationRequest) {
diff --git a/src/stores/VideoChannelStore.ts b/src/stores/VideoChannelStore.ts
index 9ab521b50ff..8d7b32a94a6 100644
--- a/src/stores/VideoChannelStore.ts
+++ b/src/stores/VideoChannelStore.ts
@@ -136,14 +136,40 @@ export default class VideoChannelStore extends AsyncStoreWithClient {
}
}
+ // Now that we got the messaging, we need a way to ensure that it doesn't get stopped
+ const dontStopMessaging = new Promise((resolve, reject) => {
+ const listener = (uid: string) => {
+ if (uid === jitsiUid) {
+ cleanup();
+ reject(new Error("Messaging stopped"));
+ }
+ };
+ const done = () => {
+ cleanup();
+ resolve();
+ };
+ const cleanup = () => {
+ messagingStore.off(WidgetMessagingStoreEvent.StopMessaging, listener);
+ this.off(VideoChannelEvent.Connect, done);
+ this.off(VideoChannelEvent.Disconnect, done);
+ };
+
+ messagingStore.on(WidgetMessagingStoreEvent.StopMessaging, listener);
+ this.on(VideoChannelEvent.Connect, done);
+ this.on(VideoChannelEvent.Disconnect, done);
+ });
+
if (!messagingStore.isWidgetReady(jitsiUid)) {
// Wait for the widget to be ready to receive our join event
try {
- await waitForEvent(
- messagingStore,
- WidgetMessagingStoreEvent.WidgetReady,
- (uid: string) => uid === jitsiUid,
- );
+ await Promise.race([
+ waitForEvent(
+ messagingStore,
+ WidgetMessagingStoreEvent.WidgetReady,
+ (uid: string) => uid === jitsiUid,
+ ),
+ dontStopMessaging,
+ ]);
} catch (e) {
throw new Error(`Video channel in room ${roomId} never became ready: ${e}`);
}
@@ -178,11 +204,12 @@ export default class VideoChannelStore extends AsyncStoreWithClient {
videoDevice: videoDevice?.label,
});
try {
- await waitForJoin;
+ await Promise.race([waitForJoin, dontStopMessaging]);
} catch (e) {
// If it timed out, clean up our advance preparations
this.activeChannel = null;
this.roomId = null;
+
messaging.off(`action:${ElementWidgetActions.CallParticipants}`, this.onParticipants);
messaging.off(`action:${ElementWidgetActions.MuteAudio}`, this.onMuteAudio);
messaging.off(`action:${ElementWidgetActions.UnmuteAudio}`, this.onUnmuteAudio);
@@ -190,6 +217,11 @@ export default class VideoChannelStore extends AsyncStoreWithClient {
messaging.off(`action:${ElementWidgetActions.UnmuteVideo}`, this.onUnmuteVideo);
messaging.off(`action:${ElementWidgetActions.HangupCall}`, this.onHangup);
+ if (messaging.transport.ready) {
+ // The messaging still exists, which means Jitsi might still be going in the background
+ messaging.transport.send(ElementWidgetActions.ForceHangupCall, {});
+ }
+
this.emit(VideoChannelEvent.Disconnect, roomId);
throw new Error(`Failed to join call in room ${roomId}: ${e}`);
diff --git a/src/stores/notifications/RoomNotificationStateStore.ts b/src/stores/notifications/RoomNotificationStateStore.ts
index 887e1a7332c..3409f657a8d 100644
--- a/src/stores/notifications/RoomNotificationStateStore.ts
+++ b/src/stores/notifications/RoomNotificationStateStore.ts
@@ -124,7 +124,8 @@ export class RoomNotificationStateStore extends AsyncStoreWithClient {
if (this.globalState.symbol !== globalState.symbol ||
this.globalState.count !== globalState.count ||
this.globalState.color !== globalState.color ||
- this.globalState.numUnreadStates !== globalState.numUnreadStates
+ this.globalState.numUnreadStates !== globalState.numUnreadStates ||
+ state !== prevState
) {
this._globalState = globalState;
this.emit(UPDATE_STATUS_INDICATOR, globalState, state, prevState, data);
diff --git a/src/stores/spaces/SpaceStore.ts b/src/stores/spaces/SpaceStore.ts
index 0d9d55e8897..0bdde6a2c30 100644
--- a/src/stores/spaces/SpaceStore.ts
+++ b/src/stores/spaces/SpaceStore.ts
@@ -1081,6 +1081,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
?.["m.room_versions"]?.["org.matrix.msc3244.room_capabilities"]?.["restricted"];
});
+ const oldMetaSpaces = this._enabledMetaSpaces;
const enabledMetaSpaces = SettingsStore.getValue("Spaces.enabledMetaSpaces");
this._enabledMetaSpaces = metaSpaceOrder.filter(k => enabledMetaSpaces[k]);
@@ -1090,6 +1091,11 @@ export class SpaceStoreClass extends AsyncStoreWithClient {
this.sendUserProperties();
this.rebuildSpaceHierarchy(); // trigger an initial update
+ // rebuildSpaceHierarchy will only send an update if the spaces have changed.
+ // If only the meta spaces have changed, we need to send an update ourselves.
+ if (arrayHasDiff(oldMetaSpaces, this._enabledMetaSpaces)) {
+ this.emit(UPDATE_TOP_LEVEL_SPACES, this.spacePanelSpaces, this.enabledMetaSpaces);
+ }
// restore selected state from last session if any and still valid
const lastSpaceId = window.localStorage.getItem(ACTIVE_SPACE_LS_KEY);
diff --git a/src/stores/widgets/ElementWidgetActions.ts b/src/stores/widgets/ElementWidgetActions.ts
index 117c4b47f3a..7ad41885be9 100644
--- a/src/stores/widgets/ElementWidgetActions.ts
+++ b/src/stores/widgets/ElementWidgetActions.ts
@@ -21,6 +21,7 @@ export enum ElementWidgetActions {
WidgetReady = "io.element.widget_ready",
JoinCall = "io.element.join",
HangupCall = "im.vector.hangup",
+ ForceHangupCall = "io.element.force_hangup",
CallParticipants = "io.element.participants",
MuteAudio = "io.element.mute_audio",
UnmuteAudio = "io.element.unmute_audio",
@@ -35,6 +36,12 @@ export enum ElementWidgetActions {
ViewRoom = "io.element.view_room",
}
+export interface IHangupCallApiRequest extends IWidgetApiRequest {
+ data: {
+ errorMessage?: string;
+ };
+}
+
/**
* @deprecated Use MSC2931 instead
*/
diff --git a/src/stores/widgets/StopGapWidget.ts b/src/stores/widgets/StopGapWidget.ts
index 5f95e441093..1cc0ebc74bf 100644
--- a/src/stores/widgets/StopGapWidget.ts
+++ b/src/stores/widgets/StopGapWidget.ts
@@ -37,6 +37,7 @@ import { MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event";
import { logger } from "matrix-js-sdk/src/logger";
import { ClientEvent } from "matrix-js-sdk/src/client";
+import { _t } from "../../languageHandler";
import { StopGapWidgetDriver } from "./StopGapWidgetDriver";
import { WidgetMessagingStore } from "./WidgetMessagingStore";
import { RoomViewStore } from "../RoomViewStore";
@@ -50,7 +51,7 @@ import ActiveWidgetStore from "../ActiveWidgetStore";
import { objectShallowClone } from "../../utils/objects";
import defaultDispatcher from "../../dispatcher/dispatcher";
import { Action } from "../../dispatcher/actions";
-import { ElementWidgetActions, IViewRoomApiRequest } from "./ElementWidgetActions";
+import { ElementWidgetActions, IHangupCallApiRequest, IViewRoomApiRequest } from "./ElementWidgetActions";
import { ModalWidgetStore } from "../ModalWidgetStore";
import ThemeWatcher from "../../settings/watchers/ThemeWatcher";
import { ElementWidgetCapabilities } from "./ElementWidgetCapabilities";
@@ -59,6 +60,8 @@ import { getUserLanguage } from "../../languageHandler";
import { WidgetVariableCustomisations } from "../../customisations/WidgetVariables";
import { arrayFastClone } from "../../utils/arrays";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
+import Modal from "../../Modal";
+import ErrorDialog from "../../components/views/dialogs/ErrorDialog";
// TODO: Destroy all of this code
@@ -353,6 +356,21 @@ export class StopGapWidget extends EventEmitter {
},
);
}
+
+ if (WidgetType.JITSI.matches(this.mockWidget.type)) {
+ this.messaging.on(`action:${ElementWidgetActions.HangupCall}`,
+ (ev: CustomEvent) => {
+ if (ev.detail.data?.errorMessage) {
+ Modal.createTrackedDialog("Connection lost", "", ErrorDialog, {
+ title: _t("Connection lost"),
+ description: _t("You were disconnected from the call. (Error: %(message)s)", {
+ message: ev.detail.data.errorMessage,
+ }),
+ });
+ }
+ },
+ );
+ }
}
public async prepare(): Promise {
diff --git a/src/stores/widgets/WidgetMessagingStore.ts b/src/stores/widgets/WidgetMessagingStore.ts
index bcc46c0e43a..686f222a1f7 100644
--- a/src/stores/widgets/WidgetMessagingStore.ts
+++ b/src/stores/widgets/WidgetMessagingStore.ts
@@ -25,6 +25,7 @@ import WidgetUtils from "../../utils/WidgetUtils";
export enum WidgetMessagingStoreEvent {
StoreMessaging = "store_messaging",
+ StopMessaging = "stop_messaging",
WidgetReady = "widget_ready",
}
@@ -71,9 +72,7 @@ export class WidgetMessagingStore extends AsyncStoreWithClient {
}
public stopMessaging(widget: Widget, roomId: string) {
- const uid = WidgetUtils.calcWidgetUid(widget.id, roomId);
- this.widgetMap.remove(uid)?.stop();
- this.readyWidgets.delete(uid);
+ this.stopMessagingByUid(WidgetUtils.calcWidgetUid(widget.id, roomId));
}
public getMessaging(widget: Widget, roomId: string): ClientWidgetApi {
@@ -86,6 +85,8 @@ export class WidgetMessagingStore extends AsyncStoreWithClient {
*/
public stopMessagingByUid(widgetUid: string) {
this.widgetMap.remove(widgetUid)?.stop();
+ this.readyWidgets.delete(widgetUid);
+ this.emit(WidgetMessagingStoreEvent.StopMessaging, widgetUid);
}
/**
diff --git a/src/utils/WellKnownUtils.ts b/src/utils/WellKnownUtils.ts
index e41adabb903..451f956f16f 100644
--- a/src/utils/WellKnownUtils.ts
+++ b/src/utils/WellKnownUtils.ts
@@ -24,6 +24,7 @@ const E2EE_WK_KEY = "io.element.e2ee";
const E2EE_WK_KEY_DEPRECATED = "im.vector.riot.e2ee";
export const TILE_SERVER_WK_KEY = new UnstableValue(
"m.tile_server", "org.matrix.msc3488.tile_server");
+const EMBEDDED_PAGES_WK_PROPERTY = "io.element.embedded_pages";
/* eslint-disable camelcase */
export interface ICallBehaviourWellKnown {
@@ -39,6 +40,10 @@ export interface IE2EEWellKnown {
export interface ITileServerWellKnown {
map_style_url?: string;
}
+
+export interface IEmbeddedPagesWellKnown {
+ home_url?: string;
+}
/* eslint-enable camelcase */
export function getCallBehaviourWellKnown(): ICallBehaviourWellKnown {
@@ -70,6 +75,16 @@ export function tileServerFromWellKnown(
);
}
+export function getEmbeddedPagesWellKnown(): IEmbeddedPagesWellKnown | undefined {
+ return embeddedPagesFromWellKnown(MatrixClientPeg.get()?.getClientWellKnown());
+}
+
+export function embeddedPagesFromWellKnown(
+ clientWellKnown?: IClientWellKnown,
+): IEmbeddedPagesWellKnown {
+ return (clientWellKnown?.[EMBEDDED_PAGES_WK_PROPERTY]);
+}
+
export function isSecureBackupRequired(): boolean {
const wellKnown = getE2EEWellKnown();
return wellKnown && wellKnown["secure_backup_required"] === true;
diff --git a/src/utils/WidgetUtils.ts b/src/utils/WidgetUtils.ts
index b2f33b22253..8eebed3871c 100644
--- a/src/utils/WidgetUtils.ts
+++ b/src/utils/WidgetUtils.ts
@@ -286,6 +286,7 @@ export default class WidgetUtils {
widgetUrl?: string,
widgetName?: string,
widgetData?: object,
+ widgetAvatarUrl?: string,
) {
let content;
@@ -299,6 +300,7 @@ export default class WidgetUtils {
url: widgetUrl,
name: widgetName,
data: widgetData,
+ avatar_url: widgetAvatarUrl,
};
} else {
content = {};
diff --git a/src/utils/location/map.ts b/src/utils/location/map.ts
index b3b74d14495..5c5ab34e18c 100644
--- a/src/utils/location/map.ts
+++ b/src/utils/location/map.ts
@@ -36,7 +36,9 @@ export const createMap = (
style: styleUrl,
zoom: 15,
interactive,
+ attributionControl: false,
});
+ map.addControl(new maplibregl.AttributionControl(), 'top-right');
map.on('error', (e) => {
logger.error(
@@ -63,7 +65,7 @@ export const createMarker = (coords: GeolocationCoordinates, element: HTMLElemen
return marker;
};
-const makeLink = (coords: GeolocationCoordinates): string => {
+export const makeMapSiteLink = (coords: GeolocationCoordinates): string => {
return (
"https://www.openstreetmap.org/" +
`?mlat=${coords.latitude}` +
@@ -72,18 +74,18 @@ const makeLink = (coords: GeolocationCoordinates): string => {
);
};
-export const createMapSiteLink = (event: MatrixEvent): string => {
+export const createMapSiteLinkFromEvent = (event: MatrixEvent): string => {
const content: Object = event.getContent();
const mLocation = content[M_LOCATION.name];
if (mLocation !== undefined) {
const uri = mLocation["uri"];
if (uri !== undefined) {
- return makeLink(parseGeoUri(uri));
+ return makeMapSiteLink(parseGeoUri(uri));
}
} else {
const geoUri = content["geo_uri"];
if (geoUri) {
- return makeLink(parseGeoUri(geoUri));
+ return makeMapSiteLink(parseGeoUri(geoUri));
}
}
return null;
diff --git a/src/utils/pages.ts b/src/utils/pages.ts
index 03bab1563b4..75e4fef9bf6 100644
--- a/src/utils/pages.ts
+++ b/src/utils/pages.ts
@@ -17,6 +17,7 @@ limitations under the License.
import { logger } from "matrix-js-sdk/src/logger";
import { IConfigOptions } from "../IConfigOptions";
+import { getEmbeddedPagesWellKnown } from '../utils/WellKnownUtils';
import { SnakedObject } from "./SnakedObject";
export function getHomePageUrl(appConfig: IConfigOptions): string | null {
@@ -38,6 +39,10 @@ export function getHomePageUrl(appConfig: IConfigOptions): string | null {
}
}
+ if (!pageUrl) {
+ pageUrl = getEmbeddedPagesWellKnown()?.home_url;
+ }
+
return pageUrl;
}
diff --git a/test/CallHandler-test.ts b/test/CallHandler-test.ts
index 01c1085032e..6a4f29aaa17 100644
--- a/test/CallHandler-test.ts
+++ b/test/CallHandler-test.ts
@@ -21,12 +21,10 @@ import EventEmitter from 'events';
import CallHandler, {
CallHandlerEvent, PROTOCOL_PSTN, PROTOCOL_PSTN_PREFIXED, PROTOCOL_SIP_NATIVE, PROTOCOL_SIP_VIRTUAL,
} from '../src/CallHandler';
-import { stubClient, mkStubRoom } from './test-utils';
+import { stubClient, mkStubRoom, untilDispatch } from './test-utils';
import { MatrixClientPeg } from '../src/MatrixClientPeg';
-import dis from '../src/dispatcher/dispatcher';
import DMRoomMap from '../src/utils/DMRoomMap';
import SdkConfig from '../src/SdkConfig';
-import { ActionPayload } from '../src/dispatcher/payloads';
import { Action } from "../src/dispatcher/actions";
// The Matrix IDs that the user sees when talking to Alice & Bob
@@ -95,18 +93,6 @@ class FakeCall extends EventEmitter {
}
}
-function untilDispatch(waitForAction: string): Promise {
- let dispatchHandle;
- return new Promise(resolve => {
- dispatchHandle = dis.register(payload => {
- if (payload.action === waitForAction) {
- dis.unregister(dispatchHandle);
- resolve(payload);
- }
- });
- });
-}
-
function untilCallHandlerEvent(callHandler: CallHandler, event: CallHandlerEvent): Promise {
return new Promise((resolve) => {
callHandler.addListener(event, () => {
diff --git a/test/components/views/beacon/BeaconViewDialog-test.tsx b/test/components/views/beacon/BeaconViewDialog-test.tsx
index 8d0fb30e307..12b40939392 100644
--- a/test/components/views/beacon/BeaconViewDialog-test.tsx
+++ b/test/components/views/beacon/BeaconViewDialog-test.tsx
@@ -89,6 +89,10 @@ describe(' ', () => {
const getComponent = (props = {}) =>
mount( );
+ beforeAll(() => {
+ maplibregl.AttributionControl = jest.fn();
+ });
+
beforeEach(() => {
jest.spyOn(OwnBeaconStore.instance, 'getLiveBeaconIds').mockRestore();
diff --git a/test/components/views/beacon/ShareLatestLocation-test.tsx b/test/components/views/beacon/ShareLatestLocation-test.tsx
new file mode 100644
index 00000000000..28d36bc9772
--- /dev/null
+++ b/test/components/views/beacon/ShareLatestLocation-test.tsx
@@ -0,0 +1,59 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React from 'react';
+import { mount } from 'enzyme';
+import { act } from 'react-dom/test-utils';
+
+import ShareLatestLocation from '../../../../src/components/views/beacon/ShareLatestLocation';
+import { copyPlaintext } from '../../../../src/utils/strings';
+import { flushPromises } from '../../../test-utils';
+
+jest.mock('../../../../src/utils/strings', () => ({
+ copyPlaintext: jest.fn().mockResolvedValue(undefined),
+}));
+
+describe(' ', () => {
+ const defaultProps = {
+ latestLocationState: {
+ uri: 'geo:51,42;u=35',
+ timestamp: 123,
+ },
+ };
+ const getComponent = (props = {}) =>
+ mount( );
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('renders null when no location', () => {
+ const component = getComponent({ latestLocationState: undefined });
+ expect(component.html()).toBeNull();
+ });
+
+ it('renders share buttons when there is a location', async () => {
+ const component = getComponent();
+ expect(component).toMatchSnapshot();
+
+ await act(async () => {
+ component.find('.mx_CopyableText_copyButton').at(0).simulate('click');
+ await flushPromises();
+ });
+
+ expect(copyPlaintext).toHaveBeenCalledWith('51,42');
+ });
+});
diff --git a/test/components/views/beacon/__snapshots__/BeaconListItem-test.tsx.snap b/test/components/views/beacon/__snapshots__/BeaconListItem-test.tsx.snap
index 1518a60dba9..221d534c029 100644
--- a/test/components/views/beacon/__snapshots__/BeaconListItem-test.tsx.snap
+++ b/test/components/views/beacon/__snapshots__/BeaconListItem-test.tsx.snap
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[` when a beacon is live and has locations renders beacon info 1`] = `"
Alice's car Live until 16:04
Updated a few seconds ago "`;
+exports[` when a beacon is live and has locations renders beacon info 1`] = `"
Alice's car Live until 16:04
Updated a few seconds ago "`;
diff --git a/test/components/views/beacon/__snapshots__/BeaconViewDialog-test.tsx.snap b/test/components/views/beacon/__snapshots__/BeaconViewDialog-test.tsx.snap
index 59e47767817..648ed3e93fa 100644
--- a/test/components/views/beacon/__snapshots__/BeaconViewDialog-test.tsx.snap
+++ b/test/components/views/beacon/__snapshots__/BeaconViewDialog-test.tsx.snap
@@ -1,37 +1,83 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[` renders a fallback when no live beacons remain 1`] = `
-
-
-
- No live locations
-
-
+
+
+
+ No live locations
+
+
+
+ Close
+
+
+
+ ,
+
+
+
+ No live locations
+
+
- Close
-
-
-
+
+ Close
+
+
+
,
+]
`;
diff --git a/test/components/views/beacon/__snapshots__/ShareLatestLocation-test.tsx.snap b/test/components/views/beacon/__snapshots__/ShareLatestLocation-test.tsx.snap
new file mode 100644
index 00000000000..5f55d3103d0
--- /dev/null
+++ b/test/components/views/beacon/__snapshots__/ShareLatestLocation-test.tsx.snap
@@ -0,0 +1,79 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`
renders share buttons when there is a location 1`] = `
+
+
+
+
+
+
+
+
+`;
diff --git a/test/components/views/elements/AccessibleButton-test.tsx b/test/components/views/elements/AccessibleButton-test.tsx
new file mode 100644
index 00000000000..89385dd0577
--- /dev/null
+++ b/test/components/views/elements/AccessibleButton-test.tsx
@@ -0,0 +1,204 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React from 'react';
+import { mount } from 'enzyme';
+import { act } from 'react-dom/test-utils';
+
+import AccessibleButton from '../../../../src/components/views/elements/AccessibleButton';
+import { Key } from '../../../../src/Keyboard';
+import { mockPlatformPeg, unmockPlatformPeg } from '../../../test-utils';
+
+describe('
', () => {
+ const defaultProps = {
+ onClick: jest.fn(),
+ children: 'i am a button',
+ };
+ const getComponent = (props = {}) =>
+ mount(
);
+
+ beforeEach(() => {
+ mockPlatformPeg();
+ });
+
+ afterAll(() => {
+ unmockPlatformPeg();
+ });
+
+ const makeKeyboardEvent = (key: string) => ({
+ key,
+ stopPropagation: jest.fn(),
+ preventDefault: jest.fn(),
+ }) as unknown as KeyboardEvent;
+
+ it('renders div with role button by default', () => {
+ const component = getComponent();
+ expect(component).toMatchSnapshot();
+ });
+
+ it('renders a button element', () => {
+ const component = getComponent({ element: 'button' });
+ expect(component).toMatchSnapshot();
+ });
+
+ it('renders with correct classes when button has kind', () => {
+ const component = getComponent({
+ kind: 'primary',
+ });
+ expect(component).toMatchSnapshot();
+ });
+
+ it('disables button correctly', () => {
+ const onClick = jest.fn();
+ const component = getComponent({
+ onClick,
+ disabled: true,
+ });
+ expect(component.find('.mx_AccessibleButton').props().disabled).toBeTruthy();
+ expect(component.find('.mx_AccessibleButton').props()['aria-disabled']).toBeTruthy();
+
+ act(() => {
+ component.simulate('click');
+ });
+
+ expect(onClick).not.toHaveBeenCalled();
+
+ act(() => {
+ const keydownEvent = makeKeyboardEvent(Key.ENTER);
+ component.simulate('keydown', keydownEvent);
+ });
+
+ expect(onClick).not.toHaveBeenCalled();
+ });
+
+ it('calls onClick handler on button click', () => {
+ const onClick = jest.fn();
+ const component = getComponent({
+ onClick,
+ });
+
+ act(() => {
+ component.simulate('click');
+ });
+
+ expect(onClick).toHaveBeenCalled();
+ });
+
+ it('calls onClick handler on button mousedown when triggerOnMousedown is passed', () => {
+ const onClick = jest.fn();
+ const component = getComponent({
+ onClick,
+ triggerOnMouseDown: true,
+ });
+
+ act(() => {
+ component.simulate('mousedown');
+ });
+
+ expect(onClick).toHaveBeenCalled();
+ });
+
+ describe('handling keyboard events', () => {
+ it('calls onClick handler on enter keydown', () => {
+ const onClick = jest.fn();
+ const component = getComponent({
+ onClick,
+ });
+
+ const keyboardEvent = makeKeyboardEvent(Key.ENTER);
+ act(() => {
+ component.simulate('keydown', keyboardEvent);
+ });
+
+ expect(onClick).toHaveBeenCalled();
+
+ act(() => {
+ component.simulate('keyup', keyboardEvent);
+ });
+
+ // handler only called once on keydown
+ expect(onClick).toHaveBeenCalledTimes(1);
+ // called for both keyup and keydown
+ expect(keyboardEvent.stopPropagation).toHaveBeenCalledTimes(2);
+ expect(keyboardEvent.preventDefault).toHaveBeenCalledTimes(2);
+ });
+
+ it('calls onClick handler on space keyup', () => {
+ const onClick = jest.fn();
+ const component = getComponent({
+ onClick,
+ });
+
+ const keyboardEvent = makeKeyboardEvent(Key.SPACE);
+ act(() => {
+ component.simulate('keydown', keyboardEvent);
+ });
+
+ expect(onClick).not.toHaveBeenCalled();
+
+ act(() => {
+ component.simulate('keyup', keyboardEvent);
+ });
+
+ // handler only called once on keyup
+ expect(onClick).toHaveBeenCalledTimes(1);
+ // called for both keyup and keydown
+ expect(keyboardEvent.stopPropagation).toHaveBeenCalledTimes(2);
+ expect(keyboardEvent.preventDefault).toHaveBeenCalledTimes(2);
+ });
+
+ it('calls onKeydown/onKeyUp handlers for keys other than space and enter', () => {
+ const onClick = jest.fn();
+ const onKeyDown = jest.fn();
+ const onKeyUp = jest.fn();
+ const component = getComponent({
+ onClick,
+ onKeyDown,
+ onKeyUp,
+ });
+
+ const keyboardEvent = makeKeyboardEvent(Key.K);
+ act(() => {
+ component.simulate('keydown', keyboardEvent);
+ component.simulate('keyup', keyboardEvent);
+ });
+
+ expect(onClick).not.toHaveBeenCalled();
+ expect(onKeyDown).toHaveBeenCalled();
+ expect(onKeyUp).toHaveBeenCalled();
+ expect(keyboardEvent.stopPropagation).not.toHaveBeenCalled();
+ expect(keyboardEvent.preventDefault).not.toHaveBeenCalled();
+ });
+
+ it('does nothing on non space/enter key presses when no onKeydown/onKeyUp handlers provided', () => {
+ const onClick = jest.fn();
+ const component = getComponent({
+ onClick,
+ });
+
+ const keyboardEvent = makeKeyboardEvent(Key.K);
+ act(() => {
+ component.simulate('keydown', keyboardEvent);
+ component.simulate('keyup', keyboardEvent);
+ });
+
+ // no onClick call, no problems
+ expect(onClick).not.toHaveBeenCalled();
+ expect(keyboardEvent.stopPropagation).not.toHaveBeenCalled();
+ expect(keyboardEvent.preventDefault).not.toHaveBeenCalled();
+ });
+ });
+});
diff --git a/test/components/views/elements/LabelledCheckbox-test.tsx b/test/components/views/elements/LabelledCheckbox-test.tsx
new file mode 100644
index 00000000000..b03ee0c1f18
--- /dev/null
+++ b/test/components/views/elements/LabelledCheckbox-test.tsx
@@ -0,0 +1,124 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React from 'react';
+import { mount } from 'enzyme';
+import { act } from "react-dom/test-utils";
+
+import LabelledCheckbox from "../../../../src/components/views/elements/LabelledCheckbox";
+
+// Fake random strings to give a predictable snapshot for checkbox IDs
+jest.mock(
+ 'matrix-js-sdk/src/randomstring',
+ () => {
+ return {
+ randomString: () => "abdefghi",
+ };
+ },
+);
+
+describe('
', () => {
+ type CompProps = React.ComponentProps
;
+ const getComponent = (props: CompProps) => mount( );
+ type CompClass = ReturnType;
+
+ const getCheckbox = (component: CompClass) => component.find(`input[type="checkbox"]`);
+ const getLabel = (component: CompClass) => component.find(`.mx_LabelledCheckbox_label`);
+ const getByline = (component: CompClass) => component.find(`.mx_LabelledCheckbox_byline`);
+
+ const isChecked = (checkbox: ReturnType) => checkbox.is(`[checked=true]`);
+ const isDisabled = (checkbox: ReturnType) => checkbox.is(`[disabled=true]`);
+ const getText = (span: ReturnType) => span.length > 0 ? span.at(0).text() : null;
+
+ test.each([null, "this is a byline"])(
+ "should render with byline of %p",
+ (byline) => {
+ const props: CompProps = {
+ label: "Hello world",
+ value: true,
+ byline: byline,
+ onChange: jest.fn(),
+ };
+ const component = getComponent(props);
+ const checkbox = getCheckbox(component);
+
+ expect(component).toMatchSnapshot();
+ expect(isChecked(checkbox)).toBe(true);
+ expect(isDisabled(checkbox)).toBe(false);
+ expect(getText(getLabel(component))).toBe(props.label);
+ expect(getText(getByline(component))).toBe(byline);
+ },
+ );
+
+ it('should support unchecked by default', () => {
+ const props: CompProps = {
+ label: "Hello world",
+ value: false,
+ onChange: jest.fn(),
+ };
+ const component = getComponent(props);
+
+ expect(isChecked(getCheckbox(component))).toBe(false);
+ });
+
+ it('should be possible to disable the checkbox', () => {
+ const props: CompProps = {
+ label: "Hello world",
+ value: false,
+ disabled: true,
+ onChange: jest.fn(),
+ };
+ const component = getComponent(props);
+
+ expect(isDisabled(getCheckbox(component))).toBe(true);
+ });
+
+ it('should emit onChange calls', () => {
+ const props: CompProps = {
+ label: "Hello world",
+ value: false,
+ onChange: jest.fn(),
+ };
+ const component = getComponent(props);
+
+ expect(props.onChange).not.toHaveBeenCalled();
+
+ act(() => {
+ getCheckbox(component).simulate('change');
+ });
+
+ expect(props.onChange).toHaveBeenCalledTimes(1);
+ });
+
+ it('should react to value and disabled prop changes', () => {
+ const props: CompProps = {
+ label: "Hello world",
+ value: false,
+ onChange: jest.fn(),
+ };
+ const component = getComponent(props);
+ let checkbox = getCheckbox(component);
+
+ expect(isChecked(checkbox)).toBe(false);
+ expect(isDisabled(checkbox)).toBe(false);
+
+ component.setProps({ value: true, disabled: true });
+ checkbox = getCheckbox(component); // refresh reference to checkbox
+
+ expect(isChecked(checkbox)).toBe(true);
+ expect(isDisabled(checkbox)).toBe(true);
+ });
+});
diff --git a/test/components/views/elements/__snapshots__/AccessibleButton-test.tsx.snap b/test/components/views/elements/__snapshots__/AccessibleButton-test.tsx.snap
new file mode 100644
index 00000000000..0d049b34f7f
--- /dev/null
+++ b/test/components/views/elements/__snapshots__/AccessibleButton-test.tsx.snap
@@ -0,0 +1,62 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` renders a button element 1`] = `
+
+
+ i am a button
+
+
+`;
+
+exports[` renders div with role button by default 1`] = `
+
+
+ i am a button
+
+
+`;
+
+exports[` renders with correct classes when button has kind 1`] = `
+
+
+ i am a button
+
+
+`;
diff --git a/test/components/views/elements/__snapshots__/LabelledCheckbox-test.tsx.snap b/test/components/views/elements/__snapshots__/LabelledCheckbox-test.tsx.snap
new file mode 100644
index 00000000000..34cdbe59be9
--- /dev/null
+++ b/test/components/views/elements/__snapshots__/LabelledCheckbox-test.tsx.snap
@@ -0,0 +1,108 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` should render with byline of "this is a byline" 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hello world
+
+
+ this is a byline
+
+
+
+
+`;
+
+exports[` should render with byline of null 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hello world
+
+
+
+
+`;
diff --git a/test/components/views/elements/__snapshots__/PollCreateDialog-test.tsx.snap b/test/components/views/elements/__snapshots__/PollCreateDialog-test.tsx.snap
index 77e40f05e7d..72c7fcc8112 100644
--- a/test/components/views/elements/__snapshots__/PollCreateDialog-test.tsx.snap
+++ b/test/components/views/elements/__snapshots__/PollCreateDialog-test.tsx.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`PollCreateDialog renders a blank poll 1`] = `"
"`;
+exports[`PollCreateDialog renders a blank poll 1`] = `"
"`;
exports[`PollCreateDialog renders a question and some options 1`] = `"
"`;
diff --git a/test/components/views/location/LocationPicker-test.tsx b/test/components/views/location/LocationPicker-test.tsx
index 6dd25ae72d0..bb2f8e63489 100644
--- a/test/components/views/location/LocationPicker-test.tsx
+++ b/test/components/views/location/LocationPicker-test.tsx
@@ -186,6 +186,28 @@ describe("LocationPicker", () => {
expect(wrapper.find('MemberAvatar').length).toBeTruthy();
});
+ it('disables submit button until geolocation completes', () => {
+ const onChoose = jest.fn();
+ const wrapper = getComponent({ shareType, onChoose });
+
+ // submit button is enabled when position is truthy
+ expect(findByTestId(wrapper, 'location-picker-submit-button').at(0).props().disabled).toBeTruthy();
+ act(() => {
+ findByTestId(wrapper, 'location-picker-submit-button').at(0).simulate('click');
+ });
+ // nothing happens on button click
+ expect(onChoose).not.toHaveBeenCalled();
+
+ act(() => {
+ // @ts-ignore
+ mocked(mockGeolocate).emit('geolocate', mockGeolocationPosition);
+ wrapper.setProps({});
+ });
+
+ // submit button is enabled when position is truthy
+ expect(findByTestId(wrapper, 'location-picker-submit-button').at(0).props().disabled).toBeFalsy();
+ });
+
it('submits location', () => {
const onChoose = jest.fn();
const wrapper = getComponent({ onChoose, shareType });
diff --git a/test/components/views/location/LocationViewDialog-test.tsx b/test/components/views/location/LocationViewDialog-test.tsx
index fa23192bbfb..af270c5f974 100644
--- a/test/components/views/location/LocationViewDialog-test.tsx
+++ b/test/components/views/location/LocationViewDialog-test.tsx
@@ -18,6 +18,7 @@ import React from 'react';
import { mount } from 'enzyme';
import { RoomMember } from 'matrix-js-sdk/src/matrix';
import { LocationAssetType } from 'matrix-js-sdk/src/@types/location';
+import maplibregl from 'maplibre-gl';
import LocationViewDialog from '../../../../src/components/views/location/LocationViewDialog';
import { TILE_SERVER_WK_KEY } from '../../../../src/utils/WellKnownUtils';
@@ -41,6 +42,10 @@ describe(' ', () => {
const getComponent = (props = {}) =>
mount( );
+ beforeAll(() => {
+ maplibregl.AttributionControl = jest.fn();
+ });
+
it('renders map correctly', () => {
const component = getComponent();
expect(component.find('Map')).toMatchSnapshot();
diff --git a/test/components/views/location/Map-test.tsx b/test/components/views/location/Map-test.tsx
index 12915c192ee..dc349793c6d 100644
--- a/test/components/views/location/Map-test.tsx
+++ b/test/components/views/location/Map-test.tsx
@@ -44,6 +44,10 @@ describe(' ', () => {
wrappingComponentProps: { value: matrixClient },
});
+ beforeAll(() => {
+ maplibregl.AttributionControl = jest.fn();
+ });
+
beforeEach(() => {
jest.clearAllMocks();
matrixClient.getClientWellKnown.mockReturnValue({
diff --git a/test/components/views/location/__snapshots__/LocationShareMenu-test.tsx.snap b/test/components/views/location/__snapshots__/LocationShareMenu-test.tsx.snap
index 758a026368c..76f50889c05 100644
--- a/test/components/views/location/__snapshots__/LocationShareMenu-test.tsx.snap
+++ b/test/components/views/location/__snapshots__/LocationShareMenu-test.tsx.snap
@@ -34,7 +34,7 @@ exports[` with live location disabled goes to labs flag scr
value={false}
>
with live location disabled goes to labs flag scr
aria-disabled={true}
className="mx_AccessibleButton mx_EnableLiveShare_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary mx_AccessibleButton_disabled"
data-test-id="enable-live-share-submit"
+ disabled={true}
role="button"
tabIndex={0}
>
diff --git a/test/components/views/location/__snapshots__/LocationViewDialog-test.tsx.snap b/test/components/views/location/__snapshots__/LocationViewDialog-test.tsx.snap
index a9f7a03f07d..6104f0dad0b 100644
--- a/test/components/views/location/__snapshots__/LocationViewDialog-test.tsx.snap
+++ b/test/components/views/location/__snapshots__/LocationViewDialog-test.tsx.snap
@@ -23,7 +23,20 @@ exports[`
renders map correctly 1`] = `
},
"_eventsCount": 1,
"_maxListeners": undefined,
- "addControl": [MockFunction],
+ "addControl": [MockFunction] {
+ "calls": Array [
+ Array [
+ mockConstructor {},
+ "top-right",
+ ],
+ ],
+ "results": Array [
+ Object {
+ "type": "return",
+ "value": undefined,
+ },
+ ],
+ },
"fitBounds": [MockFunction],
"removeControl": [MockFunction],
"setCenter": [MockFunction] {
@@ -78,7 +91,20 @@ exports[`
renders map correctly 1`] = `
},
"_eventsCount": 1,
"_maxListeners": undefined,
- "addControl": [MockFunction],
+ "addControl": [MockFunction] {
+ "calls": Array [
+ Array [
+ mockConstructor {},
+ "top-right",
+ ],
+ ],
+ "results": Array [
+ Object {
+ "type": "return",
+ "value": undefined,
+ },
+ ],
+ },
"fitBounds": [MockFunction],
"removeControl": [MockFunction],
"setCenter": [MockFunction] {
diff --git a/test/components/views/messages/MBeaconBody-test.tsx b/test/components/views/messages/MBeaconBody-test.tsx
index 5afbb05c78b..e9cb719f7f2 100644
--- a/test/components/views/messages/MBeaconBody-test.tsx
+++ b/test/components/views/messages/MBeaconBody-test.tsx
@@ -79,6 +79,11 @@ describe('
', () => {
});
const modalSpy = jest.spyOn(Modal, 'createTrackedDialog').mockReturnValue(undefined);
+
+ beforeAll(() => {
+ maplibregl.AttributionControl = jest.fn();
+ });
+
beforeEach(() => {
jest.clearAllMocks();
});
@@ -116,7 +121,7 @@ describe('
', () => {
makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient });
const component = getComponent({ mxEvent: beaconInfoEvent });
act(() => {
- component.find('.mx_MBeaconBody_map').simulate('click');
+ component.find('.mx_MBeaconBody_map').at(0).simulate('click');
});
expect(modalSpy).not.toHaveBeenCalled();
@@ -230,7 +235,7 @@ describe('
', () => {
const component = getComponent({ mxEvent: aliceBeaconInfo });
act(() => {
- component.find('.mx_MBeaconBody_map').simulate('click');
+ component.find('.mx_MBeaconBody_map').at(0).simulate('click');
});
expect(modalSpy).not.toHaveBeenCalled();
@@ -264,7 +269,7 @@ describe('
', () => {
const component = getComponent({ mxEvent: aliceBeaconInfo });
act(() => {
- component.find('.mx_MBeaconBody_map').simulate('click');
+ component.find('.mx_MBeaconBody_map').at(0).simulate('click');
});
expect(modalSpy).not.toHaveBeenCalled();
diff --git a/test/components/views/messages/MLocationBody-test.tsx b/test/components/views/messages/MLocationBody-test.tsx
index cc5a6105e50..ec2270f6358 100644
--- a/test/components/views/messages/MLocationBody-test.tsx
+++ b/test/components/views/messages/MLocationBody-test.tsx
@@ -56,6 +56,15 @@ describe("MLocationBody", () => {
wrappingComponent: MatrixClientContext.Provider,
wrappingComponentProps: { value: mockClient },
});
+
+ beforeAll(() => {
+ maplibregl.AttributionControl = jest.fn();
+ });
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
describe('with error', () => {
let sdkConfigSpy;
diff --git a/test/components/views/messages/__snapshots__/MLocationBody-test.tsx.snap b/test/components/views/messages/__snapshots__/MLocationBody-test.tsx.snap
index f4914b510d1..6123b3b7b46 100644
--- a/test/components/views/messages/__snapshots__/MLocationBody-test.tsx.snap
+++ b/test/components/views/messages/__snapshots__/MLocationBody-test.tsx.snap
@@ -58,7 +58,7 @@ exports[`MLocationBody
without error renders map correctly 1`] =
permalinkCreator={Object {}}
>
without error renders map correctly 1`] =
without error renders map correctly 1`] =
},
"_eventsCount": 1,
"_maxListeners": undefined,
- "addControl": [MockFunction],
+ "addControl": [MockFunction] {
+ "calls": Array [
+ Array [
+ mockConstructor {},
+ "top-right",
+ ],
+ ],
+ "results": Array [
+ Object {
+ "type": "return",
+ "value": undefined,
+ },
+ ],
+ },
"fitBounds": [MockFunction],
"removeControl": [MockFunction],
"setCenter": [MockFunction] {
@@ -135,22 +148,12 @@ exports[`MLocationBody without error renders map correctly 1`] =
"lon": -0.1276,
},
],
- Array [
- Object {
- "lat": 51.5076,
- "lon": -0.1276,
- },
- ],
],
"results": Array [
Object {
"type": "return",
"value": undefined,
},
- Object {
- "type": "return",
- "value": undefined,
- },
],
},
"setStyle": [MockFunction],
@@ -162,11 +165,11 @@ exports[`MLocationBody without error renders map correctly 1`] =
>
main notification switches email switches renders ema
value={false}
>
main notification switches renders only enable notifi
value={false}
>
renders container 1`] = `
class="mx_SettingsTab_toggleWithDescription"
>
{
+ describe("appendUntilRejected", () => {
+ const femaleFacepalmEmoji = "🤦♀️";
+
+ it("should not accept emoji strings into type=plain", () => {
+ const part = new PlainPart();
+ expect(part.appendUntilRejected(femaleFacepalmEmoji, "")).toEqual(femaleFacepalmEmoji);
+ expect(part.text).toEqual("");
+ });
+
+ it("should accept emoji strings into type=emoji", () => {
+ const part = new EmojiPart();
+ expect(part.appendUntilRejected(femaleFacepalmEmoji, "")).toBeUndefined();
+ expect(part.text).toEqual(femaleFacepalmEmoji);
+ });
+ });
+});
diff --git a/test/editor/roundtrip-test.ts b/test/editor/roundtrip-test.ts
new file mode 100644
index 00000000000..424f639233b
--- /dev/null
+++ b/test/editor/roundtrip-test.ts
@@ -0,0 +1,170 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { MatrixEvent } from 'matrix-js-sdk/src/matrix';
+
+import { parseEvent } from "../../src/editor/deserialize";
+import EditorModel from '../../src/editor/model';
+import DocumentOffset from '../../src/editor/offset';
+import { htmlSerializeIfNeeded, textSerialize } from '../../src/editor/serialize';
+import { createPartCreator } from "./mock";
+
+function htmlMessage(formattedBody: string, msgtype = "m.text") {
+ return {
+ getContent() {
+ return {
+ msgtype,
+ format: "org.matrix.custom.html",
+ formatted_body: formattedBody,
+ };
+ },
+ } as unknown as MatrixEvent;
+}
+
+async function md2html(markdown: string): Promise {
+ const pc = createPartCreator();
+ const oldModel = new EditorModel([], pc, () => {});
+ await oldModel.update(
+ markdown,
+ "insertText",
+ new DocumentOffset(markdown.length, false),
+ );
+ return htmlSerializeIfNeeded(oldModel, { forceHTML: true });
+}
+
+function html2md(html: string): string {
+ const pc = createPartCreator();
+ const parts = parseEvent(htmlMessage(html), pc);
+ const newModel = new EditorModel(parts, pc);
+ return textSerialize(newModel);
+}
+
+async function roundTripMarkdown(markdown: string): Promise {
+ return html2md(await md2html(markdown));
+}
+
+async function roundTripHtml(html: string): Promise {
+ return await md2html(html2md(html));
+}
+
+describe('editor/roundtrip', function() {
+ describe('markdown messages should round-trip if they contain', function() {
+ test.each([
+ ["newlines", "hello\nworld"],
+ ["pills", "text message for @room"],
+ ["pills with interesting characters in mxid", "text message for @alice\\\\\\_\\]#>&:hs.example.com"],
+ ["styling", "**bold** and _emphasised_"],
+ ["bold within a word", "abso**fragging**lutely"],
+ ["escaped html", "a\\b"],
+ ["escaped markdown", "\\*\\*foo\\*\\* \\_bar\\_ \\[a\\](b)"],
+ ["escaped backslashes", "C:\\\\Program Files"],
+ ["code in backticks", "foo ->`x`"],
+ ["code blocks containing backticks", "```\nfoo ->`x`\nbar\n```"],
+ ["code blocks containing markdown", "```\n__init__.py\n```"],
+ ["nested formatting", "ab **c _d_ e** fg"],
+ ["an ordered list", "A\n\n1. b\n2. c\n3. d\nE"],
+ ["an ordered list starting later", "A\n\n9. b\n10. c\n11. d\nE"],
+ ["an unordered list", "A\n\n- b\n- c\n- d\nE"],
+ ["code block followed by text after a blank line", "```A\nfoo(bar).baz();\n\n3\n```\n\nB"],
+ ["just a code block", "```\nfoo(bar).baz();\n\n3\n```"],
+ ["code block with language specifier", "```bash\nmake install\n\n```"],
+ ["inline code", "there's no place `127.0.0.1` like"],
+ ["nested quotations", "saying\n\n> > foo\n\n> NO\n\nis valid"],
+ ["quotations", "saying\n\n> NO\n\nis valid"],
+ ["links", "click [this](http://example.com/)!"],
+ ])('%s', async (_name, markdown) => {
+ expect(await roundTripMarkdown(markdown)).toEqual(markdown);
+ });
+
+ test.skip.each([
+ // Removes trailing spaces
+ ["a code block followed by newlines", "```\nfoo(bar).baz();\n\n3\n```\n\n"],
+ // Adds a space after the code block
+ ["a code block surrounded by text", "```A\nfoo(bar).baz();\n\n3\n```\nB"],
+ // Adds a space before the list
+ ["an unordered list directly preceded by text", "A\n- b\n- c\n- d\nE"],
+ // Re-numbers to 1, 2, 3
+ ["an ordered list where everything is 1", "A\n\n1. b\n1. c\n1. d\nE"],
+ // Adds a space before the list
+ ["an ordered list directly preceded by text", "A\n1. b\n2. c\n3. d\nE"],
+ // Adds and removes spaces before the nested list
+ ["nested unordered lists", "A\n- b\n- c\n - c1\n - c2\n- d\nE"],
+ // Adds and removes spaces before the nested list
+ ["nested ordered lists", "A\n\n1. b\n2. c\n 1. c1\n 2. c2\n3. d\nE"],
+ // Adds and removes spaces before the nested list
+ ["nested mixed lists", "A\n\n1. b\n2. c\n - c1\n - c2\n3. d\nE"],
+ // Backslashes get doubled
+ ["backslashes", "C:\\Program Files"],
+ // Deletes the whitespace
+ ['newlines with trailing and leading whitespace', "hello \n world"],
+ // Escapes the underscores
+ ["underscores within a word", "abso_fragging_lutely"],
+ // Includes the trailing text into the quotation
+ // https://github.com/vector-im/element-web/issues/22341
+ ["quotations without separating newlines", "saying\n> NO\nis valid"],
+ // Removes trailing and leading whitespace
+ ["quotations with trailing and leading whitespace", "saying \n\n> NO\n\n is valid"],
+ ])('%s', async (_name, markdown) => {
+ expect(await roundTripMarkdown(markdown)).toEqual(markdown);
+ });
+
+ it('styling, but * becomes _ and __ becomes **', async function() {
+ expect(await roundTripMarkdown("__bold__ and *emphasised*"))
+ .toEqual("**bold** and _emphasised_");
+ });
+ });
+
+ describe('HTML messages should round-trip if they contain', function() {
+ test.each([
+ ["backslashes", "C:\\Program Files"],
+ [
+ "nested blockquotes",
+ "\nfoo
\n\nbar
\n \n \n",
+ ],
+ ["ordered lists", "\nasd \nfgd \n \n"],
+ ["ordered lists starting later", '\nasd \nfgd \n \n'],
+ ["unordered lists", "\n"],
+ ["code blocks with surrounding text", "a
\na\ny;\n
\nb
\n"],
+ ["code blocks", "a\ny;\n
\n"],
+ ["code blocks containing markdown", "__init__.py\n
\n"],
+ ["code blocks with language specifier", "__init__.py\n
\n"],
+ ["paragraphs including formatting", "one
\nt w o
\n"],
+ ["paragraphs", "one
\ntwo
\n"],
+ ["links", "http://more.example.com/"],
+ ["escaped html", "This >em<isn't>em< important"],
+ ["markdown-like symbols", "You _would_ **type** [a](http://this.example.com) this."],
+ ["formatting within a word", "absofragging lutely"],
+ ["formatting", "This is import ant"],
+ ["line breaks", "one two"],
+ ])('%s', async (_name, html) => {
+ expect(await roundTripHtml(html)).toEqual(html);
+ });
+
+ test.skip.each([
+ // Strips out the pill - maybe needs some user lookup to work?
+ ["user pills", 'Alice '],
+ // Appends a slash to the URL
+ // https://github.com/vector-im/element-web/issues/22342
+ ["links without trailing slashes", 'Go here to see more'],
+ // Inserts newlines after tags
+ ["paragraphs without newlines", "one
two
"],
+ // Inserts a code block
+ ["nested lists", "\nasd \n\n\n \n \n"],
+ ])('%s', async (_name, html) => {
+ expect(await roundTripHtml(html)).toEqual(html);
+ });
+ });
+});
diff --git a/test/end-to-end-tests/src/scenario.ts b/test/end-to-end-tests/src/scenario.ts
index dc6e1309d78..b3de76f3d79 100644
--- a/test/end-to-end-tests/src/scenario.ts
+++ b/test/end-to-end-tests/src/scenario.ts
@@ -24,17 +24,14 @@ import { e2eEncryptionScenarios } from './scenarios/e2e-encryption';
import { ElementSession } from "./session";
import { RestSessionCreator } from "./rest/creator";
import { RestMultiSession } from "./rest/multi";
-import { spacesScenarios } from './scenarios/spaces';
import { RestSession } from "./rest/session";
import { stickerScenarios } from './scenarios/sticker';
import { userViewScenarios } from "./scenarios/user-view";
-import { ssoCustomisationScenarios } from "./scenarios/sso-customisations";
-import { updateScenarios } from "./scenarios/update";
export async function scenario(createSession: (s: string) => Promise,
restCreator: RestSessionCreator): Promise {
let firstUser = true;
- async function createUser(username) {
+ async function createUser(username: string) {
const session = await createSession(username);
if (firstUser) {
// only show browser version for first browser opened
@@ -56,8 +53,6 @@ export async function scenario(createSession: (s: string) => Promise Promise {
diff --git a/test/end-to-end-tests/src/scenarios/spaces.ts b/test/end-to-end-tests/src/scenarios/spaces.ts
deleted file mode 100644
index 909d58afe28..00000000000
--- a/test/end-to-end-tests/src/scenarios/spaces.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-Copyright 2021 The Matrix.org Foundation C.I.C.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import { createSpace, inviteSpace } from "../usecases/create-space";
-import { ElementSession } from "../session";
-
-export async function spacesScenarios(alice: ElementSession, bob: ElementSession): Promise {
- console.log(" creating a space for spaces scenarios:");
-
- await alice.delay(1000); // wait for dialogs to close
- await setupSpaceUsingAliceAndInviteBob(alice, bob);
-}
-
-const space = "Test Space";
-
-async function setupSpaceUsingAliceAndInviteBob(alice: ElementSession, bob: ElementSession): Promise {
- await createSpace(alice, space);
- await inviteSpace(alice, space, "@bob:localhost");
- await bob.query(`.mx_SpaceButton[aria-label="${space}"]`); // assert invite received
-}
diff --git a/test/end-to-end-tests/src/scenarios/sso-customisations.ts b/test/end-to-end-tests/src/scenarios/sso-customisations.ts
deleted file mode 100644
index 957f45a6823..00000000000
--- a/test/end-to-end-tests/src/scenarios/sso-customisations.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import { strict as assert } from "assert";
-
-import { ElementSession } from "../session";
-import { logout } from "../usecases/logout";
-import { applyConfigChange } from "../util";
-
-export async function ssoCustomisationScenarios(session: ElementSession): Promise {
- console.log(" injecting logout customisations for SSO scenarios:");
-
- await session.delay(1000); // wait for dialogs to close
- await applyConfigChange(session, {
- // we redirect to config.json because it's a predictable page that isn't Element
- // itself. We could use example.org, matrix.org, or something else, however this
- // puts dependency of external infrastructure on our tests. In the same vein, we
- // don't really want to figure out how to ship a `test-landing.html` page when
- // running with an uncontrolled Element (via `./run.sh --app-url http://localhost:8080`).
- // Using the config.json is just as fine, and we can search for strategic names.
- 'logout_redirect_url': '/config.json',
- });
-
- await logoutCanCauseRedirect(session);
-}
-
-async function logoutCanCauseRedirect(session: ElementSession): Promise {
- await logout(session, false); // we'll check the login page ourselves, so don't assert
-
- session.log.step("waits for redirect to config.json (as external page)");
- const foundLoginUrl = await session.poll(async () => {
- const url = session.page.url();
- return url === session.url('/config.json');
- });
- assert(foundLoginUrl);
- session.log.done();
-}
diff --git a/test/end-to-end-tests/src/scenarios/update.ts b/test/end-to-end-tests/src/scenarios/update.ts
deleted file mode 100644
index 30d21c5feba..00000000000
--- a/test/end-to-end-tests/src/scenarios/update.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import { HTTPRequest } from "puppeteer";
-import { strict as assert } from 'assert';
-
-import { ElementSession } from "../session";
-
-const NEW_VERSION = "some-new-version";
-
-async function mockVersionHTTPResponse(session: ElementSession) {
- // Mock the HTTP response to return a new version to trigger auto-update behaviour
- await session.page.setRequestInterception(true);
- session.page.on('request', (request: HTTPRequest) => {
- if (request.isInterceptResolutionHandled()) return;
- const url = new URL(request.url());
- if (url.pathname === "/version") {
- request.respond({
- contentType: "text/html",
- status: 200,
- body: NEW_VERSION,
- });
- } else {
- request.continue();
- }
- });
-}
-
-export async function updateScenarios(session: ElementSession) {
- // Mock the HTTP response to return a newer version, then wait for the page to reload in response
- await mockVersionHTTPResponse(session);
- await session.goto(session.url('/'));
- await session.waitForReload();
- const newUrl = new URL(session.page.url());
- assert.equal(newUrl.searchParams.get("updated"), NEW_VERSION);
-}
diff --git a/test/end-to-end-tests/src/session.ts b/test/end-to-end-tests/src/session.ts
index 86f612b0afa..c3f19db532d 100644
--- a/test/end-to-end-tests/src/session.ts
+++ b/test/end-to-end-tests/src/session.ts
@@ -23,10 +23,6 @@ import { delay, serializeLog } from './util';
const DEFAULT_TIMEOUT = 20000;
-interface XHRLogger {
- logs: () => string;
-}
-
export class ElementSession {
readonly consoleLog: LogBuffer;
readonly networkLog: LogBuffer;
@@ -80,10 +76,6 @@ export class ElementSession {
return this.getElementProperty(field, 'innerText');
}
- public getOuterHTML(field: puppeteer.ElementHandle): Promise {
- return this.getElementProperty(field, 'outerHTML');
- }
-
public isChecked(field: puppeteer.ElementHandle): Promise {
return this.getElementProperty(field, 'checked');
}
@@ -96,29 +88,6 @@ export class ElementSession {
return this.networkLog.buffer;
}
- public logXHRRequests(): XHRLogger {
- let buffer = "";
- this.page.on('requestfinished', async (req) => {
- const type = req.resourceType();
- const response = await req.response();
- //if (type === 'xhr' || type === 'fetch') {
- buffer += `${type} ${response.status()} ${req.method()} ${req.url()} \n`;
- // if (req.method() === "POST") {
- // buffer += " Post data: " + req.postData();
- // }
- //}
- });
- return {
- logs() {
- return buffer;
- },
- };
- }
-
- public async printElements(label: string, elements: puppeteer.ElementHandle[]): Promise {
- console.log(label, await Promise.all(elements.map(this.getOuterHTML)));
- }
-
public async replaceInputText(input: puppeteer.ElementHandle, text: string): Promise {
// click 3 times to select all text
await input.click({ clickCount: 3 });
@@ -149,45 +118,6 @@ export class ElementSession {
return await this.page.$$(selector);
}
- public waitForReload(): Promise {
- const timeout = DEFAULT_TIMEOUT;
- return new Promise((resolve, reject) => {
- const timeoutHandle = setTimeout(() => {
- this.page.off('domcontentloaded', callback);
- reject(new Error(`timeout of ${timeout}ms for waitForReload elapsed`));
- }, timeout);
-
- const callback = async () => {
- clearTimeout(timeoutHandle);
- resolve();
- };
-
- this.page.once('domcontentloaded', callback);
- });
- }
-
- public waitForNewPage(): Promise {
- const timeout = DEFAULT_TIMEOUT;
- return new Promise((resolve, reject) => {
- const timeoutHandle = setTimeout(() => {
- this.browser.off('targetcreated', callback);
- reject(new Error(`timeout of ${timeout}ms for waitForNewPage elapsed`));
- }, timeout);
-
- const callback = async (target) => {
- if (target.type() !== 'page') {
- return;
- }
- this.browser.off('targetcreated', callback);
- clearTimeout(timeoutHandle);
- const page = await target.page();
- resolve(page);
- };
-
- this.browser.on('targetcreated', callback);
- });
- }
-
/** wait for a /sync request started after this call that gets a 200 response */
public async waitForNextSuccessfulSync(): Promise {
const syncUrls = [];
diff --git a/test/end-to-end-tests/src/usecases/create-space.ts b/test/end-to-end-tests/src/usecases/create-space.ts
deleted file mode 100644
index 3fa2730f57d..00000000000
--- a/test/end-to-end-tests/src/usecases/create-space.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-Copyright 2021 The Matrix.org Foundation C.I.C.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import { ElementSession } from "../session";
-
-export async function openSpaceCreateMenu(session: ElementSession): Promise {
- const spaceCreateButton = await session.query('.mx_SpaceButton_new');
- await spaceCreateButton.click();
-}
-
-export async function createSpace(session: ElementSession, name: string, isPublic = false): Promise {
- session.log.step(`creates space "${name}"`);
-
- await openSpaceCreateMenu(session);
- const className = isPublic ? ".mx_SpaceCreateMenuType_public" : ".mx_SpaceCreateMenuType_private";
- const visibilityButton = await session.query(className);
- await visibilityButton.click();
-
- const nameInput = await session.query('input[name="spaceName"]');
- await session.replaceInputText(nameInput, name);
-
- await session.delay(100);
-
- const createButton = await session.query('.mx_SpaceCreateMenu_wrapper .mx_AccessibleButton_kind_primary');
- await createButton.click();
-
- if (!isPublic) {
- const justMeButton = await session.query('.mx_SpaceRoomView_privateScope_justMeButton');
- await justMeButton.click();
- const continueButton = await session.query('.mx_AddExistingToSpace_footer .mx_AccessibleButton_kind_primary');
- await continueButton.click();
- } else {
- for (let i = 0; i < 2; i++) {
- const continueButton = await session.query('.mx_SpaceRoomView_buttons .mx_AccessibleButton_kind_primary');
- await continueButton.click();
- }
- }
-
- session.log.done();
-}
-
-export async function inviteSpace(session: ElementSession, spaceName: string, userId: string): Promise {
- session.log.step(`invites "${userId}" to space "${spaceName}"`);
-
- const spaceButton = await session.query(`.mx_SpaceButton[aria-label="${spaceName}"]`);
- await spaceButton.click({
- button: 'right',
- });
-
- const inviteButton = await session.query('.mx_SpacePanel_contextMenu_inviteButton[aria-label="Invite"]');
- await inviteButton.click();
-
- try {
- // You only get this interstitial if it's a public space, so give up after 200ms
- // if it hasn't appeared
- const button = await session.query('.mx_SpacePublicShare_inviteButton', 200);
- await button.click();
- } catch (e) {
- // ignore
- }
-
- const inviteTextArea = await session.query(".mx_InviteDialog_editor input");
- await inviteTextArea.type(userId);
- const selectUserItem = await session.query(".mx_InviteDialog_roomTile");
- await selectUserItem.click();
- const confirmButton = await session.query(".mx_InviteDialog_goButton");
- await confirmButton.click();
- session.log.done();
-}
diff --git a/test/end-to-end-tests/src/usecases/logout.ts b/test/end-to-end-tests/src/usecases/logout.ts
deleted file mode 100644
index b422ff3d744..00000000000
--- a/test/end-to-end-tests/src/usecases/logout.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import { strict as assert } from 'assert';
-
-import { ElementSession } from "../session";
-
-export async function logout(session: ElementSession, assertLoginPage = true): Promise {
- session.log.startGroup("logs out");
-
- session.log.step("navigates to user menu");
- const userButton = await session.query('.mx_UserMenu > div.mx_AccessibleButton');
- await userButton.click();
- session.log.done();
-
- session.log.step("clicks the 'Sign Out' button");
- const signOutButton = await session.query('.mx_UserMenu_contextMenu .mx_UserMenu_iconSignOut');
- await signOutButton.click();
- session.log.done();
-
- if (assertLoginPage) {
- const foundLoginUrl = await session.poll(async () => {
- const url = session.page.url();
- return url === session.url('/#/login');
- });
- assert(foundLoginUrl);
- }
-
- session.log.endGroup();
-}
diff --git a/test/end-to-end-tests/src/util.ts b/test/end-to-end-tests/src/util.ts
index f45b23afcb0..298e708007e 100644
--- a/test/end-to-end-tests/src/util.ts
+++ b/test/end-to-end-tests/src/util.ts
@@ -28,7 +28,7 @@ export const range = function(start: number, amount: number, step = 1): Array {
+export const delay = function(ms: number): Promise {
return new Promise((resolve) => setTimeout(resolve, ms));
};
@@ -44,17 +44,6 @@ export const measureStop = function(session: ElementSession, name: string): Prom
}, name);
};
-// TODO: Proper types on `config` - for some reason won't accept an import of ConfigOptions.
-export async function applyConfigChange(session: ElementSession, config: any): Promise {
- await session.page.evaluate((_config) => {
- // note: we can't *set* the object because the window version is effectively a pointer.
- for (const [k, v] of Object.entries(_config)) {
- // @ts-ignore - for some reason it's not picking up on global.d.ts types.
- window.mxReactSdkConfig[k] = v;
- }
- }, config);
-}
-
export async function serializeLog(msg: ConsoleMessage): Promise {
// 9 characters padding is somewhat arbitrary ("warning".length + some)
let s = `${new Date().toISOString()} | ${ padEnd(msg.type(), 9, ' ')}| ${msg.text()} `; // trailing space is intentional
diff --git a/test/hooks/usePublicRoomDirectory-test.tsx b/test/hooks/usePublicRoomDirectory-test.tsx
new file mode 100644
index 00000000000..3cd76d11248
--- /dev/null
+++ b/test/hooks/usePublicRoomDirectory-test.tsx
@@ -0,0 +1,120 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { mount } from "enzyme";
+import { sleep } from "matrix-js-sdk/src/utils";
+import React from "react";
+import { act } from "react-dom/test-utils";
+
+import { usePublicRoomDirectory } from "../../src/hooks/usePublicRoomDirectory";
+import { MatrixClientPeg } from "../../src/MatrixClientPeg";
+import { stubClient } from "../test-utils/test-utils";
+
+function PublicRoomComponent({ onClick }) {
+ const roomDirectory = usePublicRoomDirectory();
+
+ const {
+ ready,
+ loading,
+ publicRooms,
+ } = roomDirectory;
+
+ return onClick(roomDirectory)}>
+ { (!ready || loading) && `ready: ${ready}, loading: ${loading}` }
+ { publicRooms[0] && (
+ `Name: ${publicRooms[0].name}`
+ ) }
+
;
+}
+
+describe("usePublicRoomDirectory", () => {
+ let cli;
+
+ beforeEach(() => {
+ stubClient();
+ cli = MatrixClientPeg.get();
+
+ MatrixClientPeg.getHomeserverName = () => "matrix.org";
+ cli.getThirdpartyProtocols = () => Promise.resolve({});
+ cli.publicRooms = (({ filter: { generic_search_term: query } }) => Promise.resolve({
+ chunk: [{
+ room_id: "hello world!",
+ name: query,
+ world_readable: true,
+ guest_can_join: true,
+ num_joined_members: 1,
+ }],
+ total_room_count_estimate: 1,
+ }));
+ });
+
+ it("should display public rooms when searching", async () => {
+ const query = "ROOM NAME";
+
+ const wrapper = mount( {
+ hook.search({
+ limit: 1,
+ query,
+ });
+ }} />);
+
+ expect(wrapper.text()).toBe("ready: false, loading: false");
+
+ await act(async () => {
+ await sleep(1);
+ wrapper.simulate("click");
+ return act(() => sleep(1));
+ });
+
+ expect(wrapper.text()).toContain(query);
+ });
+
+ it("should work with empty queries", async () => {
+ const wrapper = mount( {
+ hook.search({
+ limit: 1,
+ query: "",
+ });
+ }} />);
+
+ await act(async () => {
+ await sleep(1);
+ wrapper.simulate("click");
+ return act(() => sleep(1));
+ });
+
+ expect(wrapper.text()).toBe("");
+ });
+
+ it("should recover from a server exception", async () => {
+ cli.publicRooms = () => { throw new Error("Oops"); };
+ const query = "ROOM NAME";
+
+ const wrapper = mount( {
+ hook.search({
+ limit: 1,
+ query,
+ });
+ }} />);
+ await act(async () => {
+ await sleep(1);
+ wrapper.simulate("click");
+ return act(() => sleep(1));
+ });
+
+ expect(wrapper.text()).toBe("");
+ });
+});
diff --git a/test/hooks/useUserDirectory-test.tsx b/test/hooks/useUserDirectory-test.tsx
new file mode 100644
index 00000000000..bcd2861dfee
--- /dev/null
+++ b/test/hooks/useUserDirectory-test.tsx
@@ -0,0 +1,116 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { mount } from "enzyme";
+import { sleep } from "matrix-js-sdk/src/utils";
+import React from "react";
+import { act } from "react-dom/test-utils";
+
+import { useUserDirectory } from "../../src/hooks/useUserDirectory";
+import { MatrixClientPeg } from "../../src/MatrixClientPeg";
+import { stubClient } from "../test-utils";
+
+function UserDirectoryComponent({ onClick }) {
+ const userDirectory = useUserDirectory();
+
+ const {
+ ready,
+ loading,
+ users,
+ } = userDirectory;
+
+ return onClick(userDirectory)}>
+ { users[0]
+ ? (
+ `Name: ${users[0].name}`
+ )
+ : `ready: ${ready}, loading: ${loading}` }
+
;
+}
+
+describe("useUserDirectory", () => {
+ let cli;
+
+ beforeEach(() => {
+ stubClient();
+ cli = MatrixClientPeg.get();
+
+ MatrixClientPeg.getHomeserverName = () => "matrix.org";
+ cli.getThirdpartyProtocols = () => Promise.resolve({});
+ cli.searchUserDirectory = (({ term: query }) => Promise.resolve({
+ results: [{
+ user_id: "@bob:matrix.org",
+ display_name: query,
+ }] },
+ ));
+ });
+
+ it("search for users in the identity server", async () => {
+ const query = "Bob";
+
+ const wrapper = mount( {
+ hook.search({
+ limit: 1,
+ query,
+ });
+ }} />);
+
+ expect(wrapper.text()).toBe("ready: true, loading: false");
+
+ await act(async () => {
+ await sleep(1);
+ wrapper.simulate("click");
+ return act(() => sleep(1));
+ });
+
+ expect(wrapper.text()).toContain(query);
+ });
+
+ it("should work with empty queries", async () => {
+ const query = "";
+
+ const wrapper = mount( {
+ hook.search({
+ limit: 1,
+ query,
+ });
+ }} />);
+ await act(async () => {
+ await sleep(1);
+ wrapper.simulate("click");
+ return act(() => sleep(1));
+ });
+ expect(wrapper.text()).toBe("ready: true, loading: false");
+ });
+
+ it("should work with empty queries", async () => {
+ cli.searchUserDirectory = () => { throw new Error("Oops"); };
+ const query = "Bob";
+
+ const wrapper = mount( {
+ hook.search({
+ limit: 1,
+ query,
+ });
+ }} />);
+ await act(async () => {
+ await sleep(1);
+ wrapper.simulate("click");
+ return act(() => sleep(1));
+ });
+ expect(wrapper.text()).toBe("ready: true, loading: false");
+ });
+});
diff --git a/test/settings/watchers/FontWatcher-test.tsx b/test/settings/watchers/FontWatcher-test.tsx
new file mode 100644
index 00000000000..25aba6c2dd8
--- /dev/null
+++ b/test/settings/watchers/FontWatcher-test.tsx
@@ -0,0 +1,83 @@
+/*
+Copyright 2022 r00ster91
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { sleep } from 'matrix-js-sdk/src/utils';
+
+import SettingsStore from '../../../src/settings/SettingsStore';
+import { SettingLevel } from '../../../src/settings/SettingLevel';
+import { FontWatcher } from "../../../src/settings/watchers/FontWatcher";
+import { Action } from "../../../src/dispatcher/actions";
+import { untilDispatch } from "../../test-utils";
+import defaultDispatcher from "../../../src/dispatcher/dispatcher";
+
+async function setSystemFont(font: string): Promise {
+ await SettingsStore.setValue("useSystemFont", null, SettingLevel.DEVICE, !!font);
+ await SettingsStore.setValue("systemFont", null, SettingLevel.DEVICE, font);
+ await untilDispatch(Action.UpdateSystemFont);
+ await sleep(1); // await the FontWatcher doing its action
+}
+
+describe('FontWatcher', function() {
+ it("should load font on start()", async () => {
+ const watcher = new FontWatcher();
+ await setSystemFont("Font Name");
+ expect(document.body.style.fontFamily).toBe("");
+ watcher.start();
+ expect(document.body.style.fontFamily).toBe('"Font Name"');
+ });
+
+ it("should load font on Action.OnLoggedIn", async () => {
+ await setSystemFont("Font Name");
+ new FontWatcher().start();
+ document.body.style.fontFamily = ""; // clear the fontFamily which was set by start which we tested already
+ defaultDispatcher.fire(Action.OnLoggedIn, true);
+ expect(document.body.style.fontFamily).toBe('"Font Name"');
+ });
+
+ it("should reset font on Action.OnLoggedOut", async () => {
+ await setSystemFont("Font Name");
+ const watcher = new FontWatcher();
+ watcher.start();
+ expect(document.body.style.fontFamily).toBe('"Font Name"');
+ defaultDispatcher.fire(Action.OnLoggedOut, true);
+ expect(document.body.style.fontFamily).toBe("");
+ });
+
+ describe("Sets font as expected", () => {
+ let fontWatcher: FontWatcher;
+ beforeEach(() => {
+ fontWatcher = new FontWatcher();
+ fontWatcher.start();
+ });
+ afterEach(() => {
+ fontWatcher.stop();
+ });
+
+ it('encloses the fonts by double quotes and sets them as the system font', async () => {
+ await setSystemFont("Fira Sans Thin, Commodore 64");
+ expect(document.body.style.fontFamily).toBe(`"Fira Sans Thin","Commodore 64"`);
+ });
+ it('does not add double quotes if already present and sets the font as the system font', async () => {
+ await setSystemFont(`"Commodore 64"`);
+ expect(document.body.style.fontFamily).toBe(`"Commodore 64"`);
+ });
+ it('trims whitespace, encloses the fonts by double quotes, and sets them as the system font', async () => {
+ await setSystemFont(` Fira Code , "Commodore 64" `);
+ expect(document.body.style.fontFamily).toBe(`"Fira Code","Commodore 64"`);
+ });
+ });
+});
diff --git a/test/stores/SpaceStore-test.ts b/test/stores/SpaceStore-test.ts
index 47c3f974b23..d83bc21f224 100644
--- a/test/stores/SpaceStore-test.ts
+++ b/test/stores/SpaceStore-test.ts
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+import { EventEmitter } from "events";
import { mocked } from 'jest-mock';
import { EventType } from "matrix-js-sdk/src/@types/event";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
@@ -1221,4 +1222,26 @@ describe("SpaceStore", () => {
expect(SpaceStore.instance.spacePanelSpaces.map(r => r.roomId)).toStrictEqual([rootSpace.roomId]);
await prom;
});
+
+ it("correctly emits events for metaspace changes during onReady", async () => {
+ // similar to useEventEmitterState, but for use inside of tests
+ function testEventEmitterState(
+ emitter: EventEmitter | undefined,
+ eventName: string | symbol,
+ callback: (...args: any[]) => void,
+ ): () => void {
+ callback();
+ emitter.addListener(eventName, callback);
+ return () => emitter.removeListener(eventName, callback);
+ }
+
+ let metaSpaces;
+ const removeListener = testEventEmitterState(store, UPDATE_TOP_LEVEL_SPACES, () => {
+ metaSpaces = store.enabledMetaSpaces;
+ });
+ expect(metaSpaces).toEqual(store.enabledMetaSpaces);
+ await run();
+ expect(metaSpaces).toEqual(store.enabledMetaSpaces);
+ removeListener();
+ });
});
diff --git a/test/stores/VideoChannelStore-test.ts b/test/stores/VideoChannelStore-test.ts
index 09508d477a4..cf5def33347 100644
--- a/test/stores/VideoChannelStore-test.ts
+++ b/test/stores/VideoChannelStore-test.ts
@@ -114,23 +114,26 @@ describe("VideoChannelStore", () => {
expect(store.roomId).toBeFalsy();
expect(store.connected).toEqual(false);
- store.connect("!1:example.org", null, null);
+ const connectPromise = store.connect("!1:example.org", null, null);
await confirmConnect();
+ await expect(connectPromise).resolves.toBeUndefined();
expect(store.roomId).toEqual("!1:example.org");
expect(store.connected).toEqual(true);
- store.disconnect();
+ const disconnectPromise = store.disconnect();
await confirmDisconnect();
+ await expect(disconnectPromise).resolves.toBeUndefined();
expect(store.roomId).toBeFalsy();
expect(store.connected).toEqual(false);
WidgetMessagingStore.instance.stopMessaging(widget, "!1:example.org");
});
it("waits for messaging when connecting", async () => {
- store.connect("!1:example.org", null, null);
+ const connectPromise = store.connect("!1:example.org", null, null);
WidgetMessagingStore.instance.storeMessaging(widget, "!1:example.org", messaging);
widgetReady();
await confirmConnect();
+ await expect(connectPromise).resolves.toBeUndefined();
expect(store.roomId).toEqual("!1:example.org");
expect(store.connected).toEqual(true);
@@ -138,4 +141,19 @@ describe("VideoChannelStore", () => {
await confirmDisconnect();
WidgetMessagingStore.instance.stopMessaging(widget, "!1:example.org");
});
+
+ it("rejects if the widget's messaging gets stopped mid-connect", async () => {
+ WidgetMessagingStore.instance.storeMessaging(widget, "!1:example.org", messaging);
+ widgetReady();
+ expect(store.roomId).toBeFalsy();
+ expect(store.connected).toEqual(false);
+
+ const connectPromise = store.connect("!1:example.org", null, null);
+ // Wait for the store to contact the widget API, then stop the messaging
+ await messageSent;
+ WidgetMessagingStore.instance.stopMessaging(widget, "!1:example.org");
+ await expect(connectPromise).rejects.toBeDefined();
+ expect(store.roomId).toBeFalsy();
+ expect(store.connected).toEqual(false);
+ });
});
diff --git a/test/test-utils/utilities.ts b/test/test-utils/utilities.ts
index a4370fbc9e1..d7da56407b9 100644
--- a/test/test-utils/utilities.ts
+++ b/test/test-utils/utilities.ts
@@ -17,8 +17,24 @@ limitations under the License.
import { ReactWrapper } from "enzyme";
import EventEmitter from "events";
+import { ActionPayload } from "../../src/dispatcher/payloads";
+import defaultDispatcher from "../../src/dispatcher/dispatcher";
+import { DispatcherAction } from "../../src/dispatcher/actions";
+
export const emitPromise = (e: EventEmitter, k: string | symbol) => new Promise(r => e.once(k, r));
+export function untilDispatch(waitForAction: DispatcherAction): Promise {
+ let dispatchHandle: string;
+ return new Promise(resolve => {
+ dispatchHandle = defaultDispatcher.register(payload => {
+ if (payload.action === waitForAction) {
+ defaultDispatcher.unregister(dispatchHandle);
+ resolve(payload);
+ }
+ });
+ });
+}
+
const findByAttr = (attr: string) => (component: ReactWrapper, value: string) => component.find(`[${attr}="${value}"]`);
export const findByTestId = findByAttr('data-test-id');
export const findById = findByAttr('id');
diff --git a/test/utils/location/map-test.ts b/test/utils/location/map-test.ts
index f389f12cfdb..d090926f07d 100644
--- a/test/utils/location/map-test.ts
+++ b/test/utils/location/map-test.ts
@@ -14,20 +14,20 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import { createMapSiteLink } from "../../../src/utils/location";
+import { createMapSiteLinkFromEvent } from "../../../src/utils/location";
import { mkMessage } from "../../test-utils";
import { makeLegacyLocationEvent, makeLocationEvent } from "../../test-utils/location";
-describe("createMapSiteLink", () => {
+describe("createMapSiteLinkFromEvent", () => {
it("returns null if event does not contain geouri", () => {
- expect(createMapSiteLink(mkMessage({
+ expect(createMapSiteLinkFromEvent(mkMessage({
room: '1', user: '@sender:server', event: true,
}))).toBeNull();
});
it("returns OpenStreetMap link if event contains m.location", () => {
expect(
- createMapSiteLink(makeLocationEvent("geo:51.5076,-0.1276")),
+ createMapSiteLinkFromEvent(makeLocationEvent("geo:51.5076,-0.1276")),
).toEqual(
"https://www.openstreetmap.org/" +
"?mlat=51.5076&mlon=-0.1276" +
@@ -37,7 +37,7 @@ describe("createMapSiteLink", () => {
it("returns OpenStreetMap link if event contains geo_uri", () => {
expect(
- createMapSiteLink(makeLegacyLocationEvent("geo:51.5076,-0.1276")),
+ createMapSiteLinkFromEvent(makeLegacyLocationEvent("geo:51.5076,-0.1276")),
).toEqual(
"https://www.openstreetmap.org/" +
"?mlat=51.5076&mlon=-0.1276" +
diff --git a/yarn.lock b/yarn.lock
index 5a896108f07..aef96e9170b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3,28 +3,28 @@
"@actions/core@^1.4.0":
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.7.0.tgz#f179a5a0bf5c1102d89b8cf1712825e763feaee4"
- integrity sha512-7fPSS7yKOhTpgLMbw7lBLc1QJWvJBBAgyTX2PEhagWcKK8t0H8AKCoPMfnrHqIm5cRYH4QFPqD1/ruhuUE7YcQ==
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.8.2.tgz#67539d669ae9b751430469e9ae4d83e0525973ac"
+ integrity sha512-FXcBL7nyik8K5ODeCKlxi+vts7torOkoDAKfeh61EAkAy1HAvwn9uVzZBY0f15YcQTcZZ2/iSGBFHEuioZWfDA==
dependencies:
- "@actions/http-client" "^1.0.11"
+ "@actions/http-client" "^2.0.1"
"@actions/github@^5.0.0":
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/@actions/github/-/github-5.0.1.tgz#5fdbe371d9a592038668be95d12421361585fba1"
- integrity sha512-JZGyPM9ektb8NVTTI/2gfJ9DL7Rk98tQ7OVyTlgTuaQroariRBsOnzjy0I2EarX4xUZpK88YyO503fhmjFdyAg==
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/@actions/github/-/github-5.0.3.tgz#b305765d6173962d113451ea324ff675aa674f35"
+ integrity sha512-myjA/pdLQfhUGLtRZC/J4L1RXOG4o6aYdiEq+zr5wVVKljzbFld+xv10k1FX6IkIJtNxbAq44BdwSNpQ015P0A==
dependencies:
- "@actions/http-client" "^1.0.11"
+ "@actions/http-client" "^2.0.1"
"@octokit/core" "^3.6.0"
"@octokit/plugin-paginate-rest" "^2.17.0"
"@octokit/plugin-rest-endpoint-methods" "^5.13.0"
-"@actions/http-client@^1.0.11":
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-1.0.11.tgz#c58b12e9aa8b159ee39e7dd6cbd0e91d905633c0"
- integrity sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==
+"@actions/http-client@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-2.0.1.tgz#873f4ca98fe32f6839462a6f046332677322f99c"
+ integrity sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==
dependencies:
- tunnel "0.0.6"
+ tunnel "^0.0.6"
"@ampproject/remapping@^2.1.0":
version "2.2.0"
@@ -57,26 +57,26 @@
dependencies:
"@babel/highlight" "^7.16.7"
-"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.10":
+"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.17.10":
version "7.17.10"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab"
integrity sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==
"@babel/core@^7.1.0", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.17.9", "@babel/core@^7.7.2", "@babel/core@^7.8.0":
- version "7.17.10"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.10.tgz#74ef0fbf56b7dfc3f198fc2d927f4f03e12f4b05"
- integrity sha512-liKoppandF3ZcBnIYFjfSDHZLKdLHGJRkoWtG8zQyGJBQfIYobpnVGI5+pLBNtS6psFLDzyq8+h5HiVljW9PNA==
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.12.tgz#b4eb2d7ebc3449b062381644c93050db545b70ee"
+ integrity sha512-44ODe6O1IVz9s2oJE3rZ4trNNKTX9O7KpQpfAP4t8QII/zwrVRHL7i2pxhqtcY7tqMLrrKfMlBKnm1QlrRFs5w==
dependencies:
"@ampproject/remapping" "^2.1.0"
"@babel/code-frame" "^7.16.7"
- "@babel/generator" "^7.17.10"
+ "@babel/generator" "^7.17.12"
"@babel/helper-compilation-targets" "^7.17.10"
- "@babel/helper-module-transforms" "^7.17.7"
+ "@babel/helper-module-transforms" "^7.17.12"
"@babel/helpers" "^7.17.9"
- "@babel/parser" "^7.17.10"
+ "@babel/parser" "^7.17.12"
"@babel/template" "^7.16.7"
- "@babel/traverse" "^7.17.10"
- "@babel/types" "^7.17.10"
+ "@babel/traverse" "^7.17.12"
+ "@babel/types" "^7.17.12"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
@@ -99,13 +99,13 @@
dependencies:
eslint-rule-composer "^0.3.0"
-"@babel/generator@^7.17.10", "@babel/generator@^7.7.2":
- version "7.17.10"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.10.tgz#c281fa35b0c349bbe9d02916f4ae08fc85ed7189"
- integrity sha512-46MJZZo9y3o4kmhBVc7zW7i8dtR1oIK/sdO5NcfcZRhTGYi+KKJRtHNgsU6c4VUcJmUNV/LQdebD/9Dlv4K+Tg==
+"@babel/generator@^7.17.12", "@babel/generator@^7.7.2":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.12.tgz#5970e6160e9be0428e02f4aba62d8551ec366cc8"
+ integrity sha512-V49KtZiiiLjH/CnIW6OjJdrenrGoyh6AmKQ3k2AZFKozC1h846Q4NYlZ5nqAigPDUXfGzC88+LOUuG8yKd2kCw==
dependencies:
- "@babel/types" "^7.17.10"
- "@jridgewell/gen-mapping" "^0.1.0"
+ "@babel/types" "^7.17.12"
+ "@jridgewell/gen-mapping" "^0.3.0"
jsesc "^2.5.1"
"@babel/helper-annotate-as-pure@^7.16.7":
@@ -133,10 +133,10 @@
browserslist "^4.20.2"
semver "^6.3.0"
-"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.6":
- version "7.17.9"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.9.tgz#71835d7fb9f38bd9f1378e40a4c0902fdc2ea49d"
- integrity sha512-kUjip3gruz6AJKOq5i3nC6CoCEEF/oHH3cp6tOZhB+IyyyPyW0g1Gfsxn3mkk6S08pIA2y8GQh609v9G/5sHVQ==
+"@babel/helper-create-class-features-plugin@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.12.tgz#d4f8393fc4838cbff6b7c199af5229aee16d07cf"
+ integrity sha512-sZoOeUTkFJMyhqCei2+Z+wtH/BehW8NVKQt7IRUQlRiOARuXymJYfN/FCcI8CvVbR0XVyDM6eLFOlR7YtiXnew==
dependencies:
"@babel/helper-annotate-as-pure" "^7.16.7"
"@babel/helper-environment-visitor" "^7.16.7"
@@ -146,10 +146,10 @@
"@babel/helper-replace-supers" "^7.16.7"
"@babel/helper-split-export-declaration" "^7.16.7"
-"@babel/helper-create-regexp-features-plugin@^7.16.7", "@babel/helper-create-regexp-features-plugin@^7.17.0":
- version "7.17.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz#1dcc7d40ba0c6b6b25618997c5dbfd310f186fe1"
- integrity sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==
+"@babel/helper-create-regexp-features-plugin@^7.16.7", "@babel/helper-create-regexp-features-plugin@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz#bb37ca467f9694bbe55b884ae7a5cc1e0084e4fd"
+ integrity sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw==
dependencies:
"@babel/helper-annotate-as-pure" "^7.16.7"
regexpu-core "^5.0.1"
@@ -211,10 +211,10 @@
dependencies:
"@babel/types" "^7.16.7"
-"@babel/helper-module-transforms@^7.16.7", "@babel/helper-module-transforms@^7.17.7":
- version "7.17.7"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd"
- integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==
+"@babel/helper-module-transforms@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.12.tgz#bec00139520cb3feb078ef7a4578562480efb77e"
+ integrity sha512-t5s2BeSWIghhFRPh9XMn6EIGmvn8Lmw5RVASJzkIx1mSemubQQBNIZiQD7WzaFmaHIrjAec4x8z9Yx8SjJ1/LA==
dependencies:
"@babel/helper-environment-visitor" "^7.16.7"
"@babel/helper-module-imports" "^7.16.7"
@@ -222,8 +222,8 @@
"@babel/helper-split-export-declaration" "^7.16.7"
"@babel/helper-validator-identifier" "^7.16.7"
"@babel/template" "^7.16.7"
- "@babel/traverse" "^7.17.3"
- "@babel/types" "^7.17.0"
+ "@babel/traverse" "^7.17.12"
+ "@babel/types" "^7.17.12"
"@babel/helper-optimise-call-expression@^7.16.7":
version "7.16.7"
@@ -232,10 +232,10 @@
dependencies:
"@babel/types" "^7.16.7"
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5"
- integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.17.12", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96"
+ integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==
"@babel/helper-remap-async-to-generator@^7.16.8":
version "7.16.8"
@@ -308,59 +308,59 @@
"@babel/types" "^7.17.0"
"@babel/highlight@^7.16.7":
- version "7.17.9"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.9.tgz#61b2ee7f32ea0454612def4fccdae0de232b73e3"
- integrity sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351"
+ integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==
dependencies:
"@babel/helper-validator-identifier" "^7.16.7"
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@babel/parser@^7.1.0", "@babel/parser@^7.12.11", "@babel/parser@^7.13.16", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.10":
- version "7.17.10"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.10.tgz#873b16db82a8909e0fbd7f115772f4b739f6ce78"
- integrity sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==
+"@babel/parser@^7.1.0", "@babel/parser@^7.12.11", "@babel/parser@^7.13.16", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.12.tgz#36c2ed06944e3691ba82735fc4cf62d12d491a23"
+ integrity sha512-FLzHmN9V3AJIrWfOpvRlZCeVg/WLdicSnTMsLur6uDj9TT8ymUlG9XxURdW/XvuygK+2CW0poOJABdA4m/YKxA==
-"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050"
- integrity sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==
+"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.17.12.tgz#1dca338caaefca368639c9ffb095afbd4d420b1e"
+ integrity sha512-xCJQXl4EeQ3J9C4yOmpTrtVGmzpm2iSzyxbkZHw7UCnZBftHpF/hpII80uWVyVrc40ytIClHjgWGTG1g/yB+aw==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
-"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz#cc001234dfc139ac45f6bcf801866198c8c72ff9"
- integrity sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==
+"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.17.12.tgz#0d498ec8f0374b1e2eb54b9cb2c4c78714c77753"
+ integrity sha512-/vt0hpIw0x4b6BLKUkwlvEoiGZYYLNZ96CzyHYPbtG2jZGz6LBe7/V+drYrc/d+ovrF9NBi0pmtvmNb/FsWtRQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/helper-skip-transparent-expression-wrappers" "^7.16.0"
- "@babel/plugin-proposal-optional-chaining" "^7.16.7"
+ "@babel/plugin-proposal-optional-chaining" "^7.17.12"
-"@babel/plugin-proposal-async-generator-functions@^7.16.8":
- version "7.16.8"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz#3bdd1ebbe620804ea9416706cd67d60787504bc8"
- integrity sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==
+"@babel/plugin-proposal-async-generator-functions@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz#094a417e31ce7e692d84bab06c8e2a607cbeef03"
+ integrity sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/helper-remap-async-to-generator" "^7.16.8"
"@babel/plugin-syntax-async-generators" "^7.8.4"
-"@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0"
- integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==
+"@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz#84f65c0cc247d46f40a6da99aadd6438315d80a4"
+ integrity sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw==
dependencies:
- "@babel/helper-create-class-features-plugin" "^7.16.7"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-create-class-features-plugin" "^7.17.12"
+ "@babel/helper-plugin-utils" "^7.17.12"
-"@babel/plugin-proposal-class-static-block@^7.17.6":
- version "7.17.6"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz#164e8fd25f0d80fa48c5a4d1438a6629325ad83c"
- integrity sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==
+"@babel/plugin-proposal-class-static-block@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.12.tgz#947f09dd496322c9543ec3b318bf52b4d9833334"
+ integrity sha512-8ILyDG6eL14F8iub97dVc8q35Md0PJYAnA5Kz9NACFOkt6ffCcr0FISyUPKHsvuAy36fkpIitxZ9bVYPFMGQHA==
dependencies:
- "@babel/helper-create-class-features-plugin" "^7.17.6"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-create-class-features-plugin" "^7.17.12"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-syntax-class-static-block" "^7.14.5"
"@babel/plugin-proposal-dynamic-import@^7.16.7":
@@ -372,43 +372,43 @@
"@babel/plugin-syntax-dynamic-import" "^7.8.3"
"@babel/plugin-proposal-export-default-from@^7.12.1":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.16.7.tgz#a40ab158ca55627b71c5513f03d3469026a9e929"
- integrity sha512-+cENpW1rgIjExn+o5c8Jw/4BuH4eGKKYvkMB8/0ZxFQ9mC0t4z09VsPIwNg6waF69QYC81zxGeAsREGuqQoKeg==
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.17.12.tgz#df785e638618d8ffa14e08c78c44d9695d083b73"
+ integrity sha512-LpsTRw725eBAXXKUOnJJct+SEaOzwR78zahcLuripD2+dKc2Sj+8Q2DzA+GC/jOpOu/KlDXuxrzG214o1zTauQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-syntax-export-default-from" "^7.16.7"
-"@babel/plugin-proposal-export-namespace-from@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz#09de09df18445a5786a305681423ae63507a6163"
- integrity sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==
+"@babel/plugin-proposal-export-namespace-from@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz#b22864ccd662db9606edb2287ea5fd1709f05378"
+ integrity sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-syntax-export-namespace-from" "^7.8.3"
-"@babel/plugin-proposal-json-strings@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz#9732cb1d17d9a2626a08c5be25186c195b6fa6e8"
- integrity sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==
+"@babel/plugin-proposal-json-strings@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.17.12.tgz#f4642951792437233216d8c1af370bb0fbff4664"
+ integrity sha512-rKJ+rKBoXwLnIn7n6o6fulViHMrOThz99ybH+hKHcOZbnN14VuMnH9fo2eHE69C8pO4uX1Q7t2HYYIDmv8VYkg==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-syntax-json-strings" "^7.8.3"
-"@babel/plugin-proposal-logical-assignment-operators@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz#be23c0ba74deec1922e639832904be0bea73cdea"
- integrity sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==
+"@babel/plugin-proposal-logical-assignment-operators@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.17.12.tgz#c64a1bcb2b0a6d0ed2ff674fd120f90ee4b88a23"
+ integrity sha512-EqFo2s1Z5yy+JeJu7SFfbIUtToJTVlC61/C7WLKDntSw4Sz6JNAIfL7zQ74VvirxpjB5kz/kIx0gCcb+5OEo2Q==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
-"@babel/plugin-proposal-nullish-coalescing-operator@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz#141fc20b6857e59459d430c850a0011e36561d99"
- integrity sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==
+"@babel/plugin-proposal-nullish-coalescing-operator@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz#1e93079bbc2cbc756f6db6a1925157c4a92b94be"
+ integrity sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
"@babel/plugin-proposal-numeric-separator@^7.12.7", "@babel/plugin-proposal-numeric-separator@^7.16.7":
@@ -419,16 +419,16 @@
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-syntax-numeric-separator" "^7.10.4"
-"@babel/plugin-proposal-object-rest-spread@^7.12.1", "@babel/plugin-proposal-object-rest-spread@^7.17.3":
- version "7.17.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz#d9eb649a54628a51701aef7e0ea3d17e2b9dd390"
- integrity sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==
+"@babel/plugin-proposal-object-rest-spread@^7.12.1", "@babel/plugin-proposal-object-rest-spread@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.12.tgz#f94a91715a7f2f8cfb3c06af820c776440bc0148"
+ integrity sha512-6l9cO3YXXRh4yPCPRA776ZyJ3RobG4ZKJZhp7NDRbKIOeV3dBPG8FXCF7ZtiO2RTCIOkQOph1xDDcc01iWVNjQ==
dependencies:
- "@babel/compat-data" "^7.17.0"
- "@babel/helper-compilation-targets" "^7.16.7"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/compat-data" "^7.17.10"
+ "@babel/helper-compilation-targets" "^7.17.10"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-syntax-object-rest-spread" "^7.8.3"
- "@babel/plugin-transform-parameters" "^7.16.7"
+ "@babel/plugin-transform-parameters" "^7.17.12"
"@babel/plugin-proposal-optional-catch-binding@^7.16.7":
version "7.16.7"
@@ -438,40 +438,40 @@
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
-"@babel/plugin-proposal-optional-chaining@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz#7cd629564724816c0e8a969535551f943c64c39a"
- integrity sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==
+"@babel/plugin-proposal-optional-chaining@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz#f96949e9bacace3a9066323a5cf90cfb9de67174"
+ integrity sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/helper-skip-transparent-expression-wrappers" "^7.16.0"
"@babel/plugin-syntax-optional-chaining" "^7.8.3"
-"@babel/plugin-proposal-private-methods@^7.16.11":
- version "7.16.11"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz#e8df108288555ff259f4527dbe84813aac3a1c50"
- integrity sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==
+"@babel/plugin-proposal-private-methods@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.17.12.tgz#c2ca3a80beb7539289938da005ad525a038a819c"
+ integrity sha512-SllXoxo19HmxhDWm3luPz+cPhtoTSKLJE9PXshsfrOzBqs60QP0r8OaJItrPhAj0d7mZMnNF0Y1UUggCDgMz1A==
dependencies:
- "@babel/helper-create-class-features-plugin" "^7.16.10"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-create-class-features-plugin" "^7.17.12"
+ "@babel/helper-plugin-utils" "^7.17.12"
-"@babel/plugin-proposal-private-property-in-object@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz#b0b8cef543c2c3d57e59e2c611994861d46a3fce"
- integrity sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==
+"@babel/plugin-proposal-private-property-in-object@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.17.12.tgz#b02efb7f106d544667d91ae97405a9fd8c93952d"
+ integrity sha512-/6BtVi57CJfrtDNKfK5b66ydK2J5pXUKBKSPD2G1whamMuEnZWgoOIfO8Vf9F/DoD4izBLD/Au4NMQfruzzykg==
dependencies:
"@babel/helper-annotate-as-pure" "^7.16.7"
- "@babel/helper-create-class-features-plugin" "^7.16.7"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-create-class-features-plugin" "^7.17.12"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-syntax-private-property-in-object" "^7.14.5"
-"@babel/plugin-proposal-unicode-property-regex@^7.16.7", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz#635d18eb10c6214210ffc5ff4932552de08188a2"
- integrity sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==
+"@babel/plugin-proposal-unicode-property-regex@^7.17.12", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.17.12.tgz#3dbd7a67bd7f94c8238b394da112d86aaf32ad4d"
+ integrity sha512-Wb9qLjXf3ZazqXA7IvI7ozqRIXIGPtSo+L5coFmEkhTQK18ao4UDDD0zdTGAarmbLj2urpRwrc6893cu5Bfh0A==
dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.16.7"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-create-regexp-features-plugin" "^7.17.12"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
@@ -536,12 +536,12 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-syntax-jsx@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665"
- integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==
+"@babel/plugin-syntax-jsx@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.17.12.tgz#834035b45061983a491f60096f61a2e7c5674a47"
+ integrity sha512-spyY3E3AURfxh/RHtjx5j6hs8am5NbUBGfcZ2vB3uShSpZdQyXSf5rR5Mk76vbtlAZOelyVQ71Fg0x9SG4fsog==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3":
version "7.10.4"
@@ -599,27 +599,27 @@
dependencies:
"@babel/helper-plugin-utils" "^7.14.5"
-"@babel/plugin-syntax-typescript@^7.16.7", "@babel/plugin-syntax-typescript@^7.7.2":
- version "7.17.10"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.10.tgz#80031e6042cad6a95ed753f672ebd23c30933195"
- integrity sha512-xJefea1DWXW09pW4Tm9bjwVlPDyYA2it3fWlmEjpYz6alPvTUjL0EOzNzI/FEOyI3r4/J7uVH5UqKgl1TQ5hqQ==
+"@babel/plugin-syntax-typescript@^7.17.12", "@babel/plugin-syntax-typescript@^7.7.2":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz#b54fc3be6de734a56b87508f99d6428b5b605a7b"
+ integrity sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
-"@babel/plugin-transform-arrow-functions@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz#44125e653d94b98db76369de9c396dc14bef4154"
- integrity sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==
+"@babel/plugin-transform-arrow-functions@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz#dddd783b473b1b1537ef46423e3944ff24898c45"
+ integrity sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
-"@babel/plugin-transform-async-to-generator@^7.16.8":
- version "7.16.8"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz#b83dff4b970cf41f1b819f8b49cc0cfbaa53a808"
- integrity sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==
+"@babel/plugin-transform-async-to-generator@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.17.12.tgz#dbe5511e6b01eee1496c944e35cdfe3f58050832"
+ integrity sha512-J8dbrWIOO3orDzir57NRsjg4uxucvhby0L/KZuGsWDj0g7twWK3g7JhJhOrXtuXiw8MeiSdJ3E0OW9H8LYEzLQ==
dependencies:
"@babel/helper-module-imports" "^7.16.7"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/helper-remap-async-to-generator" "^7.16.8"
"@babel/plugin-transform-block-scoped-functions@^7.16.7":
@@ -629,40 +629,40 @@
dependencies:
"@babel/helper-plugin-utils" "^7.16.7"
-"@babel/plugin-transform-block-scoping@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz#f50664ab99ddeaee5bc681b8f3a6ea9d72ab4f87"
- integrity sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==
+"@babel/plugin-transform-block-scoping@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.17.12.tgz#68fc3c4b3bb7dfd809d97b7ed19a584052a2725c"
+ integrity sha512-jw8XW/B1i7Lqwqj2CbrViPcZijSxfguBWZP2aN59NHgxUyO/OcO1mfdCxH13QhN5LbWhPkX+f+brKGhZTiqtZQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
-"@babel/plugin-transform-classes@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz#8f4b9562850cd973de3b498f1218796eb181ce00"
- integrity sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==
+"@babel/plugin-transform-classes@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.17.12.tgz#da889e89a4d38375eeb24985218edeab93af4f29"
+ integrity sha512-cvO7lc7pZat6BsvH6l/EGaI8zpl8paICaoGk+7x7guvtfak/TbIf66nYmJOH13EuG0H+Xx3M+9LQDtSvZFKXKw==
dependencies:
"@babel/helper-annotate-as-pure" "^7.16.7"
"@babel/helper-environment-visitor" "^7.16.7"
- "@babel/helper-function-name" "^7.16.7"
+ "@babel/helper-function-name" "^7.17.9"
"@babel/helper-optimise-call-expression" "^7.16.7"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/helper-replace-supers" "^7.16.7"
"@babel/helper-split-export-declaration" "^7.16.7"
globals "^11.1.0"
-"@babel/plugin-transform-computed-properties@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz#66dee12e46f61d2aae7a73710f591eb3df616470"
- integrity sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==
+"@babel/plugin-transform-computed-properties@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz#bca616a83679698f3258e892ed422546e531387f"
+ integrity sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
-"@babel/plugin-transform-destructuring@^7.17.7":
- version "7.17.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1"
- integrity sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ==
+"@babel/plugin-transform-destructuring@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.12.tgz#0861d61e75e2401aca30f2570d46dfc85caacf35"
+ integrity sha512-P8pt0YiKtX5UMUL5Xzsc9Oyij+pJE6JuC+F1k0/brq/OOGs5jDa1If3OY0LRWGvJsJhI+8tsiecL3nJLc0WTlg==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4":
version "7.16.7"
@@ -672,12 +672,12 @@
"@babel/helper-create-regexp-features-plugin" "^7.16.7"
"@babel/helper-plugin-utils" "^7.16.7"
-"@babel/plugin-transform-duplicate-keys@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz#2207e9ca8f82a0d36a5a67b6536e7ef8b08823c9"
- integrity sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==
+"@babel/plugin-transform-duplicate-keys@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.17.12.tgz#a09aa709a3310013f8e48e0e23bc7ace0f21477c"
+ integrity sha512-EA5eYFUG6xeerdabina/xIoB95jJ17mAkR8ivx6ZSu9frKShBjpOGZPn511MTDTkiCO+zXnzNczvUM69YSf3Zw==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-transform-exponentiation-operator@^7.16.7":
version "7.16.7"
@@ -687,12 +687,12 @@
"@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7"
"@babel/helper-plugin-utils" "^7.16.7"
-"@babel/plugin-transform-for-of@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz#649d639d4617dff502a9a158c479b3b556728d8c"
- integrity sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==
+"@babel/plugin-transform-for-of@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.17.12.tgz#5397c22554ec737a27918e7e7e0e7b679b05f5ec"
+ integrity sha512-76lTwYaCxw8ldT7tNmye4LLwSoKDbRCBzu6n/DcK/P3FOR29+38CIIaVIZfwol9By8W/QHORYEnYSLuvcQKrsg==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-transform-function-name@^7.16.7":
version "7.16.7"
@@ -703,12 +703,12 @@
"@babel/helper-function-name" "^7.16.7"
"@babel/helper-plugin-utils" "^7.16.7"
-"@babel/plugin-transform-literals@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz#254c9618c5ff749e87cb0c0cef1a0a050c0bdab1"
- integrity sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==
+"@babel/plugin-transform-literals@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz#97131fbc6bbb261487105b4b3edbf9ebf9c830ae"
+ integrity sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-transform-member-expression-literals@^7.16.7":
version "7.16.7"
@@ -717,57 +717,58 @@
dependencies:
"@babel/helper-plugin-utils" "^7.16.7"
-"@babel/plugin-transform-modules-amd@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz#b28d323016a7daaae8609781d1f8c9da42b13186"
- integrity sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==
+"@babel/plugin-transform-modules-amd@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.17.12.tgz#08ec1f10f854c15bb3b44952e60f1fc126d7d481"
+ integrity sha512-p5rt9tB5Ndcc2Za7CeNxVf7YAjRcUMR6yi8o8tKjb9KhRkEvXwa+C0hj6DA5bVDkKRxB0NYhMUGbVKoFu4+zEA==
dependencies:
- "@babel/helper-module-transforms" "^7.16.7"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-module-transforms" "^7.17.12"
+ "@babel/helper-plugin-utils" "^7.17.12"
babel-plugin-dynamic-import-node "^2.3.3"
-"@babel/plugin-transform-modules-commonjs@^7.17.9":
- version "7.17.9"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.9.tgz#274be1a2087beec0254d4abd4d86e52442e1e5b6"
- integrity sha512-2TBFd/r2I6VlYn0YRTz2JdazS+FoUuQ2rIFHoAxtyP/0G3D82SBLaRq9rnUkpqlLg03Byfl/+M32mpxjO6KaPw==
+"@babel/plugin-transform-modules-commonjs@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.12.tgz#37691c7404320d007288edd5a2d8600bcef61c34"
+ integrity sha512-tVPs6MImAJz+DiX8Y1xXEMdTk5Lwxu9jiPjlS+nv5M2A59R7+/d1+9A8C/sbuY0b3QjIxqClkj6KAplEtRvzaA==
dependencies:
- "@babel/helper-module-transforms" "^7.17.7"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-module-transforms" "^7.17.12"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/helper-simple-access" "^7.17.7"
babel-plugin-dynamic-import-node "^2.3.3"
-"@babel/plugin-transform-modules-systemjs@^7.17.8":
- version "7.17.8"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz#81fd834024fae14ea78fbe34168b042f38703859"
- integrity sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw==
+"@babel/plugin-transform-modules-systemjs@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.12.tgz#e631b151b99d25401cd9679476cc35e6e5bbc7d4"
+ integrity sha512-NVhDb0q00hqZcuLduUf/kMzbOQHiocmPbIxIvk23HLiEqaTKC/l4eRxeC7lO63M72BmACoiKOcb9AkOAJRerpw==
dependencies:
"@babel/helper-hoist-variables" "^7.16.7"
- "@babel/helper-module-transforms" "^7.17.7"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-module-transforms" "^7.17.12"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/helper-validator-identifier" "^7.16.7"
babel-plugin-dynamic-import-node "^2.3.3"
-"@babel/plugin-transform-modules-umd@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz#23dad479fa585283dbd22215bff12719171e7618"
- integrity sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==
+"@babel/plugin-transform-modules-umd@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.17.12.tgz#b37be3ecf198c1fea10e6268461729ced05644e1"
+ integrity sha512-BnsPkrUHsjzZGpnrmJeDFkOMMljWFHPjDc9xDcz71/C+ybF3lfC3V4m3dwXPLZrE5b3bgd4V+3/Pj+3620d7IA==
dependencies:
- "@babel/helper-module-transforms" "^7.16.7"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-module-transforms" "^7.17.12"
+ "@babel/helper-plugin-utils" "^7.17.12"
-"@babel/plugin-transform-named-capturing-groups-regex@^7.17.10":
- version "7.17.10"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.10.tgz#715dbcfafdb54ce8bccd3d12e8917296a4ba66a4"
- integrity sha512-v54O6yLaJySCs6mGzaVOUw9T967GnH38T6CQSAtnzdNPwu84l2qAjssKzo/WSO8Yi7NF+7ekm5cVbF/5qiIgNA==
+"@babel/plugin-transform-named-capturing-groups-regex@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.12.tgz#9c4a5a5966e0434d515f2675c227fd8cc8606931"
+ integrity sha512-vWoWFM5CKaTeHrdUJ/3SIOTRV+MBVGybOC9mhJkaprGNt5demMymDW24yC74avb915/mIRe3TgNb/d8idvnCRA==
dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.17.0"
+ "@babel/helper-create-regexp-features-plugin" "^7.17.12"
+ "@babel/helper-plugin-utils" "^7.17.12"
-"@babel/plugin-transform-new-target@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz#9967d89a5c243818e0800fdad89db22c5f514244"
- integrity sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==
+"@babel/plugin-transform-new-target@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.17.12.tgz#10842cd605a620944e81ea6060e9e65c265742e3"
+ integrity sha512-CaOtzk2fDYisbjAD4Sd1MTKGVIpRtx9bWLyj24Y/k6p4s4gQ3CqDGJauFJxt8M/LEx003d0i3klVqnN73qvK3w==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-transform-object-super@^7.16.7":
version "7.16.7"
@@ -777,12 +778,12 @@
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/helper-replace-supers" "^7.16.7"
-"@babel/plugin-transform-parameters@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz#a1721f55b99b736511cb7e0152f61f17688f331f"
- integrity sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==
+"@babel/plugin-transform-parameters@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz#eb467cd9586ff5ff115a9880d6fdbd4a846b7766"
+ integrity sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-transform-property-literals@^7.16.7":
version "7.16.7"
@@ -805,16 +806,16 @@
dependencies:
"@babel/plugin-transform-react-jsx" "^7.16.7"
-"@babel/plugin-transform-react-jsx@^7.16.7":
- version "7.17.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz#eac1565da176ccb1a715dae0b4609858808008c1"
- integrity sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ==
+"@babel/plugin-transform-react-jsx@^7.16.7", "@babel/plugin-transform-react-jsx@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.12.tgz#2aa20022709cd6a3f40b45d60603d5f269586dba"
+ integrity sha512-Lcaw8bxd1DKht3thfD4A12dqo1X16he1Lm8rIv8sTwjAYNInRS1qHa9aJoqvzpscItXvftKDCfaEQzwoVyXpEQ==
dependencies:
"@babel/helper-annotate-as-pure" "^7.16.7"
"@babel/helper-module-imports" "^7.16.7"
- "@babel/helper-plugin-utils" "^7.16.7"
- "@babel/plugin-syntax-jsx" "^7.16.7"
- "@babel/types" "^7.17.0"
+ "@babel/helper-plugin-utils" "^7.17.12"
+ "@babel/plugin-syntax-jsx" "^7.17.12"
+ "@babel/types" "^7.17.12"
"@babel/plugin-transform-react-pure-annotations@^7.16.7":
version "7.16.7"
@@ -831,20 +832,20 @@
dependencies:
regenerator-transform "^0.15.0"
-"@babel/plugin-transform-reserved-words@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz#1d798e078f7c5958eec952059c460b220a63f586"
- integrity sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==
+"@babel/plugin-transform-reserved-words@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.17.12.tgz#7dbd349f3cdffba751e817cf40ca1386732f652f"
+ integrity sha512-1KYqwbJV3Co03NIi14uEHW8P50Md6KqFgt0FfpHdK6oyAHQVTosgPuPSiWud1HX0oYJ1hGRRlk0fP87jFpqXZA==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/plugin-transform-runtime@^7.12.10":
- version "7.17.10"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.10.tgz#b89d821c55d61b5e3d3c3d1d636d8d5a81040ae1"
- integrity sha512-6jrMilUAJhktTr56kACL8LnWC5hx3Lf27BS0R0DSyW/OoJfb/iTHeE96V3b1dgKG3FSFdd/0culnYWMkjcKCig==
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.12.tgz#5dc79735c4038c6f4fc0490f68f2798ce608cadd"
+ integrity sha512-xsl5MeGjWnmV6Ui9PfILM2+YRpa3GqLOrczPpXV3N2KCgQGU+sU8OfzuMbjkIdfvZEZIm+3y0V7w58sk0SGzlw==
dependencies:
"@babel/helper-module-imports" "^7.16.7"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
babel-plugin-polyfill-corejs2 "^0.3.0"
babel-plugin-polyfill-corejs3 "^0.5.0"
babel-plugin-polyfill-regenerator "^0.3.0"
@@ -857,12 +858,12 @@
dependencies:
"@babel/helper-plugin-utils" "^7.16.7"
-"@babel/plugin-transform-spread@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz#a303e2122f9f12e0105daeedd0f30fb197d8ff44"
- integrity sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==
+"@babel/plugin-transform-spread@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz#c112cad3064299f03ea32afed1d659223935d1f5"
+ integrity sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/helper-skip-transparent-expression-wrappers" "^7.16.0"
"@babel/plugin-transform-sticky-regex@^7.16.7":
@@ -872,28 +873,28 @@
dependencies:
"@babel/helper-plugin-utils" "^7.16.7"
-"@babel/plugin-transform-template-literals@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz#f3d1c45d28967c8e80f53666fc9c3e50618217ab"
- integrity sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==
+"@babel/plugin-transform-template-literals@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.17.12.tgz#4aec0a18f39dd86c442e1d077746df003e362c6e"
+ integrity sha512-kAKJ7DX1dSRa2s7WN1xUAuaQmkTpN+uig4wCKWivVXIObqGbVTUlSavHyfI2iZvz89GFAMGm9p2DBJ4Y1Tp0hw==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
-"@babel/plugin-transform-typeof-symbol@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz#9cdbe622582c21368bd482b660ba87d5545d4f7e"
- integrity sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==
+"@babel/plugin-transform-typeof-symbol@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.17.12.tgz#0f12f57ac35e98b35b4ed34829948d42bd0e6889"
+ integrity sha512-Q8y+Jp7ZdtSPXCThB6zjQ74N3lj0f6TDh1Hnf5B+sYlzQ8i5Pjp8gW0My79iekSpT4WnI06blqP6DT0OmaXXmw==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
-"@babel/plugin-transform-typescript@^7.16.7":
- version "7.16.8"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0"
- integrity sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==
+"@babel/plugin-transform-typescript@^7.17.12":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.17.12.tgz#9654587131bc776ff713218d929fa9a2e98ca16d"
+ integrity sha512-ICbXZqg6hgenjmwciVI/UfqZtExBrZOrS8sLB5mTHGO/j08Io3MmooULBiijWk9JBknjM3CbbtTc/0ZsqLrjXQ==
dependencies:
- "@babel/helper-create-class-features-plugin" "^7.16.7"
- "@babel/helper-plugin-utils" "^7.16.7"
- "@babel/plugin-syntax-typescript" "^7.16.7"
+ "@babel/helper-create-class-features-plugin" "^7.17.12"
+ "@babel/helper-plugin-utils" "^7.17.12"
+ "@babel/plugin-syntax-typescript" "^7.17.12"
"@babel/plugin-transform-unicode-escapes@^7.16.7":
version "7.16.7"
@@ -911,31 +912,31 @@
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/preset-env@^7.12.11":
- version "7.17.10"
- resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.17.10.tgz#a81b093669e3eb6541bb81a23173c5963c5de69c"
- integrity sha512-YNgyBHZQpeoBSRBg0xixsZzfT58Ze1iZrajvv0lJc70qDDGuGfonEnMGfWeSY0mQ3JTuCWFbMkzFRVafOyJx4g==
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.17.12.tgz#b81ae0bb762b683d68b07b6d2d4020ccbef8d67a"
+ integrity sha512-Kke30Rj3Lmcx97bVs71LO0s8M6FmJ7tUAQI9fNId62rf0cYG1UAWwdNO9/sE0/pLEahAw1MqMorymoD12bj5Fg==
dependencies:
"@babel/compat-data" "^7.17.10"
"@babel/helper-compilation-targets" "^7.17.10"
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/helper-validator-option" "^7.16.7"
- "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7"
- "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7"
- "@babel/plugin-proposal-async-generator-functions" "^7.16.8"
- "@babel/plugin-proposal-class-properties" "^7.16.7"
- "@babel/plugin-proposal-class-static-block" "^7.17.6"
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.17.12"
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.17.12"
+ "@babel/plugin-proposal-async-generator-functions" "^7.17.12"
+ "@babel/plugin-proposal-class-properties" "^7.17.12"
+ "@babel/plugin-proposal-class-static-block" "^7.17.12"
"@babel/plugin-proposal-dynamic-import" "^7.16.7"
- "@babel/plugin-proposal-export-namespace-from" "^7.16.7"
- "@babel/plugin-proposal-json-strings" "^7.16.7"
- "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7"
- "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7"
+ "@babel/plugin-proposal-export-namespace-from" "^7.17.12"
+ "@babel/plugin-proposal-json-strings" "^7.17.12"
+ "@babel/plugin-proposal-logical-assignment-operators" "^7.17.12"
+ "@babel/plugin-proposal-nullish-coalescing-operator" "^7.17.12"
"@babel/plugin-proposal-numeric-separator" "^7.16.7"
- "@babel/plugin-proposal-object-rest-spread" "^7.17.3"
+ "@babel/plugin-proposal-object-rest-spread" "^7.17.12"
"@babel/plugin-proposal-optional-catch-binding" "^7.16.7"
- "@babel/plugin-proposal-optional-chaining" "^7.16.7"
- "@babel/plugin-proposal-private-methods" "^7.16.11"
- "@babel/plugin-proposal-private-property-in-object" "^7.16.7"
- "@babel/plugin-proposal-unicode-property-regex" "^7.16.7"
+ "@babel/plugin-proposal-optional-chaining" "^7.17.12"
+ "@babel/plugin-proposal-private-methods" "^7.17.12"
+ "@babel/plugin-proposal-private-property-in-object" "^7.17.12"
+ "@babel/plugin-proposal-unicode-property-regex" "^7.17.12"
"@babel/plugin-syntax-async-generators" "^7.8.4"
"@babel/plugin-syntax-class-properties" "^7.12.13"
"@babel/plugin-syntax-class-static-block" "^7.14.5"
@@ -950,40 +951,40 @@
"@babel/plugin-syntax-optional-chaining" "^7.8.3"
"@babel/plugin-syntax-private-property-in-object" "^7.14.5"
"@babel/plugin-syntax-top-level-await" "^7.14.5"
- "@babel/plugin-transform-arrow-functions" "^7.16.7"
- "@babel/plugin-transform-async-to-generator" "^7.16.8"
+ "@babel/plugin-transform-arrow-functions" "^7.17.12"
+ "@babel/plugin-transform-async-to-generator" "^7.17.12"
"@babel/plugin-transform-block-scoped-functions" "^7.16.7"
- "@babel/plugin-transform-block-scoping" "^7.16.7"
- "@babel/plugin-transform-classes" "^7.16.7"
- "@babel/plugin-transform-computed-properties" "^7.16.7"
- "@babel/plugin-transform-destructuring" "^7.17.7"
+ "@babel/plugin-transform-block-scoping" "^7.17.12"
+ "@babel/plugin-transform-classes" "^7.17.12"
+ "@babel/plugin-transform-computed-properties" "^7.17.12"
+ "@babel/plugin-transform-destructuring" "^7.17.12"
"@babel/plugin-transform-dotall-regex" "^7.16.7"
- "@babel/plugin-transform-duplicate-keys" "^7.16.7"
+ "@babel/plugin-transform-duplicate-keys" "^7.17.12"
"@babel/plugin-transform-exponentiation-operator" "^7.16.7"
- "@babel/plugin-transform-for-of" "^7.16.7"
+ "@babel/plugin-transform-for-of" "^7.17.12"
"@babel/plugin-transform-function-name" "^7.16.7"
- "@babel/plugin-transform-literals" "^7.16.7"
+ "@babel/plugin-transform-literals" "^7.17.12"
"@babel/plugin-transform-member-expression-literals" "^7.16.7"
- "@babel/plugin-transform-modules-amd" "^7.16.7"
- "@babel/plugin-transform-modules-commonjs" "^7.17.9"
- "@babel/plugin-transform-modules-systemjs" "^7.17.8"
- "@babel/plugin-transform-modules-umd" "^7.16.7"
- "@babel/plugin-transform-named-capturing-groups-regex" "^7.17.10"
- "@babel/plugin-transform-new-target" "^7.16.7"
+ "@babel/plugin-transform-modules-amd" "^7.17.12"
+ "@babel/plugin-transform-modules-commonjs" "^7.17.12"
+ "@babel/plugin-transform-modules-systemjs" "^7.17.12"
+ "@babel/plugin-transform-modules-umd" "^7.17.12"
+ "@babel/plugin-transform-named-capturing-groups-regex" "^7.17.12"
+ "@babel/plugin-transform-new-target" "^7.17.12"
"@babel/plugin-transform-object-super" "^7.16.7"
- "@babel/plugin-transform-parameters" "^7.16.7"
+ "@babel/plugin-transform-parameters" "^7.17.12"
"@babel/plugin-transform-property-literals" "^7.16.7"
"@babel/plugin-transform-regenerator" "^7.17.9"
- "@babel/plugin-transform-reserved-words" "^7.16.7"
+ "@babel/plugin-transform-reserved-words" "^7.17.12"
"@babel/plugin-transform-shorthand-properties" "^7.16.7"
- "@babel/plugin-transform-spread" "^7.16.7"
+ "@babel/plugin-transform-spread" "^7.17.12"
"@babel/plugin-transform-sticky-regex" "^7.16.7"
- "@babel/plugin-transform-template-literals" "^7.16.7"
- "@babel/plugin-transform-typeof-symbol" "^7.16.7"
+ "@babel/plugin-transform-template-literals" "^7.17.12"
+ "@babel/plugin-transform-typeof-symbol" "^7.17.12"
"@babel/plugin-transform-unicode-escapes" "^7.16.7"
"@babel/plugin-transform-unicode-regex" "^7.16.7"
"@babel/preset-modules" "^0.1.5"
- "@babel/types" "^7.17.10"
+ "@babel/types" "^7.17.12"
babel-plugin-polyfill-corejs2 "^0.3.0"
babel-plugin-polyfill-corejs3 "^0.5.0"
babel-plugin-polyfill-regenerator "^0.3.0"
@@ -1002,25 +1003,25 @@
esutils "^2.0.2"
"@babel/preset-react@^7.12.10":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.16.7.tgz#4c18150491edc69c183ff818f9f2aecbe5d93852"
- integrity sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.17.12.tgz#62adbd2d1870c0de3893095757ed5b00b492ab3d"
+ integrity sha512-h5U+rwreXtZaRBEQhW1hOJLMq8XNJBQ/9oymXiCXTuT/0uOwpbT0gUt+sXeOqoXBgNuUKI7TaObVwoEyWkpFgA==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/helper-validator-option" "^7.16.7"
"@babel/plugin-transform-react-display-name" "^7.16.7"
- "@babel/plugin-transform-react-jsx" "^7.16.7"
+ "@babel/plugin-transform-react-jsx" "^7.17.12"
"@babel/plugin-transform-react-jsx-development" "^7.16.7"
"@babel/plugin-transform-react-pure-annotations" "^7.16.7"
"@babel/preset-typescript@^7.12.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9"
- integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ==
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.17.12.tgz#40269e0a0084d56fc5731b6c40febe1c9a4a3e8c"
+ integrity sha512-S1ViF8W2QwAKUGJXxP9NAfNaqGDdEBJKpYkxHf5Yy2C4NPPzXGeR3Lhk7G8xJaaLcFTRfNjVbtbVtm8Gb0mqvg==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.17.12"
"@babel/helper-validator-option" "^7.16.7"
- "@babel/plugin-transform-typescript" "^7.16.7"
+ "@babel/plugin-transform-typescript" "^7.17.12"
"@babel/register@^7.12.10":
version "7.17.7"
@@ -1057,26 +1058,26 @@
"@babel/parser" "^7.16.7"
"@babel/types" "^7.16.7"
-"@babel/traverse@^7.12.12", "@babel/traverse@^7.13.0", "@babel/traverse@^7.13.17", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.10", "@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9", "@babel/traverse@^7.7.2":
- version "7.17.10"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.10.tgz#1ee1a5ac39f4eac844e6cf855b35520e5eb6f8b5"
- integrity sha512-VmbrTHQteIdUUQNTb+zE12SHS/xQVIShmBPhlNP12hD5poF2pbITW1Z4172d03HegaQWhLffdkRJYtAzp0AGcw==
+"@babel/traverse@^7.12.12", "@babel/traverse@^7.13.0", "@babel/traverse@^7.13.17", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.12", "@babel/traverse@^7.17.9", "@babel/traverse@^7.7.2":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.12.tgz#011874d2abbca0ccf1adbe38f6f7a4ff1747599c"
+ integrity sha512-zULPs+TbCvOkIFd4FrG53xrpxvCBwLIgo6tO0tJorY7YV2IWFxUfS/lXDJbGgfyYt9ery/Gxj2niwttNnB0gIw==
dependencies:
"@babel/code-frame" "^7.16.7"
- "@babel/generator" "^7.17.10"
+ "@babel/generator" "^7.17.12"
"@babel/helper-environment-visitor" "^7.16.7"
"@babel/helper-function-name" "^7.17.9"
"@babel/helper-hoist-variables" "^7.16.7"
"@babel/helper-split-export-declaration" "^7.16.7"
- "@babel/parser" "^7.17.10"
- "@babel/types" "^7.17.10"
+ "@babel/parser" "^7.17.12"
+ "@babel/types" "^7.17.12"
debug "^4.1.0"
globals "^11.1.0"
-"@babel/types@^7.0.0", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.17.10", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
- version "7.17.10"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.10.tgz#d35d7b4467e439fcf06d195f8100e0fea7fc82c4"
- integrity sha512-9O26jG0mBYfGkUYCYZRnBwbVLd1UZOICEr2Em6InB6jVfsAv1GKgwXHmrSg+WFWDmeKTA6vyTZiN8tCSM5Oo3A==
+"@babel/types@^7.0.0", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.17.12", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
+ version "7.17.12"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.12.tgz#1210690a516489c0200f355d87619157fbbd69a0"
+ integrity sha512-rH8i29wcZ6x9xjzI5ILHL/yZkbQnCERdHlogKuIb4PUr7do4iT8DPekrTbBLWTnRQm6U0GYABbTMSzijmEqlAg==
dependencies:
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
@@ -1132,18 +1133,18 @@
lodash.once "^4.1.1"
"@eslint/eslintrc@^1.1.0":
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.2.tgz#4989b9e8c0216747ee7cca314ae73791bb281aae"
- integrity sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.3.tgz#fcaa2bcef39e13d6e9e7f6271f4cc7cae1174886"
+ integrity sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
- espree "^9.3.1"
+ espree "^9.3.2"
globals "^13.9.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
js-yaml "^4.1.0"
- minimatch "^3.0.4"
+ minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@humanwhocodes/config-array@^0.9.2":
@@ -1385,25 +1386,34 @@
"@jridgewell/set-array" "^1.0.0"
"@jridgewell/sourcemap-codec" "^1.4.10"
+"@jridgewell/gen-mapping@^0.3.0":
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9"
+ integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==
+ dependencies:
+ "@jridgewell/set-array" "^1.0.0"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
"@jridgewell/resolve-uri@^3.0.3":
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.6.tgz#4ac237f4dabc8dd93330386907b97591801f7352"
- integrity sha512-R7xHtBSNm+9SyvpJkdQl+qrM3Hm2fea3Ef197M3mUug+v+yR+Rhfbs7PBtcBUVnIWJ4JcAdjvij+c8hXS9p5aw==
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe"
+ integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==
"@jridgewell/set-array@^1.0.0":
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.0.tgz#1179863356ac8fbea64a5a4bcde93a4871012c01"
- integrity sha512-SfJxIxNVYLTsKwzB3MoOQ1yxf4w/E6MdkvTgrgAt1bfxjSrLUoHMKrDOykwN14q65waezZIdqDneUIPh4/sKxg==
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea"
+ integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==
"@jridgewell/sourcemap-codec@^1.4.10":
- version "1.4.12"
- resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.12.tgz#7ed98f6fa525ffb7c56a2cbecb5f7bb91abd2baf"
- integrity sha512-az/NhpIwP3K33ILr0T2bso+k2E/SLf8Yidd8mHl0n6sCQ4YdyC8qDhZA6kOPDNDBA56ZnIjngVl0U3jREA0BUA==
+ version "1.4.13"
+ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c"
+ integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==
"@jridgewell/trace-mapping@^0.3.8", "@jridgewell/trace-mapping@^0.3.9":
- version "0.3.9"
- resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
- integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
+ version "0.3.13"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea"
+ integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
@@ -1424,7 +1434,7 @@
"@mapbox/jsonlint-lines-primitives@^2.0.2":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz#ce56e539f83552b58d10d672ea4d6fc9adc7b234"
- integrity sha1-zlblOfg1UrWNENZy6k1vya3HsjQ=
+ integrity sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==
"@mapbox/mapbox-gl-supported@^1.5.0":
version "1.5.0"
@@ -1434,7 +1444,7 @@
"@mapbox/point-geometry@0.1.0", "@mapbox/point-geometry@^0.1.0", "@mapbox/point-geometry@~0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz#8a83f9335c7860effa2eeeca254332aa0aeed8f2"
- integrity sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI=
+ integrity sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==
"@mapbox/tiny-sdf@^1.1.1":
version "1.2.5"
@@ -1444,7 +1454,7 @@
"@mapbox/unitbezier@^0.0.0":
version "0.0.0"
resolved "https://registry.yarnpkg.com/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz#15651bd553a67b8581fb398810c98ad86a34524e"
- integrity sha1-FWUb1VOme4WB+zmIEMmK2Go0Uk4=
+ integrity sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==
"@mapbox/vector-tile@^1.3.1":
version "1.3.1"
@@ -1589,15 +1599,14 @@
dependencies:
"@octokit/openapi-types" "^11.2.0"
-"@peculiar/asn1-schema@^2.1.0":
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.1.0.tgz#b1c185e1bd65c269d693c569534880cedc8aa5fa"
- integrity sha512-D6g4C5YRKC/iPujMAOXuZ7YGdaoMx8GsvWzfVSyx2LYeL38ECOKNywlYAuwbqQvON64lgsYdAujWQPX8hhoBLw==
+"@peculiar/asn1-schema@^2.1.6":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.1.7.tgz#17d9b79f7df748ef84158ea61a24fc11d9f3f4d9"
+ integrity sha512-RxnHrl7WgNxWPsGeSw7YUGTS3s5En7JwhdOilRpEShQJQ9TH8v1nZtslyZGX5GxgUJ1P4dnRsCnt7R5EYmvtUg==
dependencies:
- "@types/asn1js" "^2.0.2"
- asn1js "^2.3.1"
- pvtsutils "^1.2.1"
- tslib "^2.3.1"
+ asn1js "^3.0.3"
+ pvtsutils "^1.3.2"
+ tslib "^2.4.0"
"@peculiar/json-schema@^1.1.12":
version "1.1.12"
@@ -1607,106 +1616,106 @@
tslib "^2.0.0"
"@peculiar/webcrypto@^1.1.4":
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.3.3.tgz#ccca15d27d64a63df013e6575834563aa5df0dbc"
- integrity sha512-+jkp16Hp18HkphJlMtqsQKjyDWJBh0AhDuoB+vVakuIRbkBdaFb7v26Ldm25altjiYhCyQnR5NChHxwSTvbXJw==
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.4.0.tgz#f941bd95285a0f8a3d2af39ccda5197b80cd32bf"
+ integrity sha512-U58N44b2m3OuTgpmKgf0LPDOmP3bhwNz01vAnj1mBwxBASRhptWYK+M3zG+HBkDqGQM+bFsoIihTW8MdmPXEqg==
dependencies:
- "@peculiar/asn1-schema" "^2.1.0"
+ "@peculiar/asn1-schema" "^2.1.6"
"@peculiar/json-schema" "^1.1.12"
- pvtsutils "^1.2.2"
- tslib "^2.3.1"
- webcrypto-core "^1.7.2"
+ pvtsutils "^1.3.2"
+ tslib "^2.4.0"
+ webcrypto-core "^1.7.4"
-"@percy/cli-build@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/cli-build/-/cli-build-1.1.4.tgz#98f93d427e116264cacde03bd06b5a8bb28029b8"
- integrity sha512-ciifipdGEtBwEsMzUfOBDiVKiYRdGFs3vH3S3gn/3tTSxTp14uICJfTJ/J6vVPmxYEmaduEuVi/yJS4p3/O+SA==
+"@percy/cli-build@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/cli-build/-/cli-build-1.2.1.tgz#6e4e6af1bf664b14ed89c18d8b5599fc4ebf528c"
+ integrity sha512-Xs7N0Z2Yzj9/cZ5ii0jimO8HYtuKxSlj9/pR7n3IjtXhmW9oThNMCjYfNiOiQ/MigzVJgLMnnbgsyhm8/+9X3w==
dependencies:
- "@percy/cli-command" "1.1.4"
+ "@percy/cli-command" "1.2.1"
-"@percy/cli-command@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/cli-command/-/cli-command-1.1.4.tgz#5732d43b5506c9c22d39703ba6200a242897bad0"
- integrity sha512-DooBkI0H3A1o/+NIr2diCgFmAoWCl7IZcoKasTCZnZYNVVLJhIqxNFtb/t8jpj+NC4ga0E4OGGEtNQ9ZcdtzHw==
+"@percy/cli-command@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/cli-command/-/cli-command-1.2.1.tgz#b526ce7861ba590fc605def3adc5707ba9cb1498"
+ integrity sha512-jW7p8MJ3+ZCXCbB0Pv2gUifAzGdY+RhS45a/1jpCj68VHXen6FynPX0XNNnzl1CbYDZ6wkqis3IMIuNdbsKSlw==
dependencies:
- "@percy/config" "1.1.4"
- "@percy/core" "1.1.4"
- "@percy/logger" "1.1.4"
+ "@percy/config" "1.2.1"
+ "@percy/core" "1.2.1"
+ "@percy/logger" "1.2.1"
-"@percy/cli-config@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/cli-config/-/cli-config-1.1.4.tgz#13b2957f12e3383f2fe9b993c48aebf922ee1c76"
- integrity sha512-dbkARKV/tXCa5pUB9jzdputfLMwjURwhwytDnh6Wwh9/GiY9RQW1ARGgJipwmZjcCp27ytbcRM1+zy0DXJ5nww==
+"@percy/cli-config@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/cli-config/-/cli-config-1.2.1.tgz#1e0d53c93b326d57a2f5651f26d3e163a6de169f"
+ integrity sha512-m2Kt6rSZgXw1t7hRLT11eyyCRXXD2xEATqVJH37Q1qMMid4VCCCY88AFaYH+E965UAgMkTVqVyk2ydsDb9gMAg==
dependencies:
- "@percy/cli-command" "1.1.4"
+ "@percy/cli-command" "1.2.1"
-"@percy/cli-exec@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/cli-exec/-/cli-exec-1.1.4.tgz#325c89526b522098bf98fcf155c2368759bcad50"
- integrity sha512-2stWIHPMAlDzjRVb04pg2CUb/3h66S51ExBeUvjAY0CBKOhWQZX/PQidQLgZJy2pgFZnPQvk3Uesg8h5i6Vc7g==
+"@percy/cli-exec@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/cli-exec/-/cli-exec-1.2.1.tgz#b24c07808aba00fab88146d6f8a5664548a2211e"
+ integrity sha512-7K6SOt/ORsr1PQ9hp16xkPWaR9IF0Z2bZfOjGw4dr3pqVYZu/sW9gCttiOH9ONG9fjA2faDuXuS91NW0EkABAQ==
dependencies:
- "@percy/cli-command" "1.1.4"
+ "@percy/cli-command" "1.2.1"
cross-spawn "^7.0.3"
which "^2.0.2"
-"@percy/cli-snapshot@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/cli-snapshot/-/cli-snapshot-1.1.4.tgz#42407a9568c90b656bb08fee7f1bdeb3e12a5c14"
- integrity sha512-c6u9zJYZThyFIEnPWtqaiPfSgRXX+Ncpc4mObFRne8gQJX62OVji06keaa98wyxHDZyFqUe8NUr9t6pOzWjISw==
+"@percy/cli-snapshot@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/cli-snapshot/-/cli-snapshot-1.2.1.tgz#63ebe11ac3b5485b1fdb1137d76dd72af0d347ba"
+ integrity sha512-cuem4pH6eEbaPIyOjsXM7BnfVe2sEVcRZOvhaA/P7d44TEWDgCQeTfHvCiDQM+aoXaqjJ7mq2Ezg+jxfWA19DQ==
dependencies:
- "@percy/cli-command" "1.1.4"
+ "@percy/cli-command" "1.2.1"
yaml "^2.0.0"
-"@percy/cli-upload@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/cli-upload/-/cli-upload-1.1.4.tgz#d837f342acc1d000dd8250fdfe6d7e13eaba28d1"
- integrity sha512-R07+U/DGn5T5pTuQ5vGETDmfhdQlZFeD8NDBYwdHOWlXN5gjnN4HfoZNfJ67hPwLGYOPiYXhjz83HkeyTsnn6w==
+"@percy/cli-upload@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/cli-upload/-/cli-upload-1.2.1.tgz#f8b6bf74bbe1161c580b66b9b0d288706f2bbb88"
+ integrity sha512-yJDqFDtm3if6Ggk+XP3nkfFM/vVzoVxzlD2Vjhz387fzKHKeMPVrhAeBTr8ng8Luxi50bHlNtBVzHeQf1BWfDg==
dependencies:
- "@percy/cli-command" "1.1.4"
+ "@percy/cli-command" "1.2.1"
fast-glob "^3.2.11"
image-size "^1.0.0"
"@percy/cli@^1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/cli/-/cli-1.1.4.tgz#fdc4858dec0d8e3404473c6b3de700215f1739e7"
- integrity sha512-nKGwdI/ZvVuTNjf+Yl1m4ctcIAKcoxlD2nOcCT+VEi9Y9L7sXbreFtwsIQFmSNqyH9rgSxAXcNnPXAj3DpDZcw==
- dependencies:
- "@percy/cli-build" "1.1.4"
- "@percy/cli-command" "1.1.4"
- "@percy/cli-config" "1.1.4"
- "@percy/cli-exec" "1.1.4"
- "@percy/cli-snapshot" "1.1.4"
- "@percy/cli-upload" "1.1.4"
- "@percy/client" "1.1.4"
- "@percy/logger" "1.1.4"
-
-"@percy/client@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/client/-/client-1.1.4.tgz#21fa40a6f1d218b4c8567382af03d5d7f6d5ac1b"
- integrity sha512-aJSDwQkMBiutJa7vbGZPup/wnA+EpKFVMKYyIfoAkqggqDHmHYTzHzg9C5TvH8DRzkc3xZG0vBQc1l7dgRth9A==
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/cli/-/cli-1.2.1.tgz#52bfb6551756594f2ed4b6756a051986eebf88e1"
+ integrity sha512-UClQXESfjQlfOsJ4pBrYF6nvOjIHvlRLWBfYj0SuLE2aRTO03Ehis+40dNlMUHVzbywdaXC0EAqyQqk6YBOTlg==
+ dependencies:
+ "@percy/cli-build" "1.2.1"
+ "@percy/cli-command" "1.2.1"
+ "@percy/cli-config" "1.2.1"
+ "@percy/cli-exec" "1.2.1"
+ "@percy/cli-snapshot" "1.2.1"
+ "@percy/cli-upload" "1.2.1"
+ "@percy/client" "1.2.1"
+ "@percy/logger" "1.2.1"
+
+"@percy/client@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/client/-/client-1.2.1.tgz#c22193955599dd048cb1066f8c37b9fe25f8590a"
+ integrity sha512-YmpCgISEyiyGxeLKVuq0zPWn2SeHeg/pO2T17MKp2VxtEFxEtjul5mV/5qZ7QdN7EsWz47nzuENEBRWX0pDxxQ==
dependencies:
- "@percy/env" "1.1.4"
- "@percy/logger" "1.1.4"
+ "@percy/env" "1.2.1"
+ "@percy/logger" "1.2.1"
-"@percy/config@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/config/-/config-1.1.4.tgz#66ccf25dff9f02061f679b0af00061b37cd4be83"
- integrity sha512-h1d6105dvV8pNMkohEauG/6I4xnzr2kjDEaaoVDsJazyMP0mIj/V7SLrM+KuQDTkn7vSmcty5rHPF+OjOgMhwA==
+"@percy/config@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/config/-/config-1.2.1.tgz#62cf97838a5e33116926007240fb33da267a159e"
+ integrity sha512-uv8tTMUFlFwQoYdV+Zxn6UoeuHXws9nfu8e7tQC7oQyg+AXYq06cqgxhFyHAyfGIhLZqyH5f4E+qCCCeTDJVqQ==
dependencies:
- "@percy/logger" "1.1.4"
+ "@percy/logger" "1.2.1"
ajv "^8.6.2"
cosmiconfig "^7.0.0"
yaml "^2.0.0"
-"@percy/core@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/core/-/core-1.1.4.tgz#705d632929480e9288675f629da1b0836ed8f68f"
- integrity sha512-XefP+c/EAKH5ZHdxjVpY32ywLMIIm8sF87gZOMrRCxX29IX3epoctLBc7Ce0ZemXMVJPIVxdb0t/3qiOwe0PDg==
+"@percy/core@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/core/-/core-1.2.1.tgz#062843dbb9e2481ce13a2d052f45e790b80b3f46"
+ integrity sha512-jvSW+5O1Ijlvg8pJl9BRMhj7GHHrTCFlvH7A5hl750sdpqYVKI/blOJKjKIapYDIGbGKBp8KRRM/xqXVQM5k3g==
dependencies:
- "@percy/client" "1.1.4"
- "@percy/config" "1.1.4"
- "@percy/dom" "1.1.4"
- "@percy/logger" "1.1.4"
+ "@percy/client" "1.2.1"
+ "@percy/config" "1.2.1"
+ "@percy/dom" "1.2.1"
+ "@percy/logger" "1.2.1"
content-disposition "^0.5.4"
cross-spawn "^7.0.3"
extract-zip "^2.0.1"
@@ -1724,25 +1733,25 @@
dependencies:
"@percy/sdk-utils" "^1.0.0-beta.44"
-"@percy/dom@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/dom/-/dom-1.1.4.tgz#b385960735e7c297b6e5930ce9e31992fa6eb9c6"
- integrity sha512-5Z+2UtX0xcLNt/ECGdrVSesfZlawqj31YFpaEPq71RWKtzBjG/GxlymAX5lqhY2T+EFiKtCF7d/oLJAYcJhZPQ==
+"@percy/dom@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/dom/-/dom-1.2.1.tgz#5b228c4242bf55b1502f611bed86dbf4ec109b9a"
+ integrity sha512-C3U95vTiJGDllGJFkKpKRyUC39acze0nUxY/BSZCVFPL2tYmW6QTUr+y0+HXbYUmglylzaWWHRsc5+HtDyMfTw==
-"@percy/env@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/env/-/env-1.1.4.tgz#9b069a80ec0d1f66acc746d0a33f48be6547babb"
- integrity sha512-RdAcaXSAf7OPhiiXaoD/zQF9kYTi8E4P6uwEBQlRPjgk19oYwblpwQOGA8QJIyFXuJKvz5su+yyCynvsCdjMJA==
+"@percy/env@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/env/-/env-1.2.1.tgz#653dab920e5f478fbaa2c5aa11161caa1ca20225"
+ integrity sha512-vXBX0xKGzEaygGFAlQkuv9/IemiulDK/YTWtza53HTAoEfRsITpOsx5KGckbVrNd1l3zOh/bonDzAHneLaCDGw==
-"@percy/logger@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/logger/-/logger-1.1.4.tgz#5fa8d823d643bdd8e298c50bebfe1942c869c599"
- integrity sha512-ZaKW1WHkUq1Oiz9KgbKae5u6Zn33ZuWI8S2bwl6w5aRBdnaoy3vwPDeef0WaN7BHKPmG8n0BgCS9m5IOug/kxA==
+"@percy/logger@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/logger/-/logger-1.2.1.tgz#c76f44bc0d647190772b69a43099c44c74acc584"
+ integrity sha512-Yo/Df6w1O+IV8mTMfcObk2DZK2BrNAC1yx3UBAcbPV/vGkg+vJa/lRVtJl2rGBO0yh3n5HSFlPjkhadrc/h7/g==
"@percy/sdk-utils@^1.0.0-beta.44":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@percy/sdk-utils/-/sdk-utils-1.1.4.tgz#67a98b3da424038a49fd33673b1f7f35d04dd170"
- integrity sha512-fXpRt9Sgq3eerBobRAZ4No/e5LqHn4IHU9bpsxSExVMYridDBB3hy31ZyTRPjImXPDqNZs6BaYB5Yn+zq8mD+A==
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@percy/sdk-utils/-/sdk-utils-1.2.1.tgz#fdb29b400ad45c1c4998716587a80475e790e1b9"
+ integrity sha512-Ey7T4XNJHb1kolMTFyh322tn9hapeLChCUovMy3P9zQ+Fh/LtyspVNo8uhOG+Vmidxqb0bwXkooTQTgGODFckQ==
"@sentry/browser@^6.11.0":
version "6.19.7"
@@ -1848,11 +1857,6 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
-"@types/asn1js@^2.0.2":
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/@types/asn1js/-/asn1js-2.0.2.tgz#bb1992291381b5f06e22a829f2ae009267cdf8c5"
- integrity sha512-t4YHCgtD+ERvH0FyxvNlYwJ2ezhqw7t+Ygh4urQ7dJER8i185JPv6oIM3ey5YQmGN6Zp9EMbpohkjZi9t3UxwA==
-
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.7":
version "7.1.19"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460"
@@ -1941,7 +1945,7 @@
"@types/fbemitter@*":
version "2.0.32"
resolved "https://registry.yarnpkg.com/@types/fbemitter/-/fbemitter-2.0.32.tgz#8ed204da0f54e9c8eaec31b1eec91e25132d082c"
- integrity sha1-jtIE2g9U6cjq7DGx7skeJRMtCCw=
+ integrity sha512-Hwq28bBlbmfCgLnNJvjl5ssTrbZCTSblI4vqPpqZrbbEL8vn5l2UivxhlMYfUY7a4SR8UB6RKoLjOZfljqAa6g==
"@types/file-saver@^2.0.3":
version "2.0.5"
@@ -2018,7 +2022,7 @@
"@types/json5@^0.0.29":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
- integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
+ integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
"@types/lodash@^4.14.168":
version "4.14.182"
@@ -2043,14 +2047,14 @@
integrity sha512-jhMOZSS0UGYTS9pqvt6q3wtT3uvOSve5piTEmTMx3zzTuBLvSIMxSIBIc3d5lajVD5h4xc41AMZD2M5orN3PxA==
"@types/node@*":
- version "17.0.31"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.31.tgz#a5bb84ecfa27eec5e1c802c6bbf8139bdb163a5d"
- integrity sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q==
+ version "17.0.34"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.34.tgz#3b0b6a50ff797280b8d000c6281d229f9c538cef"
+ integrity sha512-XImEz7XwTvDBtzlTnm8YvMqGW/ErMWBsKZ+hMTvnDIjGCKxwK5Xpc+c/oQjOauwq8M4OS11hEkpjX8rrI/eEgA==
"@types/node@^14.14.22", "@types/node@^14.14.31":
- version "14.18.16"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.16.tgz#878f670ba3f00482bf859b6550b6010610fc54b5"
- integrity sha512-X3bUMdK/VmvrWdoTkz+VCn6nwKwrKCFTHtqwBIaQJNx4RUIBBUFXM00bqPz/DsDd+Icjmzm6/tyYZzeGVqb6/Q==
+ version "14.18.18"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.18.tgz#5c9503030df484ccffcbb935ea9a9e1d6fad1a20"
+ integrity sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig==
"@types/normalize-package-data@^2.4.0":
version "2.4.1"
@@ -2058,9 +2062,9 @@
integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==
"@types/pako@^1.0.1":
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/@types/pako/-/pako-1.0.3.tgz#2e61c2b02020b5f44e2e5e946dfac74f4ec33c58"
- integrity sha512-EDxOsHAD5dqjbjEUM1xwa7rpKPFb8ECBE5irONTQU7/OsO3thI5YrNEWSPNMvYmvFM0l/OLQJ6Mgw7PEdXSjhg==
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@types/pako/-/pako-1.0.4.tgz#b4262aef92680a9331fcdb8420c69cf3dd98d3f3"
+ integrity sha512-Z+5bJSm28EXBSUJEgx29ioWeEEHUh6TiMkZHDhLwjc9wVFH+ressbkmX6waUZc5R3Gobn4Qu5llGxaoflZ+yhA==
"@types/parse-json@^4.0.0":
version "4.0.0"
@@ -2073,9 +2077,9 @@
integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==
"@types/prettier@^2.1.5":
- version "2.6.0"
- resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.0.tgz#efcbd41937f9ae7434c714ab698604822d890759"
- integrity sha512-G/AdOadiZhnJp0jXCaBQU449W2h716OW/EoXeYkCytxKL06X1WCXB4DZpp8TpZ8eyIJVS1cw4lrlkkSYU21cDw==
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.1.tgz#76e72d8a775eef7ce649c63c8acae1a0824bbaed"
+ integrity sha512-XFjFHmaLVifrAKaZ+EKghFHtHSUonyw8P2Qmy2/+osBnrKbH9UYtlK10zg8/kCt47MFilll/DEDKy3DHfJ0URw==
"@types/prop-types@*":
version "15.7.5"
@@ -2205,84 +2209,84 @@
integrity sha512-3NoqvZC2W5gAC5DZbTpCeJ251vGQmgcWIHQJGq2J240HY6ErQ9aWKkwfoKJlHLx+A83WPNTZ9+3cd2ILxbvr1w==
"@typescript-eslint/eslint-plugin@^5.6.0":
- version "5.22.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.22.0.tgz#7b52a0de2e664044f28b36419210aea4ab619e2a"
- integrity sha512-YCiy5PUzpAeOPGQ7VSGDEY2NeYUV1B0swde2e0HzokRsHBYjSdF6DZ51OuRZxVPHx0032lXGLvOMls91D8FXlg==
- dependencies:
- "@typescript-eslint/scope-manager" "5.22.0"
- "@typescript-eslint/type-utils" "5.22.0"
- "@typescript-eslint/utils" "5.22.0"
- debug "^4.3.2"
+ version "5.25.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.25.0.tgz#e8ce050990e4d36cc200f2de71ca0d3eb5e77a31"
+ integrity sha512-icYrFnUzvm+LhW0QeJNKkezBu6tJs9p/53dpPLFH8zoM9w1tfaKzVurkPotEpAqQ8Vf8uaFyL5jHd0Vs6Z0ZQg==
+ dependencies:
+ "@typescript-eslint/scope-manager" "5.25.0"
+ "@typescript-eslint/type-utils" "5.25.0"
+ "@typescript-eslint/utils" "5.25.0"
+ debug "^4.3.4"
functional-red-black-tree "^1.0.1"
- ignore "^5.1.8"
+ ignore "^5.2.0"
regexpp "^3.2.0"
- semver "^7.3.5"
+ semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/parser@^5.6.0":
- version "5.22.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.22.0.tgz#7bedf8784ef0d5d60567c5ba4ce162460e70c178"
- integrity sha512-piwC4krUpRDqPaPbFaycN70KCP87+PC5WZmrWs+DlVOxxmF+zI6b6hETv7Quy4s9wbkV16ikMeZgXsvzwI3icQ==
- dependencies:
- "@typescript-eslint/scope-manager" "5.22.0"
- "@typescript-eslint/types" "5.22.0"
- "@typescript-eslint/typescript-estree" "5.22.0"
- debug "^4.3.2"
-
-"@typescript-eslint/scope-manager@5.22.0":
- version "5.22.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.22.0.tgz#590865f244ebe6e46dc3e9cab7976fc2afa8af24"
- integrity sha512-yA9G5NJgV5esANJCO0oF15MkBO20mIskbZ8ijfmlKIvQKg0ynVKfHZ15/nhAJN5m8Jn3X5qkwriQCiUntC9AbA==
- dependencies:
- "@typescript-eslint/types" "5.22.0"
- "@typescript-eslint/visitor-keys" "5.22.0"
-
-"@typescript-eslint/type-utils@5.22.0":
- version "5.22.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.22.0.tgz#0c0e93b34210e334fbe1bcb7250c470f4a537c19"
- integrity sha512-iqfLZIsZhK2OEJ4cQ01xOq3NaCuG5FQRKyHicA3xhZxMgaxQazLUHbH/B2k9y5i7l3+o+B5ND9Mf1AWETeMISA==
- dependencies:
- "@typescript-eslint/utils" "5.22.0"
- debug "^4.3.2"
+ version "5.25.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.25.0.tgz#fb533487147b4b9efd999a4d2da0b6c263b64f7f"
+ integrity sha512-r3hwrOWYbNKP1nTcIw/aZoH+8bBnh/Lh1iDHoFpyG4DnCpvEdctrSl6LOo19fZbzypjQMHdajolxs6VpYoChgA==
+ dependencies:
+ "@typescript-eslint/scope-manager" "5.25.0"
+ "@typescript-eslint/types" "5.25.0"
+ "@typescript-eslint/typescript-estree" "5.25.0"
+ debug "^4.3.4"
+
+"@typescript-eslint/scope-manager@5.25.0":
+ version "5.25.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.25.0.tgz#e78f1484bca7e484c48782075219c82c6b77a09f"
+ integrity sha512-p4SKTFWj+2VpreUZ5xMQsBMDdQ9XdRvODKXN4EksyBjFp2YvQdLkyHqOffakYZPuWJUDNu3jVXtHALDyTv3cww==
+ dependencies:
+ "@typescript-eslint/types" "5.25.0"
+ "@typescript-eslint/visitor-keys" "5.25.0"
+
+"@typescript-eslint/type-utils@5.25.0":
+ version "5.25.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.25.0.tgz#5750d26a5db4c4d68d511611e0ada04e56f613bc"
+ integrity sha512-B6nb3GK3Gv1Rsb2pqalebe/RyQoyG/WDy9yhj8EE0Ikds4Xa8RR28nHz+wlt4tMZk5bnAr0f3oC8TuDAd5CPrw==
+ dependencies:
+ "@typescript-eslint/utils" "5.25.0"
+ debug "^4.3.4"
tsutils "^3.21.0"
-"@typescript-eslint/types@5.22.0":
- version "5.22.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.22.0.tgz#50a4266e457a5d4c4b87ac31903b28b06b2c3ed0"
- integrity sha512-T7owcXW4l0v7NTijmjGWwWf/1JqdlWiBzPqzAWhobxft0SiEvMJB56QXmeCQjrPuM8zEfGUKyPQr/L8+cFUBLw==
+"@typescript-eslint/types@5.25.0":
+ version "5.25.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.25.0.tgz#dee51b1855788b24a2eceeae54e4adb89b088dd8"
+ integrity sha512-7fWqfxr0KNHj75PFqlGX24gWjdV/FDBABXL5dyvBOWHpACGyveok8Uj4ipPX/1fGU63fBkzSIycEje4XsOxUFA==
-"@typescript-eslint/typescript-estree@5.22.0":
- version "5.22.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.22.0.tgz#e2116fd644c3e2fda7f4395158cddd38c0c6df97"
- integrity sha512-EyBEQxvNjg80yinGE2xdhpDYm41so/1kOItl0qrjIiJ1kX/L/L8WWGmJg8ni6eG3DwqmOzDqOhe6763bF92nOw==
+"@typescript-eslint/typescript-estree@5.25.0":
+ version "5.25.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.25.0.tgz#a7ab40d32eb944e3fb5b4e3646e81b1bcdd63e00"
+ integrity sha512-MrPODKDych/oWs/71LCnuO7NyR681HuBly2uLnX3r5i4ME7q/yBqC4hW33kmxtuauLTM0OuBOhhkFaxCCOjEEw==
dependencies:
- "@typescript-eslint/types" "5.22.0"
- "@typescript-eslint/visitor-keys" "5.22.0"
- debug "^4.3.2"
- globby "^11.0.4"
+ "@typescript-eslint/types" "5.25.0"
+ "@typescript-eslint/visitor-keys" "5.25.0"
+ debug "^4.3.4"
+ globby "^11.1.0"
is-glob "^4.0.3"
- semver "^7.3.5"
+ semver "^7.3.7"
tsutils "^3.21.0"
-"@typescript-eslint/utils@5.22.0":
- version "5.22.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.22.0.tgz#1f2c4897e2cf7e44443c848a13c60407861babd8"
- integrity sha512-HodsGb037iobrWSUMS7QH6Hl1kppikjA1ELiJlNSTYf/UdMEwzgj0WIp+lBNb6WZ3zTwb0tEz51j0Wee3iJ3wQ==
+"@typescript-eslint/utils@5.25.0":
+ version "5.25.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.25.0.tgz#272751fd737733294b4ab95e16c7f2d4a75c2049"
+ integrity sha512-qNC9bhnz/n9Kba3yI6HQgQdBLuxDoMgdjzdhSInZh6NaDnFpTUlwNGxplUFWfY260Ya0TRPvkg9dd57qxrJI9g==
dependencies:
"@types/json-schema" "^7.0.9"
- "@typescript-eslint/scope-manager" "5.22.0"
- "@typescript-eslint/types" "5.22.0"
- "@typescript-eslint/typescript-estree" "5.22.0"
+ "@typescript-eslint/scope-manager" "5.25.0"
+ "@typescript-eslint/types" "5.25.0"
+ "@typescript-eslint/typescript-estree" "5.25.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
-"@typescript-eslint/visitor-keys@5.22.0":
- version "5.22.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.22.0.tgz#f49c0ce406944ffa331a1cfabeed451ea4d0909c"
- integrity sha512-DbgTqn2Dv5RFWluG88tn0pP6Ex0ROF+dpDO1TNNZdRtLjUr6bdznjA6f/qNqJLjd2PgguAES2Zgxh/JzwzETDg==
+"@typescript-eslint/visitor-keys@5.25.0":
+ version "5.25.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.25.0.tgz#33aa5fdcc5cedb9f4c8828c6a019d58548d4474b"
+ integrity sha512-yd26vFgMsC4h2dgX4+LR+GeicSKIfUvZREFLf3DDjZPtqgLx5AJZr6TetMNwFP9hcKreTTeztQYBTNbNoOycwA==
dependencies:
- "@typescript-eslint/types" "5.22.0"
- eslint-visitor-keys "^3.0.0"
+ "@typescript-eslint/types" "5.25.0"
+ eslint-visitor-keys "^3.3.0"
"@wojtekmaj/enzyme-adapter-react-17@^0.6.1":
version "0.6.7"
@@ -2319,7 +2323,7 @@ acorn-globals@^6.0.0:
acorn "^7.1.1"
acorn-walk "^7.1.1"
-acorn-jsx@^5.3.1:
+acorn-jsx@^5.3.2:
version "5.3.2"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
@@ -2334,7 +2338,7 @@ acorn@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
-acorn@^8.2.4, acorn@^8.7.0:
+acorn@^8.2.4, acorn@^8.7.1:
version "8.7.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
@@ -2396,12 +2400,12 @@ allchange@^1.0.6:
another-json@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/another-json/-/another-json-0.2.0.tgz#b5f4019c973b6dd5c6506a2d93469cb6d32aeedc"
- integrity sha1-tfQBnJc7bdXGUGotk0acttMq7tw=
+ integrity sha512-/Ndrl68UQLhnCdsAzEXLMFuOR546o2qbYRqCglaNHbjXrwG1ayTcdwr3zkSGOGtGXDyR5X9nCFfnyG2AFJIsqg==
ansi-colors@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
- integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b"
+ integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==
ansi-escapes@^4.2.1, ansi-escapes@^4.3.0:
version "4.3.2"
@@ -2483,7 +2487,7 @@ aria-query@^4.2.2:
arr-diff@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
- integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
+ integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==
arr-flatten@^1.1.0:
version "1.1.0"
@@ -2493,7 +2497,7 @@ arr-flatten@^1.1.0:
arr-union@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
- integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
+ integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==
array-includes@^3.1.4:
version "3.1.5"
@@ -2514,7 +2518,7 @@ array-union@^2.1.0:
array-unique@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
- integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
+ integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==
array.prototype.filter@^1.0.0:
version "1.0.1"
@@ -2550,12 +2554,12 @@ array.prototype.flatmap@^1.2.5:
arrify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
- integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
+ integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==
asap@~2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
- integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
+ integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
asn1@~0.2.3:
version "0.2.6"
@@ -2564,27 +2568,29 @@ asn1@~0.2.3:
dependencies:
safer-buffer "~2.1.0"
-asn1js@^2.3.1, asn1js@^2.3.2:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-2.4.0.tgz#9ca61dbdd7e4eb49b9ae95b36ab0615b77daff93"
- integrity sha512-PvZC0FMyMut8aOnR2jAEGSkmRtHIUYPe9amUEnGjr9TdnUmsfoOkjrvUkOEU9mzpYBR1HyO9bF+8U1cLTMMHhQ==
+asn1js@^3.0.1, asn1js@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.3.tgz#fbecdcced2c046552db0c63af284eccc494e0e74"
+ integrity sha512-Oz62ld3K3n6KlRUr4iZSMbSFDDPCW84G1yX7b/gWK5a0Ka7ZYOmCxFpu91lFdQygkBi2Hgoft1/WxRqFrONqLA==
dependencies:
+ pvtsutils "^1.3.2"
pvutils "^1.1.3"
+ tslib "^2.4.0"
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
- integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
+ integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==
assign-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
- integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
+ integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==
ast-types-flow@^0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
- integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0=
+ integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==
astral-regex@^2.0.0:
version "2.0.0"
@@ -2599,7 +2605,7 @@ async@^3.2.0:
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
- integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
+ integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
at-least-node@^1.0.0:
version "1.0.0"
@@ -2637,7 +2643,7 @@ await-lock@^2.1.0:
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
- integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
+ integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==
aws4@^1.8.0:
version "1.11.0"
@@ -2645,9 +2651,9 @@ aws4@^1.8.0:
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
axe-core@^4.3.5:
- version "4.4.1"
- resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.1.tgz#7dbdc25989298f9ad006645cd396782443757413"
- integrity sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw==
+ version "4.4.2"
+ resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.2.tgz#dcf7fb6dea866166c3eab33d68208afe4d5f670c"
+ integrity sha512-LVAaGp/wkkgYJcjmHsoKx4juT1aQvJyPcW09MLCjVTh3V2cc6PnyempiLMNH5iMdfIX/zdbjUx2KDjMLCTdPeA==
axobject-query@^2.2.0:
version "2.2.0"
@@ -2821,7 +2827,7 @@ base@^0.11.1:
bcrypt-pbkdf@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
- integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
+ integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==
dependencies:
tweetnacl "^0.14.3"
@@ -2850,7 +2856,7 @@ blob-util@^2.0.2:
resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb"
integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==
-bluebird@^3.5.0, bluebird@^3.7.2:
+bluebird@^3.7.2:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
@@ -2863,7 +2869,7 @@ blurhash@^1.1.3:
boolbase@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
- integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
+ integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
brace-expansion@^1.1.7:
version "1.1.11"
@@ -2904,7 +2910,7 @@ browser-process-hrtime@^1.0.0:
browser-request@^0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/browser-request/-/browser-request-0.3.3.tgz#9ece5b5aca89a29932242e18bf933def9876cc17"
- integrity sha1-ns5bWsqJopkyJC4Yv5M975h2zBc=
+ integrity sha512-YyNI4qJJ+piQG6MMEuo7J3Bzaqssufx04zpEKYfSrl/1Op59HWali9zMtBpXnkmqMcOuWJPZvudrm9wISmnCbg==
browserslist@^4.12.0, browserslist@^4.20.2, browserslist@^4.20.3:
version "4.20.3"
@@ -2920,7 +2926,7 @@ browserslist@^4.12.0, browserslist@^4.20.2, browserslist@^4.20.3:
bs58@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
- integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo=
+ integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==
dependencies:
base-x "^3.0.2"
@@ -2947,12 +2953,12 @@ buffer-alloc@^1.2.0:
buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
- integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
+ integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==
buffer-fill@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
- integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
+ integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==
buffer-from@^1.0.0, buffer-from@^1.1.1:
version "1.1.2"
@@ -3020,9 +3026,9 @@ camelcase@^6.2.0:
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001332:
- version "1.0.30001335"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001335.tgz#899254a0b70579e5a957c32dced79f0727c61f2a"
- integrity sha512-ddP1Tgm7z2iIxu6QTtbZUv6HJxSaV/PZeSrWFZtbY4JZ69tOeNhBCl3HyRQgeNZKE5AOn1kpV7fhljigy0Ty3w==
+ version "1.0.30001341"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz#59590c8ffa8b5939cf4161f00827b8873ad72498"
+ integrity sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==
capture-exit@^2.0.0:
version "2.0.0"
@@ -3034,7 +3040,7 @@ capture-exit@^2.0.0:
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
- integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
+ integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==
chalk@^2.0.0:
version "2.4.2"
@@ -3076,7 +3082,7 @@ character-reference-invalid@^1.0.0:
check-more-types@^2.24.0:
version "2.24.0"
resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600"
- integrity sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=
+ integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==
cheerio-select@^1.5.0:
version "1.6.0"
@@ -3123,9 +3129,9 @@ ci-info@^2.0.0:
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
ci-info@^3.2.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2"
- integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.1.tgz#58331f6f472a25fe3a50a351ae3052936c2c7f32"
+ integrity sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==
cjs-module-lexer@^1.0.0:
version "1.2.2"
@@ -3345,17 +3351,17 @@ copy-descriptor@^0.1.0:
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
core-js-compat@^3.21.0, core-js-compat@^3.22.1:
- version "3.22.4"
- resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.22.4.tgz#d700f451e50f1d7672dcad0ac85d910e6691e579"
- integrity sha512-dIWcsszDezkFZrfm1cnB4f/J85gyhiCpxbgBdohWCDtSVuAaChTSpPV7ldOQf/Xds2U5xCIJZOK82G4ZPAIswA==
+ version "3.22.5"
+ resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.22.5.tgz#7fffa1d20cb18405bd22756ca1353c6f1a0e8614"
+ integrity sha512-rEF75n3QtInrYICvJjrAgV03HwKiYvtKHdPtaba1KucG+cNZ4NJnH9isqt979e67KZlhpbCOTwnsvnIr+CVeOg==
dependencies:
browserslist "^4.20.3"
semver "7.0.0"
core-js-pure@^3.20.2:
- version "3.22.4"
- resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.22.4.tgz#a992210f4cad8b32786b8654563776c56b0e0d0a"
- integrity sha512-4iF+QZkpzIz0prAFuepmxwJ2h5t4agvE8WPYqs2mjLJMNNwJOnpch76w2Q7bUfCPEv/V7wpvOfog0w273M+ZSw==
+ version "3.22.5"
+ resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.22.5.tgz#bdee0ed2f9b78f2862cda4338a07b13a49b6c9a9"
+ integrity sha512-8xo9R00iYD7TcV7OrC98GwxiUEAabVWO3dix+uyWjnYrx9fyASLlIX+f/3p5dW5qByaP2bcZ8X/T47s55et/tA==
core-js@^1.0.0:
version "1.2.7"
@@ -3482,9 +3488,14 @@ cssstyle@^2.3.0:
cssom "~0.3.6"
csstype@^3.0.2:
- version "3.0.11"
- resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33"
- integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2"
+ integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==
+
+cypress-real-events@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/cypress-real-events/-/cypress-real-events-1.7.0.tgz#ad6a78de33af3af0e6437f5c713e30691c44472c"
+ integrity sha512-iyXp07j0V9sG3YClVDcvHN2DAQDgr+EjTID82uWDw6OZBlU3pXEBqTMNYqroz3bxlb0k+F74U81aZwzMNaKyew==
cypress@^9.6.1:
version "9.6.1"
@@ -3569,11 +3580,11 @@ date-names@^0.1.11:
integrity sha512-IxxoeD9tdx8pXVcmqaRlPvrXIsSrSrIZzfzlOkm9u+hyzKp5Wk/odt9O/gd7Ockzy8n/WHeEpTVJ2bF3mMV4LA==
dayjs@^1.10.4:
- version "1.11.1"
- resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.1.tgz#90b33a3dda3417258d48ad2771b415def6545eb0"
- integrity sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA==
+ version "1.11.2"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.2.tgz#fa0f5223ef0d6724b3d8327134890cfe3d72fbe5"
+ integrity sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==
-debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2:
+debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@@ -3820,9 +3831,9 @@ ecc-jsbn@~0.1.1:
safer-buffer "^2.1.0"
electron-to-chromium@^1.4.118:
- version "1.4.131"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.131.tgz#ca42d22eac0fe545860fbc636a6f4a7190ba70a9"
- integrity sha512-oi3YPmaP87hiHn0c4ePB67tXaF+ldGhxvZnT19tW9zX6/Ej+pLN0Afja5rQ6S+TND7I9EuwQTT8JYn1k7R7rrw==
+ version "1.4.137"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz#186180a45617283f1c012284458510cd99d6787f"
+ integrity sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==
emittery@^0.8.1:
version "0.8.1"
@@ -3952,17 +3963,19 @@ error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.18.5, es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5:
- version "1.19.5"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.5.tgz#a2cb01eb87f724e815b278b0dd0d00f36ca9a7f1"
- integrity sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==
+es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5, es-abstract@^1.20.0:
+ version "1.20.1"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814"
+ integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==
dependencies:
call-bind "^1.0.2"
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
+ function.prototype.name "^1.1.5"
get-intrinsic "^1.1.1"
get-symbol-description "^1.0.0"
has "^1.0.3"
+ has-property-descriptors "^1.0.0"
has-symbols "^1.0.3"
internal-slot "^1.0.3"
is-callable "^1.2.4"
@@ -3974,9 +3987,10 @@ es-abstract@^1.18.5, es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19
object-inspect "^1.12.0"
object-keys "^1.1.1"
object.assign "^4.1.2"
- string.prototype.trimend "^1.0.4"
- string.prototype.trimstart "^1.0.4"
- unbox-primitive "^1.0.1"
+ regexp.prototype.flags "^1.4.3"
+ string.prototype.trimend "^1.0.5"
+ string.prototype.trimstart "^1.0.5"
+ unbox-primitive "^1.0.2"
es-array-method-boxes-properly@^1.0.0:
version "1.0.0"
@@ -4207,7 +4221,7 @@ eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
-eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0:
+eslint-visitor-keys@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
@@ -4253,13 +4267,13 @@ eslint@8.9.0:
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
-espree@^9.3.1:
- version "9.3.1"
- resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd"
- integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==
+espree@^9.3.1, espree@^9.3.2:
+ version "9.3.2"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596"
+ integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==
dependencies:
- acorn "^8.7.0"
- acorn-jsx "^5.3.1"
+ acorn "^8.7.1"
+ acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.3.0"
esprima@^4.0.0, esprima@^4.0.1:
@@ -4666,10 +4680,10 @@ flux@2.1.1:
fbjs "0.1.0-alpha.7"
immutable "^3.7.4"
-focus-lock@^0.11.0:
- version "0.11.0"
- resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.11.0.tgz#72f9055d34fff59d54aec8e602adbb5438108709"
- integrity sha512-7tCIkCdnMEnqwEWr3PktH8wA/SAcIPlhrDuLg+o20DjZ/fZW/rIy7Tc9BC2kJBOttH4vbzTXqte5PL8babatBw==
+focus-lock@^0.11.2:
+ version "0.11.2"
+ resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.11.2.tgz#aeef3caf1cea757797ac8afdebaec8fd9ab243ed"
+ integrity sha512-pZ2bO++NWLHhiKkgP1bEXHhR1/OjVcSvlCJ98aNJDFeb7H5OOQaO+SKOZle6041O9rv2tmbrO4JzClAvDUHf0g==
dependencies:
tslib "^2.0.3"
@@ -4678,16 +4692,18 @@ focus-visible@^5.2.0:
resolved "https://registry.yarnpkg.com/focus-visible/-/focus-visible-5.2.0.tgz#3a9e41fccf587bd25dcc2ef045508284f0a4d6b3"
integrity sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ==
+for-each@^0.3.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
+ integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
+ dependencies:
+ is-callable "^1.1.3"
+
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
-foreach@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
- integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k=
-
foreachasync@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/foreachasync/-/foreachasync-3.0.0.tgz#5502987dc8714be3392097f32e0071c9dee07cf6"
@@ -4892,14 +4908,14 @@ glob-to-regexp@^0.4.1:
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
- integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
- minimatch "^3.0.4"
+ minimatch "^3.1.1"
once "^1.3.0"
path-is-absolute "^1.0.0"
@@ -4932,13 +4948,13 @@ globals@^11.1.0:
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
globals@^13.6.0, globals@^13.9.0:
- version "13.13.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b"
- integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==
+ version "13.15.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-13.15.0.tgz#38113218c907d2f7e98658af246cef8b77e90bac"
+ integrity sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==
dependencies:
type-fest "^0.20.2"
-globby@^11.0.3, globby@^11.0.4:
+globby@^11.0.3, globby@^11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
@@ -5383,7 +5399,7 @@ is-buffer@^2.0.0:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
-is-callable@^1.0.4, is-callable@^1.1.4, is-callable@^1.1.5, is-callable@^1.2.4:
+is-callable@^1.0.4, is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.1.5, is-callable@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
@@ -5673,15 +5689,15 @@ is-symbol@^1.0.2, is-symbol@^1.0.3, is-symbol@^1.0.4:
dependencies:
has-symbols "^1.0.2"
-is-typed-array@^1.1.7:
- version "1.1.8"
- resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.8.tgz#cbaa6585dc7db43318bc5b89523ea384a6f65e79"
- integrity sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==
+is-typed-array@^1.1.9:
+ version "1.1.9"
+ resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.9.tgz#246d77d2871e7d9f5aeb1d54b9f52c71329ece67"
+ integrity sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==
dependencies:
available-typed-arrays "^1.0.5"
call-bind "^1.0.2"
- es-abstract "^1.18.5"
- foreach "^2.0.5"
+ es-abstract "^1.20.0"
+ for-each "^0.3.3"
has-tostringtag "^1.0.0"
is-typedarray@^1.0.0, is-typedarray@~1.0.0:
@@ -6799,10 +6815,10 @@ matrix-events-sdk@^0.0.1-beta.7:
resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1-beta.7.tgz#5ffe45eba1f67cc8d7c2377736c728b322524934"
integrity sha512-9jl4wtWanUFSy2sr2lCjErN/oC8KTAtaeaozJtrgot1JiQcEI4Rda9OLgQ7nLKaqb4Z/QUx/fR3XpDzm5Jy1JA==
-matrix-js-sdk@18.0.0:
- version "18.0.0"
- resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-18.0.0.tgz#2452ca9e80e90180de4591960a3a338151c94446"
- integrity sha512-P7PI2nQs7BfjkEATgVtQK3ix1DqIYBiDsVo9nSwJcG2vqq+Mf2PnnuPtU6/ZQBoUNhMbFCd8XCaxsPnE6XqnEA==
+matrix-js-sdk@18.1.0:
+ version "18.1.0"
+ resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-18.1.0.tgz#9fa312e71cf153c4a8aac88d908c5ddd52181c6c"
+ integrity sha512-O5D36paIsY7a2M2mOo7KKU7v1Mb3PVkmYKupXYcXd9gB/Ki1K4mds+vSDEhgkKyKwk6MK1AV/vgvp0xJCsttvg==
dependencies:
"@babel/runtime" "^7.12.5"
another-json "^0.2.0"
@@ -6816,12 +6832,11 @@ matrix-js-sdk@18.0.0:
request "^2.88.2"
unhomoglyph "^1.0.6"
-matrix-mock-request@^1.2.3:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/matrix-mock-request/-/matrix-mock-request-1.2.3.tgz#56b15d86e2601a9b48a854844396d18caab649c8"
- integrity sha512-Tr7LDHweTW8Ql4C8XhGQFGMzuh+HmPjOcQqrHH1qfSesq0cwdPWanvdnllNjeHoAMcZ43HpMFMzFZfNW1/6HYg==
+matrix-mock-request@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/matrix-mock-request/-/matrix-mock-request-2.0.0.tgz#653c258eb3b6dfbf6a48418e8633a377c82de3ab"
+ integrity sha512-5fQqMwcQuTjUV4PWBBkVJ69qtR1wW7hGylHM7Ilu5yBQdsAIhOH5xPQm8/qrEP2zQNcSogaB42sBGyuIl0Sx4g==
dependencies:
- bluebird "^3.5.0"
expect "^1.20.2"
matrix-react-test-utils@^0.2.3:
@@ -6983,7 +6998,7 @@ min-indent@^1.0.0:
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
-minimatch@^3.0.4, minimatch@^3.1.2:
+minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
@@ -7272,12 +7287,12 @@ object.getprototypeof@^1.0.3:
reflect.getprototypeof "^1.0.2"
object.hasown@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5"
- integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.1.tgz#ad1eecc60d03f49460600430d97f23882cf592a3"
+ integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==
dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.19.1"
+ define-properties "^1.1.4"
+ es-abstract "^1.19.5"
object.pick@^1.3.0:
version "1.3.0"
@@ -7787,10 +7802,10 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-pvtsutils@^1.2.1, pvtsutils@^1.2.2:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.0.tgz#3bb61f758c4c5ccd48a21a5b4943bfef643de47f"
- integrity sha512-q/BKu90CcOTSxuaoUwfAbLReg2jwlXjKpUO5htADXdDmz/XG4rIkgvA5xkc24td2SCg3vcoH9182TEceK2Zn0g==
+pvtsutils@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.2.tgz#9f8570d132cdd3c27ab7d51a2799239bf8d8d5de"
+ integrity sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==
dependencies:
tslib "^2.4.0"
@@ -7907,10 +7922,10 @@ react-blurhash@^0.1.3:
resolved "https://registry.yarnpkg.com/react-blurhash/-/react-blurhash-0.1.3.tgz#735f28f8f07fb358d7efe7e7e6dc65a7272bf89e"
integrity sha512-Q9lqbXg92NU6/2DoIl/cBM8YWL+Z4X66OiG4aT9ozOgjBwx104LHFCH5stf6aF+s0Q9Wf310Ul+dG+VXJltmPg==
-react-clientside-effect@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz#e2c4dc3c9ee109f642fac4f5b6e9bf5bcd2219a3"
- integrity sha512-2bL8qFW1TGBHozGGbVeyvnggRpMjibeZM2536AKNENLECutp2yfs44IL8Hmpn8qjFQ2K7A9PnYf3vc7aQq/cPA==
+react-clientside-effect@^1.2.6:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz#29f9b14e944a376b03fb650eed2a754dd128ea3a"
+ integrity sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==
dependencies:
"@babel/runtime" "^7.12.13"
@@ -7924,14 +7939,14 @@ react-dom@17.0.2:
scheduler "^0.20.2"
react-focus-lock@^2.5.1:
- version "2.9.0"
- resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.9.0.tgz#c148fcadb78cc86968c722b0ed7369aa45585f1c"
- integrity sha512-MF4uqKm77jkz1gn5t2BAnHeWWsDevZofrCxp2utDls0FX7pW/F1cn7Xi7pSpnqxCP1JL2okS8tcFEFIfzjJcIw==
+ version "2.9.1"
+ resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.9.1.tgz#094cfc19b4f334122c73bb0bff65d77a0c92dd16"
+ integrity sha512-pSWOQrUmiKLkffPO6BpMXN7SNKXMsuOakl652IBuALAu1esk+IcpJyM+ALcYzPTTFz1rD0R54aB9A4HuP5t1Wg==
dependencies:
"@babel/runtime" "^7.0.0"
- focus-lock "^0.11.0"
+ focus-lock "^0.11.2"
prop-types "^15.6.2"
- react-clientside-effect "^1.2.5"
+ react-clientside-effect "^1.2.6"
use-callback-ref "^1.3.0"
use-sidecar "^1.1.2"
@@ -8109,7 +8124,7 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
-regexp.prototype.flags@^1.4.1:
+regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"
integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==
@@ -8449,7 +8464,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-semver@^7.3.2, semver@^7.3.4, semver@^7.3.5:
+semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7:
version "7.3.7"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
@@ -8765,7 +8780,7 @@ string.prototype.trim@^1.2.1:
define-properties "^1.1.4"
es-abstract "^1.19.5"
-string.prototype.trimend@^1.0.4:
+string.prototype.trimend@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0"
integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==
@@ -8774,7 +8789,7 @@ string.prototype.trimend@^1.0.4:
define-properties "^1.1.4"
es-abstract "^1.19.5"
-string.prototype.trimstart@^1.0.4:
+string.prototype.trimstart@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef"
integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==
@@ -9162,7 +9177,7 @@ tslib@^1.8.1, tslib@^1.9.3:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
-tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.1, tslib@^2.4.0:
+tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
@@ -9181,7 +9196,7 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"
-tunnel@0.0.6:
+tunnel@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
@@ -9262,7 +9277,7 @@ ua-parser-js@^0.7.30:
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6"
integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==
-unbox-primitive@^1.0.1:
+unbox-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==
@@ -9515,16 +9530,16 @@ walker@^1.0.7, walker@~1.0.5:
dependencies:
makeerror "1.0.12"
-webcrypto-core@^1.7.2:
- version "1.7.3"
- resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.7.3.tgz#58252c182c5fa88fd6b607b02b5246d087dbc6e3"
- integrity sha512-8TnMtwwC/hQOyvElAOJ26lJKGgcErUG02KnKS1+QhjV4mDvQetVWU1EUEeLF8ICOrdc42+GypocyBJKRqo2kQg==
+webcrypto-core@^1.7.4:
+ version "1.7.5"
+ resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.7.5.tgz#c02104c953ca7107557f9c165d194c6316587ca4"
+ integrity sha512-gaExY2/3EHQlRNNNVSrbG2Cg94Rutl7fAaKILS1w8ZDhGxdFOaw6EbCfHIxPy9vt/xwp5o0VQAx9aySPF6hU1A==
dependencies:
- "@peculiar/asn1-schema" "^2.1.0"
+ "@peculiar/asn1-schema" "^2.1.6"
"@peculiar/json-schema" "^1.1.12"
- asn1js "^2.3.2"
- pvtsutils "^1.2.2"
- tslib "^2.3.1"
+ asn1js "^3.0.1"
+ pvtsutils "^1.3.2"
+ tslib "^2.4.0"
webidl-conversions@^3.0.0:
version "3.0.1"
@@ -9630,16 +9645,16 @@ which-module@^2.0.0:
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
which-typed-array@^1.1.7:
- version "1.1.7"
- resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.7.tgz#2761799b9a22d4b8660b3c1b40abaa7739691793"
- integrity sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.8.tgz#0cfd53401a6f334d90ed1125754a42ed663eb01f"
+ integrity sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==
dependencies:
available-typed-arrays "^1.0.5"
call-bind "^1.0.2"
- es-abstract "^1.18.5"
- foreach "^2.0.5"
+ es-abstract "^1.20.0"
+ for-each "^0.3.3"
has-tostringtag "^1.0.0"
- is-typed-array "^1.1.7"
+ is-typed-array "^1.1.9"
which@^1.2.9, which@^1.3.1:
version "1.3.1"
@@ -9800,9 +9815,9 @@ yargs@^16.2.0:
yargs-parser "^20.2.2"
yargs@^17.0.1:
- version "17.4.1"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.4.1.tgz#ebe23284207bb75cee7c408c33e722bfb27b5284"
- integrity sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==
+ version "17.5.1"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e"
+ integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==
dependencies:
cliui "^7.0.2"
escalade "^3.1.1"