diff --git a/CHANGELOG.md b/CHANGELOG.md index 94909f9df4..07e478fa02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,19 @@ -Changes in [2.2.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.2.2) (2020-03-11) +Changes in [2.2.3](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.2.3) (2020-03-17) =================================================================================================== -[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.2.1...v2.2.2) +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.2.3-rc.1...v2.2.3) + + * Upgrade JS SDK to 5.1.1 + * Add default on config setting to control call button in composer + [\#4228](https://github.com/matrix-org/matrix-react-sdk/pull/4228) + * Fix: make alternative addresses UX less confusing + [\#4226](https://github.com/matrix-org/matrix-react-sdk/pull/4226) + * Fix: best-effort to join room without canonical alias over federation from + room directory + [\#4211](https://github.com/matrix-org/matrix-react-sdk/pull/4211) + +Changes in [2.2.3-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.2.3-rc.1) (2020-03-11) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.2.1...v2.2.3-rc.1) * Update from Weblate [\#4200](https://github.com/matrix-org/matrix-react-sdk/pull/4200) diff --git a/package.json b/package.json index 26e6a6bf2e..f1dec0195c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "2.2.2", + "version": "2.2.3", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { @@ -40,15 +40,15 @@ "rethemendex": "res/css/rethemendex.sh", "clean": "rimraf lib", "build": "yarn clean && git rev-parse HEAD > git-revision.txt && yarn build:compile && yarn build:types", - "build:compile": "yarn reskindex && babel -d lib --verbose --extensions \".ts,.js\" src", - "build:types": "tsc --emitDeclarationOnly", + "build:compile": "yarn reskindex && babel -d lib --verbose --extensions \".ts,.js,.tsx\" src", + "build:types": "tsc --emitDeclarationOnly --jsx react", "start": "echo THIS IS FOR LEGACY PURPOSES ONLY. && yarn start:all", "start:all": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n build,reskindex \"yarn start:build\" \"yarn reskindex:watch\"", "start:build": "babel src -w -s -d lib --verbose --extensions \".ts,.js\"", "lint": "yarn lint:types && yarn lint:ts && yarn lint:js && yarn lint:style", "lint:js": "eslint --max-warnings 0 --ignore-path .eslintignore.errorfiles src test", "lint:ts": "tslint --project ./tsconfig.json -t stylish", - "lint:types": "tsc --noEmit", + "lint:types": "tsc --noEmit --jsx react", "lint:style": "stylelint 'res/css/**/*.scss'", "test": "jest", "test:e2e": "./test/end-to-end-tests/run.sh --riot-url http://localhost:8080" @@ -72,7 +72,6 @@ "flux": "2.1.1", "focus-visible": "^5.0.2", "fuse.js": "^2.2.0", - "gemini-scrollbar": "github:matrix-org/gemini-scrollbar#91e1e566", "gfm.css": "^1.1.1", "glob-to-regexp": "^0.4.1", "highlight.js": "^9.15.8", @@ -93,7 +92,6 @@ "react-beautiful-dnd": "^4.0.1", "react-dom": "^16.9.0", "react-focus-lock": "^2.2.1", - "react-gemini-scrollbar": "github:matrix-org/react-gemini-scrollbar#9cf17f63b7c0b0ec5f31df27da0f82f7238dc594", "resize-observer-polyfill": "^1.5.0", "sanitize-html": "^1.18.4", "text-encoding-utf-8": "^1.0.1", @@ -118,6 +116,8 @@ "@babel/preset-typescript": "^7.7.4", "@babel/register": "^7.7.4", "@peculiar/webcrypto": "^1.0.22", + "@types/classnames": "^2.2.10", + "@types/react": "16.9", "babel-eslint": "^10.0.3", "babel-jest": "^24.9.0", "chokidar": "^3.3.1", diff --git a/res/css/_common.scss b/res/css/_common.scss index e062e0bd73..ad64aced50 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -42,10 +42,15 @@ pre, code { font-size: 100% !important; } -.error, .warning { +.error, .warning, +.text-error, .text-warning { color: $warning-color; } +.text-success { + color: $accent-color; +} + b { // On Firefox, the default weight for `` is `bolder` which results in no bold // effect since we only have specific weights of our fonts available. @@ -202,37 +207,6 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { transition: opacity 0.2s ease-in-out; } -/* XXX: critical hack to GeminiScrollbar to allow them to work in FF 42 and Chrome 48. - Stop the scrollbar view from pushing out the container's overall sizing, which causes - flexbox to adapt to the new size and cause the view to keep growing. - */ -.gm-scrollbar-container .gm-scroll-view { - position: absolute; -} - -/* Expand thumbs on hoverover */ -.gm-scrollbar { - border-radius: 5px !important; -} -.gm-scrollbar.-vertical { - width: 6px; - transition: width 120ms ease-out !important; -} -.gm-scrollbar.-vertical:hover, -.gm-scrollbar.-vertical:active { - width: 8px; - transition: width 120ms ease-out !important; -} -.gm-scrollbar.-horizontal { - height: 6px; - transition: height 120ms ease-out !important; -} -.gm-scrollbar.-horizontal:hover, -.gm-scrollbar.-horizontal:active { - height: 8px; - transition: height 120ms ease-out !important; -} - // These are magic constants which are excluded from tinting, to let themes // (which only have CSS, unlike skins) tell the app what their non-tinted // colourscheme is by inspecting the stylesheet DOM. diff --git a/res/css/_components.scss b/res/css/_components.scss index bc636eb3c6..6890a1ffd1 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -65,6 +65,7 @@ @import "./views/dialogs/_GroupAddressPicker.scss"; @import "./views/dialogs/_IncomingSasDialog.scss"; @import "./views/dialogs/_InviteDialog.scss"; +@import "./views/dialogs/_KeyboardShortcutsDialog.scss"; @import "./views/dialogs/_MessageEditHistoryDialog.scss"; @import "./views/dialogs/_NewSessionReviewDialog.scss"; @import "./views/dialogs/_RoomSettingsDialog.scss"; @@ -177,7 +178,6 @@ @import "./views/rooms/_RoomTile.scss"; @import "./views/rooms/_RoomUpgradeWarningBar.scss"; @import "./views/rooms/_SearchBar.scss"; -@import "./views/rooms/_SearchableEntityList.scss"; @import "./views/rooms/_SendMessageComposer.scss"; @import "./views/rooms/_Stickers.scss"; @import "./views/rooms/_TopUnreadMessagesBar.scss"; diff --git a/res/css/structures/_GroupView.scss b/res/css/structures/_GroupView.scss index 517b8b1922..2575169664 100644 --- a/res/css/structures/_GroupView.scss +++ b/res/css/structures/_GroupView.scss @@ -180,10 +180,6 @@ limitations under the License. line-height: 2em; } -.mx_GroupView > .mx_MainSplit { - flex: 1; -} - .mx_GroupView_body { flex-grow: 1; } @@ -341,8 +337,8 @@ limitations under the License. display: none; } -.mx_GroupView_body .gm-scroll-view > * { - margin: 11px 50px 0px 68px; +.mx_GroupView_body .mx_AutoHideScrollbar_offset > * { + margin: 11px 50px 50px 68px; } .mx_GroupView_groupDesc textarea { @@ -370,7 +366,7 @@ limitations under the License. padding: 40px 20px; } -.mx_GroupView .mx_MemberInfo .gm-scroll-view > :not(.mx_MemberInfo_avatar) { +.mx_GroupView .mx_MemberInfo .mx_AutoHideScrollbar_offset > :not(.mx_MemberInfo_avatar) { padding-left: 16px; padding-right: 16px; } diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss index 4d73953cd7..25e1153fce 100644 --- a/res/css/structures/_MainSplit.scss +++ b/res/css/structures/_MainSplit.scss @@ -18,6 +18,7 @@ limitations under the License. display: flex; flex-direction: row; min-width: 0; + height: 100%; } // move hit area 5px to the right so it doesn't overlap with the timeline scrollbar diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index f2ce7e1d5c..c5a5d50068 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -76,13 +76,6 @@ limitations under the License. flex: 1 1 0; min-width: 0; - /* Experimental fix for https://github.com/vector-im/vector-web/issues/947 - and https://github.com/vector-im/vector-web/issues/946. - Empirically this stops the MessagePanel's width exploding outwards when - gemini is in 'prevented' mode - */ - overflow-x: auto; - /* To fix https://github.com/vector-im/riot-web/issues/3298 where Safari needed height 100% all the way down to the HomePage. Height does not have to be auto, empirically. diff --git a/res/css/structures/_MyGroups.scss b/res/css/structures/_MyGroups.scss index d25789ab94..36150c33a5 100644 --- a/res/css/structures/_MyGroups.scss +++ b/res/css/structures/_MyGroups.scss @@ -67,9 +67,6 @@ limitations under the License. } } - - - .mx_MyGroups_headerCard_header { font-weight: bold; margin-bottom: 10px; @@ -98,6 +95,11 @@ limitations under the License. display: flex; flex-direction: column; + overflow-y: auto; +} + +.mx_MyGroups_scrollable { + overflow-y: inherit; } .mx_MyGroups_placeholder { diff --git a/res/css/structures/_RoomDirectory.scss b/res/css/structures/_RoomDirectory.scss index 5ae8df7176..f3a7b0e243 100644 --- a/res/css/structures/_RoomDirectory.scss +++ b/res/css/structures/_RoomDirectory.scss @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2020 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. @@ -45,9 +46,8 @@ limitations under the License. } .mx_RoomDirectory_listheader { - display: flex; - margin-top: 12px; - margin-bottom: 12px; + display: block; + margin-top: 13px; } .mx_RoomDirectory_searchbox { @@ -64,7 +64,7 @@ limitations under the License. } .mx_RoomDirectory_table { - font-size: 14px; + font-size: 12px; color: $primary-fg-color; width: 100%; text-align: left; @@ -112,6 +112,7 @@ limitations under the License. .mx_RoomDirectory_name { display: inline-block; + font-size: 18px; font-weight: 600; } @@ -148,8 +149,8 @@ limitations under the License. padding: 0; } -.mx_RoomDirectory p { - font-size: 14px; +.mx_RoomDirectory > span { + font-size: 15px; margin-top: 0; .mx_AccessibleButton { diff --git a/res/css/structures/_TagPanel.scss b/res/css/structures/_TagPanel.scss index dddd2e324c..472831c0d9 100644 --- a/res/css/structures/_TagPanel.scss +++ b/res/css/structures/_TagPanel.scss @@ -23,6 +23,7 @@ limitations under the License. flex-direction: column; align-items: center; justify-content: space-between; + min-height: 0; } .mx_TagPanel_items_selected { @@ -57,6 +58,7 @@ limitations under the License. .mx_TagPanel .mx_TagPanel_scroller { flex-grow: 1; + width: 100%; } .mx_TagPanel .mx_TagPanel_tagTileContainer { diff --git a/res/css/structures/auth/_CompleteSecurity.scss b/res/css/structures/auth/_CompleteSecurity.scss index 2bf51d9574..601492d43c 100644 --- a/res/css/structures/auth/_CompleteSecurity.scss +++ b/res/css/structures/auth/_CompleteSecurity.scss @@ -37,6 +37,10 @@ limitations under the License. font-size: 15px; } +.mx_CompleteSecurity_waiting { + color: $notice-secondary-color; +} + .mx_CompleteSecurity_actionRow { display: flex; justify-content: flex-end; diff --git a/res/css/views/dialogs/_KeyboardShortcutsDialog.scss b/res/css/views/dialogs/_KeyboardShortcutsDialog.scss new file mode 100644 index 0000000000..f529b11059 --- /dev/null +++ b/res/css/views/dialogs/_KeyboardShortcutsDialog.scss @@ -0,0 +1,65 @@ +/* +Copyright 2020 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_KeyboardShortcutsDialog { + display: flex; + flex-wrap: wrap; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + flex-direction: column; + margin-bottom: -50px; + max-height: 700px; // XXX: this may need adjusting when adding new shortcuts + + .mx_KeyboardShortcutsDialog_category { + width: 33.3333%; // 3 columns + margin: 0 0 40px; + + & > div { + padding-left: 5px; + } + } + + h3 { + margin: 0 0 10px; + } + + h5 { + margin: 15px 0 5px; + font-weight: normal; + } + + kbd { + padding: 5px; + border-radius: 4px; + background-color: $reaction-row-button-bg-color; + margin-right: 5px; + min-width: 20px; + text-align: center; + display: inline-block; + border: 1px solid $kbd-border-color; + box-shadow: 0 2px $kbd-border-color; + margin-bottom: 4px; + text-transform: capitalize; + + & + kbd { + margin-left: 5px; + } + } + + .mx_KeyboardShortcutsDialog_inline div { + display: inline; + } +} diff --git a/res/css/views/dialogs/_UnknownDeviceDialog.scss b/res/css/views/dialogs/_UnknownDeviceDialog.scss index 02e0fb1fe5..2b0f8dceca 100644 --- a/res/css/views/dialogs/_UnknownDeviceDialog.scss +++ b/res/css/views/dialogs/_UnknownDeviceDialog.scss @@ -14,14 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -// CSS voodoo to support a gemini-scrollbar for the contents of the dialog -.mx_Dialog_unknownDevice .mx_Dialog { - // ideally we'd shrink the height to fit when needed, but in practice this - // is a pain in the ass. plus might as well make the dialog big given how - // important it is. - height: 100%; -} - .mx_UnknownDeviceDialog { height: 100%; display: flex; @@ -44,6 +36,7 @@ limitations under the License. .mx_UnknownDeviceDialog .mx_Dialog_content { margin-bottom: 24px; + overflow-y: scroll; } .mx_UnknownDeviceDialog_deviceList > li { diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index d402f6c48f..106392f880 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -1,5 +1,5 @@ /* -Copyright 2015, 2016 OpenMarket Ltd +Copyright 2020 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,70 +15,149 @@ limitations under the License. */ .mx_NetworkDropdown { + height: 32px; position: relative; -} + width: max-content; + padding-right: 32px; + margin-left: auto; + margin-right: 9px; + margin-top: 12px; -.mx_NetworkDropdown_input { - position: relative; - border-radius: 3px; - border: 1px solid $strong-input-border-color; - font-weight: 300; - font-size: 13px; - user-select: none; -} - -.mx_NetworkDropdown_arrow { - border-color: $primary-fg-color transparent transparent; - border-style: solid; - border-width: 5px 5px 0; - display: block; - height: 0; - position: absolute; - right: 10px; - top: 16px; - width: 0; -} - -.mx_NetworkDropdown_networkoption { - height: 37px; - line-height: 37px; - padding-left: 8px; - padding-right: 8px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.mx_NetworkDropdown_networkoption img { - margin: 5px; - width: 25px; - vertical-align: middle; -} - -input.mx_NetworkDropdown_networkoption, input.mx_NetworkDropdown_networkoption:focus { - border: 0; - padding-top: 0; - padding-bottom: 0; + .mx_AccessibleButton { + width: max-content; + } } .mx_NetworkDropdown_menu { - position: absolute; - left: -1px; - right: -1px; - top: 100%; - z-index: 2; + min-width: 204px; margin: 0; - padding: 0px; - border-radius: 3px; - border: 1px solid $accent-color; + box-sizing: border-box; + border-radius: 4px; + border: 1px solid $dialog-close-fg-color; background-color: $primary-bg-color; } -.mx_NetworkDropdown_menu .mx_NetworkDropdown_networkoption:hover { - background-color: $focus-bg-color; -} - .mx_NetworkDropdown_menu_network { font-weight: bold; } +.mx_NetworkDropdown_server { + padding: 12px 0; + border-bottom: 1px solid $input-darker-fg-color; + + .mx_NetworkDropdown_server_title { + padding: 0 10px; + font-size: 15px; + font-weight: 600; + line-height: 20px; + margin-bottom: 4px; + + // remove server button + .mx_AccessibleButton { + position: absolute; + display: inline; + right: 12px; + height: 16px; + width: 16px; + margin-top: 4px; + + &::after { + content: ""; + position: absolute; + width: 16px; + height: 16px; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/feather-customised/x.svg'); + background-color: $notice-primary-color; + } + } + } + + .mx_NetworkDropdown_server_subtitle { + padding: 0 10px; + font-size: 10px; + line-height: 14px; + margin-top: -4px; + margin-bottom: 4px; + color: $muted-fg-color; + } + + .mx_NetworkDropdown_server_network { + font-size: 12px; + line-height: 16px; + padding: 4px 10px; + cursor: pointer; + position: relative; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + + &[aria-checked=true]::after { + content: ""; + position: absolute; + width: 16px; + height: 16px; + right: 10px; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/feather-customised/check.svg'); + background-color: $input-valid-border-color; + } + } +} + +.mx_NetworkDropdown_server_add, +.mx_NetworkDropdown_server_network { + &:hover { + background-color: $header-panel-bg-color; + } +} + +.mx_NetworkDropdown_server_add { + padding: 16px 10px 16px 32px; + position: relative; + border-radius: 0 0 4px 4px; + + &::before { + content: ""; + position: absolute; + width: 16px; + height: 16px; + left: 7px; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/feather-customised/plus.svg'); + background-color: $muted-fg-color; + } +} + +.mx_NetworkDropdown_handle { + position: relative; + + &::after { + content: ""; + position: absolute; + width: 24px; + height: 24px; + right: -28px; // - (24 + 4) + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); + background-color: $primary-fg-color; + } + + .mx_NetworkDropdown_handle_server { + color: $muted-fg-color; + font-size: 12px; + } +} + +.mx_NetworkDropdown_dialog .mx_Dialog { + width: 45vw; +} diff --git a/res/css/views/elements/_DirectorySearchBox.scss b/res/css/views/elements/_DirectorySearchBox.scss index ef944f6fa0..75ef3fbabd 100644 --- a/res/css/views/elements/_DirectorySearchBox.scss +++ b/res/css/views/elements/_DirectorySearchBox.scss @@ -18,7 +18,6 @@ limitations under the License. display: flex; padding-left: 9px; padding-right: 9px; - margin: 0 5px 0 0 !important; } .mx_DirectorySearchBox_joinButton { diff --git a/res/css/views/elements/_EditableItemList.scss b/res/css/views/elements/_EditableItemList.scss index 51fa4c4423..ef60f006cc 100644 --- a/res/css/views/elements/_EditableItemList.scss +++ b/res/css/views/elements/_EditableItemList.scss @@ -20,14 +20,21 @@ limitations under the License. } .mx_EditableItem { + display: flex; margin-bottom: 5px; - margin-left: 15px; } .mx_EditableItem_delete { + order: 3; margin-right: 5px; cursor: pointer; vertical-align: middle; + width: 14px; + height: 14px; + mask-image: url('$(res)/img/feather-customised/cancel.svg'); + mask-repeat: no-repeat; + background-color: $warning-color; + mask-size: 100%; } .mx_EditableItem_email { @@ -36,12 +43,19 @@ limitations under the License. .mx_EditableItem_promptText { margin-right: 10px; + order: 2; } .mx_EditableItem_confirmBtn { margin-right: 5px; } +.mx_EditableItem_item { + flex: auto 1 0; + order: 1; +} + .mx_EditableItemList_label { margin-bottom: 5px; } + diff --git a/res/css/views/room_settings/_AliasSettings.scss b/res/css/views/room_settings/_AliasSettings.scss index 294902a1f0..f8d92e7828 100644 --- a/res/css/views/room_settings/_AliasSettings.scss +++ b/res/css/views/room_settings/_AliasSettings.scss @@ -27,6 +27,20 @@ limitations under the License. box-shadow: none; } -.mx_AliasSettings summary { - cursor: pointer; +.mx_AliasSettings { + summary { + cursor: pointer; + color: $accent-color; + font-weight: 600; + list-style: none; + + // list-style doesn't do it for webkit + &::-webkit-details-marker { + display: none; + } + } + + .mx_AliasSettings_localAliasHeader { + margin-top: 35px; + } } diff --git a/res/css/views/rooms/_RoomPreviewBar.scss b/res/css/views/rooms/_RoomPreviewBar.scss index 85b6916226..b3f6a12103 100644 --- a/res/css/views/rooms/_RoomPreviewBar.scss +++ b/res/css/views/rooms/_RoomPreviewBar.scss @@ -25,6 +25,9 @@ limitations under the License. h3 { font-size: 18px; font-weight: 600; + // break-word, with fallback to break-all, which is wider supported + word-break: break-all; + word-break: break-word; &.mx_RoomPreviewBar_spinnerTitle { display: flex; diff --git a/res/css/views/rooms/_SearchableEntityList.scss b/res/css/views/rooms/_SearchableEntityList.scss deleted file mode 100644 index 37a663123d..0000000000 --- a/res/css/views/rooms/_SearchableEntityList.scss +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright 2016 OpenMarket Ltd - -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_SearchableEntityList { - display: flex; - - flex-direction: column; -} - -.mx_SearchableEntityList_query { - font-family: $font-family; - border-radius: 3px; - border: 1px solid $input-border-color; - padding: 9px; - color: $primary-fg-color; - background-color: $primary-bg-color; - margin-left: 3px; - font-size: 15px; - margin-bottom: 8px; - width: 189px; -} - -.mx_SearchableEntityList_query::-moz-placeholder { - color: $primary-fg-color; - opacity: 0.5; - font-size: 12px; -} - -.mx_SearchableEntityList_query::-webkit-input-placeholder { - color: $primary-fg-color; - opacity: 0.5; - font-size: 12px; -} - -.mx_SearchableEntityList_listWrapper { - flex: 1; - - overflow-y: auto; -} - -.mx_SearchableEntityList_list { - display: table; - table-layout: fixed; - width: 100%; -} - -.mx_SearchableEntityList_list .mx_EntityTile_chevron { - display: none; -} - -.mx_SearchableEntityList_hrWrapper { - width: 100%; - flex: 0 0 auto; -} - -.mx_SearchableEntityList hr { - height: 1px; - border: 0px; - color: $primary-fg-color; - background-color: $primary-fg-color; - margin-right: 15px; - margin-top: 11px; - margin-bottom: 11px; -} diff --git a/res/css/views/settings/tabs/_SettingsTab.scss b/res/css/views/settings/tabs/_SettingsTab.scss index 9727946893..01a1d94956 100644 --- a/res/css/views/settings/tabs/_SettingsTab.scss +++ b/res/css/views/settings/tabs/_SettingsTab.scss @@ -47,11 +47,15 @@ limitations under the License. .mx_SettingsTab_section { margin-bottom: 24px; -} -.mx_SettingsTab_section .mx_SettingsFlag { - margin-right: 100px; - margin-bottom: 10px; + .mx_SettingsFlag { + margin-right: 100px; + margin-bottom: 10px; + } + + &.mx_SettingsTab_subsectionText .mx_SettingsFlag { + margin-right: 0px !important; + } } .mx_SettingsTab_section .mx_SettingsFlag .mx_SettingsFlag_label { diff --git a/res/img/feather-customised/chevron-down.svg b/res/img/feather-customised/chevron-down.svg new file mode 100644 index 0000000000..bcb185ede7 --- /dev/null +++ b/res/img/feather-customised/chevron-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index a3515a9d99..bfa2272283 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -165,6 +165,8 @@ $reaction-row-button-hover-border-color: $header-panel-text-primary-color; $reaction-row-button-selected-bg-color: #1f6954; $reaction-row-button-selected-border-color: $accent-color; +$kbd-border-color: #000000; + $tooltip-timeline-bg-color: $tagpanel-bg-color; $tooltip-timeline-fg-color: #ffffff; @@ -219,10 +221,6 @@ $user-tile-hover-bg-color: $header-panel-bg-color; filter: invert(1); } -.gm-scrollbar .thumb { - filter: invert(1); -} - // markdown overrides: .mx_EventTile_content .markdown-body pre:hover { border-color: #808080 !important; // inverted due to rules below diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 626ccb2e13..9bdd712e07 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -290,6 +290,8 @@ $reaction-row-button-hover-border-color: $focus-bg-color; $reaction-row-button-selected-bg-color: #e9fff9; $reaction-row-button-selected-border-color: $accent-color; +$kbd-border-color: $reaction-row-button-border-color; + $tooltip-timeline-bg-color: $tagpanel-bg-color; $tooltip-timeline-fg-color: #ffffff; diff --git a/scripts/ci/end-to-end-tests.sh b/scripts/ci/end-to-end-tests.sh index 9bdb512940..2f907dffa2 100755 --- a/scripts/ci/end-to-end-tests.sh +++ b/scripts/ci/end-to-end-tests.sh @@ -6,16 +6,8 @@ set -ev -upload_logs() { - echo "--- Uploading logs" - buildkite-agent artifact upload "logs/**/*;synapse/installations/consent/homeserver.log" -} - handle_error() { EXIT_CODE=$? - if [ $TESTS_STARTED -eq 1 ]; then - upload_logs - fi exit $EXIT_CODE } diff --git a/scripts/gen-i18n.js b/scripts/gen-i18n.js index 3d3d5af116..a4d53aea2f 100755 --- a/scripts/gen-i18n.js +++ b/scripts/gen-i18n.js @@ -237,7 +237,7 @@ const walkOpts = { const fullPath = path.join(root, fileStats.name); let trs; - if (fileStats.name.endsWith('.js')) { + if (fileStats.name.endsWith('.js') || fileStats.name.endsWith('.tsx')) { trs = getTranslationsJs(fullPath); } else if (fileStats.name.endsWith('.html')) { trs = getTranslationsOther(fullPath); diff --git a/scripts/reskindex.js b/scripts/reskindex.js index 81ab111f46..9fb0e1a7c0 100755 --- a/scripts/reskindex.js +++ b/scripts/reskindex.js @@ -8,11 +8,14 @@ var chokidar = require('chokidar'); var componentIndex = path.join('src', 'component-index.js'); var componentIndexTmp = componentIndex+".tmp"; var componentsDir = path.join('src', 'components'); -var componentGlob = '**/*.js'; +var componentJsGlob = '**/*.js'; +var componentTsGlob = '**/*.tsx'; var prevFiles = []; function reskindex() { - var files = glob.sync(componentGlob, {cwd: componentsDir}).sort(); + var jsFiles = glob.sync(componentJsGlob, {cwd: componentsDir}).sort(); + var tsFiles = glob.sync(componentTsGlob, {cwd: componentsDir}).sort(); + var files = [...tsFiles, ...jsFiles]; if (!filesHaveChanged(files, prevFiles)) { return; } @@ -36,7 +39,7 @@ function reskindex() { strm.write("let components = {};\n"); for (var i = 0; i < files.length; ++i) { - var file = files[i].replace('.js', ''); + var file = files[i].replace('.js', '').replace('.tsx', ''); var moduleName = (file.replace(/\//g, '.')); var importName = moduleName.replace(/\./g, "$"); @@ -79,7 +82,7 @@ if (!args.w) { } var watchDebouncer = null; -chokidar.watch(path.join(componentsDir, componentGlob)).on('all', (event, path) => { +chokidar.watch(path.join(componentsDir, componentJsGlob)).on('all', (event, path) => { if (path === componentIndex) return; if (watchDebouncer) clearTimeout(watchDebouncer); watchDebouncer = setTimeout(reskindex, 1000); diff --git a/src/CallHandler.js b/src/CallHandler.js index 1551b57313..2988e90f40 100644 --- a/src/CallHandler.js +++ b/src/CallHandler.js @@ -143,7 +143,7 @@ function _setCallListeners(call) { "if you proceed without verifying them, it will be "+ "possible for someone to eavesdrop on your call.", ), - button: _t('Review Devices'), + button: _t('Review Sessions'), onFinished: function(confirmed) { if (confirmed) { const room = MatrixClientPeg.get().getRoom(call.roomId); diff --git a/src/DeviceListener.js b/src/DeviceListener.js index 4e7bc8470d..6a506db496 100644 --- a/src/DeviceListener.js +++ b/src/DeviceListener.js @@ -99,9 +99,13 @@ export default class DeviceListener { } async _recheck() { - if (!SettingsStore.isFeatureEnabled("feature_cross_signing")) return; const cli = MatrixClientPeg.get(); + if ( + !SettingsStore.isFeatureEnabled("feature_cross_signing") || + !await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing") + ) return; + if (!cli.isCryptoEnabled()) return; if (!cli.getCrossSigningId()) { if (this._dismissedThisDeviceToast) { diff --git a/src/Keyboard.js b/src/Keyboard.ts similarity index 92% rename from src/Keyboard.js rename to src/Keyboard.ts index 478d75acc1..f5cf0a5492 100644 --- a/src/Keyboard.js +++ b/src/Keyboard.ts @@ -40,6 +40,7 @@ export const Key = { GREATER_THAN: ">", BACKTICK: "`", SPACE: " ", + SLASH: "/", A: "a", B: "b", C: "c", @@ -68,8 +69,9 @@ export const Key = { Z: "z", }; +export const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; + export function isOnlyCtrlOrCmdKeyEvent(ev) { - const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; if (isMac) { return ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey; } else { @@ -78,7 +80,6 @@ export function isOnlyCtrlOrCmdKeyEvent(ev) { } export function isOnlyCtrlOrCmdIgnoreShiftKeyEvent(ev) { - const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; if (isMac) { return ev.metaKey && !ev.altKey && !ev.ctrlKey; } else { diff --git a/src/accessibility/KeyboardShortcuts.tsx b/src/accessibility/KeyboardShortcuts.tsx new file mode 100644 index 0000000000..618ed4755a --- /dev/null +++ b/src/accessibility/KeyboardShortcuts.tsx @@ -0,0 +1,315 @@ +/* +Copyright 2020 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 * as React from "react"; +import classNames from "classnames"; + +import * as sdk from "../index"; +import Modal from "../Modal"; +import { _t, _td } from "../languageHandler"; +import {isMac, Key} from "../Keyboard"; + +// TS: once languageHandler is TS we can probably inline this into the enum +_td("Navigation"); +_td("Calls"); +_td("Composer"); +_td("Room List"); +_td("Autocomplete"); + +export enum Categories { + NAVIGATION = "Navigation", + CALLS = "Calls", + COMPOSER = "Composer", + ROOM_LIST = "Room List", + AUTOCOMPLETE = "Autocomplete", +} + +// TS: once languageHandler is TS we can probably inline this into the enum +_td("Alt"); +_td("Alt Gr"); +_td("Shift"); +_td("Super"); +_td("Ctrl"); + +export enum Modifiers { + ALT = "Alt", // Option on Mac and displayed as an Icon + ALT_GR = "Alt Gr", + SHIFT = "Shift", + SUPER = "Super", // should this be "Windows"? + // Instead of using below, consider CMD_OR_CTRL + COMMAND = "Command", // This gets displayed as an Icon + CONTROL = "Ctrl", +} + +// Meta-modifier: isMac ? CMD : CONTROL +export const CMD_OR_CTRL = isMac ? Modifiers.COMMAND : Modifiers.CONTROL; + +interface IKeybind { + modifiers?: Modifiers[]; + key: string; // TS: fix this once Key is an enum +} + +interface IShortcut { + keybinds: IKeybind[]; + description: string; +} + +const shortcuts: Record = { + [Categories.COMPOSER]: [ + { + keybinds: [{ + modifiers: [CMD_OR_CTRL], + key: Key.B, + }], + description: _td("Toggle Bold"), + }, { + keybinds: [{ + modifiers: [CMD_OR_CTRL], + key: Key.I, + }], + description: _td("Toggle Italics"), + }, { + keybinds: [{ + modifiers: [CMD_OR_CTRL], + key: Key.GREATER_THAN, + }], + description: _td("Toggle Quote"), + }, { + keybinds: [{ + modifiers: [CMD_OR_CTRL], + key: Key.M, + }], + description: _td("Toggle Markdown"), + }, { + keybinds: [{ + modifiers: [Modifiers.SHIFT], + key: Key.ENTER, + }], + description: _td("New line"), + }, { + keybinds: [{ + key: Key.ARROW_UP, + }, { + key: Key.ARROW_DOWN, + }], + description: _td("Navigate recent messages to edit"), + }, { + keybinds: [{ + modifiers: [CMD_OR_CTRL], + key: Key.HOME, + }, { + modifiers: [CMD_OR_CTRL], + key: Key.END, + }], + description: _td("Jump to start/end of the composer"), + }, + ], + + [Categories.CALLS]: [ + { + keybinds: [{ + modifiers: [CMD_OR_CTRL], + key: Key.D, + }], + description: _td("Toggle microphone mute"), + }, { + keybinds: [{ + modifiers: [CMD_OR_CTRL], + key: Key.E, + }], + description: _td("Toggle video on/off"), + }, + ], + + [Categories.ROOM_LIST]: [ + { + keybinds: [{ + modifiers: [CMD_OR_CTRL], + key: Key.K, + }], + description: _td("Jump to room search"), + }, { + keybinds: [{ + key: Key.ARROW_UP, + }, { + key: Key.ARROW_DOWN, + }], + description: _td("Navigate up/down in the room list"), + }, { + keybinds: [{ + key: Key.ENTER, + }], + description: _td("Select room from the room list"), + }, { + keybinds: [{ + key: Key.ARROW_LEFT, + }], + description: _td("Collapse room list section"), + }, { + keybinds: [{ + key: Key.ARROW_RIGHT, + }], + description: _td("Expand room list section"), + }, { + keybinds: [{ + key: Key.ESCAPE, + }], + description: _td("Clear room list filter field"), + }, + ], + + [Categories.NAVIGATION]: [ + { + keybinds: [{ + key: Key.PAGE_UP, + }, { + key: Key.PAGE_DOWN, + }], + description: _td("Scroll up/down in the timeline"), + }, { + keybinds: [{ + modifiers: [CMD_OR_CTRL], + key: Key.BACKTICK, + }], + description: _td("Toggle the top left menu"), + }, { + keybinds: [{ + key: Key.ESCAPE, + }], + description: _td("Close dialog or context menu"), + }, { + keybinds: [{ + key: Key.ENTER, + }, { + key: Key.SPACE, + }], + description: _td("Activate selected button"), + }, { + keybinds: [{ + modifiers: [CMD_OR_CTRL], + key: Key.SLASH, + }], + description: _td("Toggle this dialog"), + }, + ], + + [Categories.AUTOCOMPLETE]: [ + { + keybinds: [{ + key: Key.ARROW_UP, + }, { + key: Key.ARROW_DOWN, + }], + description: _td("Move autocomplete selection up/down"), + }, { + keybinds: [{ + key: Key.ESCAPE, + }], + description: _td("Cancel autocomplete"), + }, + ], +}; + +interface IModal { + close: () => void; + finished: Promise; +} + +const modifierIcon: Record = { + [Modifiers.COMMAND]: "⌘", +}; + +if (isMac) { + modifierIcon[Modifiers.ALT] = "⌥"; +} + +const alternateKeyName: Record = { + [Key.PAGE_UP]: _td("Page Up"), + [Key.PAGE_DOWN]: _td("Page Down"), + [Key.ESCAPE]: _td("Esc"), + [Key.ENTER]: _td("Enter"), + [Key.SPACE]: _td("Space"), + [Key.HOME]: _td("Home"), + [Key.END]: _td("End"), +}; +const keyIcon: Record = { + [Key.ARROW_UP]: "↑", + [Key.ARROW_DOWN]: "↓", + [Key.ARROW_LEFT]: "←", + [Key.ARROW_RIGHT]: "→", +}; + +const Shortcut: React.FC<{ + shortcut: IShortcut; +}> = ({shortcut}) => { + const classes = classNames({ + "mx_KeyboardShortcutsDialog_inline": shortcut.keybinds.every(k => !k.modifiers || k.modifiers.length === 0), + }); + + return
+
{ _t(shortcut.description) }
+ { shortcut.keybinds.map(s => { + let text = s.key; + if (alternateKeyName[s.key]) { + text = _t(alternateKeyName[s.key]); + } else if (keyIcon[s.key]) { + text = keyIcon[s.key]; + } + + return
+ { s.modifiers && s.modifiers.map(m => { + return + { modifierIcon[m] || _t(m) }+ + ; + }) } + { text } +
; + }) } +
; +}; + +let activeModal: IModal = null; +export const toggleDialog = () => { + if (activeModal) { + activeModal.close(); + activeModal = null; + return; + } + + const sections = Object.entries(shortcuts).map(([category, list]) => { + return
+

{_t(category)}

+
{list.map(shortcut => )}
+
; + }); + + const InfoDialog = sdk.getComponent('dialogs.InfoDialog'); + activeModal = Modal.createTrackedDialog("Keyboard Shortcuts", "", InfoDialog, { + className: "mx_KeyboardShortcutsDialog", + title: _t("Keyboard Shortcuts"), + description: sections, + hasCloseButton: true, + onKeyDown: (ev) => { + if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey && ev.key === Key.SLASH) { // Ctrl + / + ev.stopPropagation(); + activeModal.close(); + } + }, + onFinished: () => { + activeModal = null; + }, + }); +}; diff --git a/src/components/structures/ContextMenu.js b/src/components/structures/ContextMenu.js index 898991f4f2..b4647a6c30 100644 --- a/src/components/structures/ContextMenu.js +++ b/src/components/structures/ContextMenu.js @@ -350,7 +350,7 @@ export const ContextMenuButton = ({ label, isExpanded, children, ...props }) => }; ContextMenuButton.propTypes = { ...AccessibleButton.propTypes, - label: PropTypes.string.isRequired, + label: PropTypes.string, isExpanded: PropTypes.bool.isRequired, // whether or not the context menu is currently open }; @@ -377,7 +377,6 @@ export const MenuGroup = ({children, label, ...props}) => { ; }; MenuGroup.propTypes = { - ...AccessibleButton.propTypes, label: PropTypes.string.isRequired, className: PropTypes.string, // optional }; diff --git a/src/components/structures/EmbeddedPage.js b/src/components/structures/EmbeddedPage.js index 6d734c3838..f854dc955f 100644 --- a/src/components/structures/EmbeddedPage.js +++ b/src/components/structures/EmbeddedPage.js @@ -23,11 +23,11 @@ import PropTypes from 'prop-types'; import request from 'browser-request'; import { _t } from '../../languageHandler'; import sanitizeHtml from 'sanitize-html'; -import * as sdk from '../../index'; import dis from '../../dispatcher'; import {MatrixClientPeg} from '../../MatrixClientPeg'; import classnames from 'classnames'; import MatrixClientContext from "../../contexts/MatrixClientContext"; +import AutoHideScrollbar from "./AutoHideScrollbar"; export default class EmbeddedPage extends React.PureComponent { static propTypes = { @@ -117,10 +117,9 @@ export default class EmbeddedPage extends React.PureComponent { ; if (this.props.scrollbar) { - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); - return + return {content} - ; + ; } else { return
{content} diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index af90fbbe83..0d10dd6d8f 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -39,6 +39,7 @@ import {makeGroupPermalink, makeUserPermalink} from "../../utils/permalinks/Perm import {Group} from "matrix-js-sdk"; import {allSettled, sleep} from "../../utils/promise"; import RightPanelStore from "../../stores/RightPanelStore"; +import AutoHideScrollbar from "./AutoHideScrollbar"; const LONG_DESC_PLACEHOLDER = _td( `

HTML for your community's page

@@ -554,10 +555,6 @@ export default createReactClass({ GROUP_JOINPOLICY_INVITE, }, }); - dis.dispatch({ - action: 'panel_disable', - sideDisabled: true, - }); }, _onShareClick: function() { @@ -1173,7 +1170,6 @@ export default createReactClass({ render: function() { const GroupAvatar = sdk.getComponent("avatars.GroupAvatar"); const Spinner = sdk.getComponent("elements.Spinner"); - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); if (this.state.summaryLoading && this.state.error === null || this.state.saving) { return ; @@ -1332,10 +1328,10 @@ export default createReactClass({
- + { this._getMembershipSection() } { this._getGroupSection() } - + ); diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 20217548b7..576ae2b276 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -39,6 +39,7 @@ import RoomListActions from '../../actions/RoomListActions'; import ResizeHandle from '../views/elements/ResizeHandle'; import {Resizer, CollapseDistributor} from '../../resizer'; import MatrixClientContext from "../../contexts/MatrixClientContext"; +import * as KeyboardShortcuts from "../../accessibility/KeyboardShortcuts"; // We need to fetch each pinned message individually (if we don't already have it) // so each pinned message may trigger a request. Limit the number per room for sanity. // NB. this is just for server notices rather than pinned messages in general. @@ -337,13 +338,13 @@ const LoggedInView = createReactClass({ let handled = false; const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev); - const hasModifier = ev.altKey || ev.ctrlKey || ev.metaKey || ev.shiftKey || - ev.key === Key.ALT || ev.key === Key.CONTROL || ev.key === Key.META || ev.key === Key.SHIFT; + const hasModifier = ev.altKey || ev.ctrlKey || ev.metaKey || ev.shiftKey; + const isModifier = ev.key === Key.ALT || ev.key === Key.CONTROL || ev.key === Key.META || ev.key === Key.SHIFT; switch (ev.key) { case Key.PAGE_UP: case Key.PAGE_DOWN: - if (!hasModifier) { + if (!hasModifier && !isModifier) { this._onScrollKeyPressed(ev); handled = true; } @@ -365,8 +366,6 @@ const LoggedInView = createReactClass({ } break; case Key.BACKTICK: - if (ev.key !== "`") break; - // Ideally this would be CTRL+P for "Profile", but that's // taken by the print dialog. CTRL+I for "Information" // was previously chosen but conflicted with italics in @@ -379,12 +378,22 @@ const LoggedInView = createReactClass({ handled = true; } break; + + case Key.SLASH: + if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) { + KeyboardShortcuts.toggleDialog(); + handled = true; + } + break; } if (handled) { ev.stopPropagation(); ev.preventDefault(); - } else if (!hasModifier) { + } else if (!isModifier && !ev.altKey && !ev.ctrlKey && !ev.metaKey) { + // The above condition is crafted to _allow_ characters with Shift + // already pressed (but not the Shift key down itself). + const isClickShortcut = ev.target !== document.body && (ev.key === Key.SPACE || ev.key === Key.ENTER); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index a0b9a8fe57..3e59112a63 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -600,9 +600,8 @@ export default createReactClass({ break; case 'view_room_directory': { const RoomDirectory = sdk.getComponent("structures.RoomDirectory"); - Modal.createTrackedDialog('Room directory', '', RoomDirectory, { - config: this.props.config, - }, 'mx_RoomDirectory_dialogWrapper'); + Modal.createTrackedDialog('Room directory', '', RoomDirectory, {}, + 'mx_RoomDirectory_dialogWrapper', false, true); // View the welcome or home page if we need something to look at this._viewSomethingBehindModal(); @@ -1911,7 +1910,10 @@ export default createReactClass({ // secret storage. SettingsStore.setFeatureEnabled("feature_cross_signing", true); this.setStateForNewView({ view: VIEWS.COMPLETE_SECURITY }); - } else if (SettingsStore.isFeatureEnabled("feature_cross_signing")) { + } else if ( + SettingsStore.isFeatureEnabled("feature_cross_signing") && + await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing") + ) { // This will only work if the feature is set to 'enable' in the config, // since it's too early in the lifecycle for users to have turned the // labs flag on. diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js index b26ab5ff70..f1209b7b9e 100644 --- a/src/components/structures/MyGroups.js +++ b/src/components/structures/MyGroups.js @@ -22,6 +22,7 @@ import { _t } from '../../languageHandler'; import dis from '../../dispatcher'; import AccessibleButton from '../views/elements/AccessibleButton'; import MatrixClientContext from "../../contexts/MatrixClientContext"; +import AutoHideScrollbar from "./AutoHideScrollbar"; export default createReactClass({ displayName: 'MyGroups', @@ -62,8 +63,6 @@ export default createReactClass({ const Loader = sdk.getComponent("elements.Spinner"); const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader'); const GroupTile = sdk.getComponent("groups.GroupTile"); - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); - let content; let contentHeader; @@ -74,7 +73,7 @@ export default createReactClass({ }); contentHeader = groupNodes.length > 0 ?

{ _t('Your Communities') }

:
; content = groupNodes.length > 0 ? - +

{ _t( @@ -93,7 +92,7 @@ export default createReactClass({

{ groupNodes }
- : + :
{ _t( "You're not currently a member of any communities.", diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index dd089a9776..664aaaf21f 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -28,6 +28,7 @@ import { _t } from '../../languageHandler'; import { instanceForInstanceId, protocolNameForInstanceId } from '../../utils/DirectoryUtils'; import Analytics from '../../Analytics'; import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo"; +import {ALL_ROOMS} from "../views/directory/NetworkDropdown"; const MAX_NAME_LENGTH = 80; const MAX_TOPIC_LENGTH = 160; @@ -40,25 +41,17 @@ export default createReactClass({ displayName: 'RoomDirectory', propTypes: { - config: PropTypes.object, onFinished: PropTypes.func.isRequired, }, - getDefaultProps: function() { - return { - config: {}, - }; - }, - getInitialState: function() { return { publicRooms: [], loading: true, protocolsLoading: true, error: null, - instanceId: null, - includeAll: false, - roomServer: null, + instanceId: undefined, + roomServer: MatrixClientPeg.getHomeserverName(), filterString: null, }; }, @@ -98,6 +91,10 @@ export default createReactClass({ }); }, + componentDidMount: function() { + this.refreshRoomList(); + }, + componentWillUnmount: function() { if (this.filterTimeout) { clearTimeout(this.filterTimeout); @@ -130,10 +127,10 @@ export default createReactClass({ if (my_server != MatrixClientPeg.getHomeserverName()) { opts.server = my_server; } - if (this.state.instanceId) { - opts.third_party_instance_id = this.state.instanceId; - } else if (this.state.includeAll) { + if (this.state.instanceId === ALL_ROOMS) { opts.include_all_networks = true; + } else if (this.state.instanceId) { + opts.third_party_instance_id = this.state.instanceId; } if (this.nextBatch) opts.since = this.nextBatch; if (my_filter_string) opts.filter = { generic_search_term: my_filter_string }; @@ -247,7 +244,7 @@ export default createReactClass({ } }, - onOptionChange: function(server, instanceId, includeAll) { + onOptionChange: function(server, instanceId) { // clear next batch so we don't try to load more rooms this.nextBatch = null; this.setState({ @@ -257,7 +254,6 @@ export default createReactClass({ publicRooms: [], roomServer: server, instanceId: instanceId, - includeAll: includeAll, error: null, }, this.refreshRoomList); // We also refresh the room list each time even though this @@ -305,7 +301,7 @@ export default createReactClass({ onJoinFromSearchClick: function(alias) { // If we don't have a particular instance id selected, just show that rooms alias - if (!this.state.instanceId) { + if (!this.state.instanceId || this.state.instanceId === ALL_ROOMS) { // If the user specified an alias without a domain, add on whichever server is selected // in the dropdown if (alias.indexOf(':') == -1) { @@ -406,6 +402,12 @@ export default createReactClass({ // would normally decide what the name is. name: room.name || room_alias || _t('Unnamed room'), }; + + if (this.state.roomServer) { + payload.opts = { + viaServers: [this.state.roomServer], + }; + } } // It's not really possible to join Matrix rooms by ID because the HS has no way to know // which servers to start querying. However, there's no other way to join rooms in @@ -587,7 +589,7 @@ export default createReactClass({ } let placeholder = _t('Find a room…'); - if (!this.state.instanceId) { + if (!this.state.instanceId || this.state.instanceId === ALL_ROOMS) { placeholder = _t("Find a room… (e.g. %(exampleRoom)s)", {exampleRoom: "#example:" + this.state.roomServer}); } else if (instance_expected_field_type) { placeholder = instance_expected_field_type.placeholder; @@ -604,10 +606,18 @@ export default createReactClass({ listHeader =
+ -
; } const explanation = @@ -628,7 +638,7 @@ export default createReactClass({ title={_t("Explore rooms")} >
-

{explanation}

+ {explanation}
{listHeader} {content} diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 36e30343e4..17a496b037 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -405,21 +405,6 @@ export default createReactClass({ this.onResize(); document.addEventListener("keydown", this.onKeyDown); - - // XXX: EVIL HACK to autofocus inviting on empty rooms. - // We use the setTimeout to avoid racing with focus_composer. - if (this.state.room && - this.state.room.getJoinedMemberCount() == 1 && - this.state.room.getLiveTimeline() && - this.state.room.getLiveTimeline().getEvents() && - this.state.room.getLiveTimeline().getEvents().length <= 6) { - const inviteBox = document.getElementById("mx_SearchableEntityList_query"); - setTimeout(function() { - if (inviteBox) { - inviteBox.focus(); - } - }, 50); - } }, shouldComponentUpdate: function(nextProps, nextState) { diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index b81b3ebede..c218fee5d6 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -782,7 +782,7 @@ export default createReactClass({ if (!this._divScroll) { // Likewise, we should have the ref by this point, but if not // turn the NPE into something meaningful. - throw new Error("ScrollPanel._getScrollNode called before gemini ref collected"); + throw new Error("ScrollPanel._getScrollNode called before AutoHideScrollbar ref collected"); } return this._divScroll; diff --git a/src/components/structures/TabbedView.js b/src/components/structures/TabbedView.tsx similarity index 80% rename from src/components/structures/TabbedView.js rename to src/components/structures/TabbedView.tsx index 20af183af8..ea485acc1a 100644 --- a/src/components/structures/TabbedView.js +++ b/src/components/structures/TabbedView.tsx @@ -1,7 +1,7 @@ /* Copyright 2017 Travis Ralston Copyright 2019 New Vector Ltd -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2019, 2020 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. @@ -18,41 +18,54 @@ limitations under the License. import * as React from "react"; import {_t} from '../../languageHandler'; -import PropTypes from "prop-types"; +import * as PropTypes from "prop-types"; import * as sdk from "../../index"; +import { ReactNode } from "react"; /** * Represents a tab for the TabbedView. */ export class Tab { + public label: string; + public icon: string; + public body: React.ReactNode; + /** * Creates a new tab. * @param {string} tabLabel The untranslated tab label. * @param {string} tabIconClass The class for the tab icon. This should be a simple mask. - * @param {string} tabJsx The JSX for the tab container. + * @param {React.ReactNode} tabJsx The JSX for the tab container. */ - constructor(tabLabel, tabIconClass, tabJsx) { + constructor(tabLabel: string, tabIconClass: string, tabJsx: React.ReactNode) { this.label = tabLabel; this.icon = tabIconClass; this.body = tabJsx; } } -export default class TabbedView extends React.Component { +interface IProps { + tabs: Tab[]; +} + +interface IState { + activeTabIndex: number; +} + +export default class TabbedView extends React.Component { static propTypes = { // The tabs to show tabs: PropTypes.arrayOf(PropTypes.instanceOf(Tab)).isRequired, }; - constructor() { - super(); + constructor(props: IProps) { + super(props); this.state = { activeTabIndex: 0, }; } - _getActiveTabIndex() { + private _getActiveTabIndex() { if (!this.state || !this.state.activeTabIndex) return 0; return this.state.activeTabIndex; } @@ -62,7 +75,7 @@ export default class TabbedView extends React.Component { * @param {Tab} tab the tab to show * @private */ - _setActiveTab(tab) { + private _setActiveTab(tab: Tab) { const idx = this.props.tabs.indexOf(tab); if (idx !== -1) { this.setState({activeTabIndex: idx}); @@ -71,7 +84,7 @@ export default class TabbedView extends React.Component { } } - _renderTabLabel(tab) { + private _renderTabLabel(tab: Tab) { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); let classes = "mx_TabbedView_tabLabel "; @@ -97,7 +110,7 @@ export default class TabbedView extends React.Component { ); } - _renderTabPanel(tab) { + private _renderTabPanel(tab: Tab): React.ReactNode { return (
@@ -107,7 +120,7 @@ export default class TabbedView extends React.Component { ); } - render() { + public render(): React.ReactNode { const labels = this.props.tabs.map(tab => this._renderTabLabel(tab)); const panel = this._renderTabPanel(this.props.tabs[this._getActiveTabIndex()]); diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index 622e63d8ce..f1a39d6fcf 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -28,6 +28,7 @@ import { _t } from '../../languageHandler'; import { Droppable } from 'react-beautiful-dnd'; import classNames from 'classnames'; import MatrixClientContext from "../../contexts/MatrixClientContext"; +import AutoHideScrollbar from "./AutoHideScrollbar"; const TagPanel = createReactClass({ displayName: 'TagPanel', @@ -106,7 +107,6 @@ const TagPanel = createReactClass({ const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const ActionButton = sdk.getComponent('elements.ActionButton'); const TintableSvg = sdk.getComponent('elements.TintableSvg'); - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); const tags = this.state.orderedTags.map((tag, index) => { return
- ) } - +
; }, }); diff --git a/src/components/structures/auth/CompleteSecurity.js b/src/components/structures/auth/CompleteSecurity.js index 6bf3e7f07c..3154564cd3 100644 --- a/src/components/structures/auth/CompleteSecurity.js +++ b/src/components/structures/auth/CompleteSecurity.js @@ -54,17 +54,39 @@ export default class CompleteSecurity extends React.Component { } } - onStartClick = async () => { + _onUsePassphraseClick = async () => { this.setState({ phase: PHASE_BUSY, }); const cli = MatrixClientPeg.get(); - const backupInfo = await cli.getKeyBackupVersion(); - this.setState({backupInfo}); try { - await accessSecretStorage(async () => { - await cli.checkOwnCrossSigningTrust(); - if (backupInfo) await cli.restoreKeyBackupWithSecretStorage(backupInfo); + const backupInfo = await cli.getKeyBackupVersion(); + this.setState({backupInfo}); + + // The control flow is fairly twisted here... + // For the purposes of completing security, we only wait on getting + // as far as the trust check and then show a green shield. + // We also begin the key backup restore as well, which we're + // awaiting inside `accessSecretStorage` only so that it keeps your + // passphase cached for that work. This dialog itself will only wait + // on the first trust check, and the key backup restore will happen + // in the background. + await new Promise((resolve, reject) => { + try { + accessSecretStorage(async () => { + await cli.checkOwnCrossSigningTrust(); + resolve(); + if (backupInfo) { + // A complete restore can take many minutes for large + // accounts / slow servers, so we allow the dialog + // to advance before this. + await cli.restoreKeyBackupWithSecretStorage(backupInfo); + } + }); + } catch (e) { + console.error(e); + reject(e); + } }); if (cli.getCrossSigningId()) { @@ -147,13 +169,27 @@ export default class CompleteSecurity extends React.Component { member={MatrixClientPeg.get().getUser(this.state.verificationRequest.otherUserId)} />; } else if (phase === PHASE_INTRO) { + const InlineSpinner = sdk.getComponent('elements.InlineSpinner'); + icon = ; title = _t("Complete security"); body = (

{_t( - "Verify this session to grant it access to encrypted messages.", + "Open an existing session & use it to verify this one, " + + "granting it access to encrypted messages.", )}

+

{_t("Waiting…")}

+

{_t( + "If you can’t access one, ", + {}, { + button: sub => + {sub} + , + })}

{_t("Skip")} - - {_t("Start")} -
); diff --git a/src/components/views/dialogs/InfoDialog.js b/src/components/views/dialogs/InfoDialog.js index 8a8f51c25a..b63f6ba9c6 100644 --- a/src/components/views/dialogs/InfoDialog.js +++ b/src/components/views/dialogs/InfoDialog.js @@ -32,6 +32,7 @@ export default createReactClass({ button: PropTypes.string, onFinished: PropTypes.func, hasCloseButton: PropTypes.bool, + onKeyDown: PropTypes.func, }, getDefaultProps: function() { @@ -50,10 +51,13 @@ export default createReactClass({ const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return ( -
{ this.props.description } diff --git a/src/components/views/dialogs/QuestionDialog.js b/src/components/views/dialogs/QuestionDialog.js index 8cb16dd88f..07a1eae5d5 100644 --- a/src/components/views/dialogs/QuestionDialog.js +++ b/src/components/views/dialogs/QuestionDialog.js @@ -33,6 +33,7 @@ export default createReactClass({ onFinished: PropTypes.func.isRequired, headerImage: PropTypes.string, quitOnly: PropTypes.bool, // quitOnly doesn't show the cancel button just the quit [x]. + fixedWidth: PropTypes.bool, }, getDefaultProps: function() { @@ -63,11 +64,14 @@ export default createReactClass({ primaryButtonClass = "danger"; } return ( -
{ this.props.description } diff --git a/src/components/views/dialogs/TextInputDialog.js b/src/components/views/dialogs/TextInputDialog.js index 0ffc072cc0..b9f6f6ebce 100644 --- a/src/components/views/dialogs/TextInputDialog.js +++ b/src/components/views/dialogs/TextInputDialog.js @@ -18,6 +18,7 @@ import React, {createRef} from 'react'; import createReactClass from 'create-react-class'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; +import Field from "../elements/Field"; export default createReactClass({ displayName: 'TextInputDialog', @@ -28,9 +29,13 @@ export default createReactClass({ PropTypes.string, ]), value: PropTypes.string, + placeholder: PropTypes.string, button: PropTypes.string, focus: PropTypes.bool, onFinished: PropTypes.func.isRequired, + hasCancel: PropTypes.bool, + validator: PropTypes.func, // result of withValidation + fixedWidth: PropTypes.bool, }, getDefaultProps: function() { @@ -39,34 +44,70 @@ export default createReactClass({ value: "", description: "", focus: true, + hasCancel: true, + }; + }, + + getInitialState: function() { + return { + value: this.props.value, + valid: false, }; }, UNSAFE_componentWillMount: function() { - this._textinput = createRef(); + this._field = createRef(); }, componentDidMount: function() { if (this.props.focus) { // Set the cursor at the end of the text input - this._textinput.current.value = this.props.value; + // this._field.current.value = this.props.value; + this._field.current.focus(); } }, - onOk: function() { - this.props.onFinished(true, this._textinput.current.value); + onOk: async function(ev) { + ev.preventDefault(); + if (this.props.validator) { + await this._field.current.validate({ allowEmpty: false }); + + if (!this._field.current.state.valid) { + this._field.current.focus(); + this._field.current.validate({ allowEmpty: false, focused: true }); + return; + } + } + this.props.onFinished(true, this.state.value); }, onCancel: function() { this.props.onFinished(false); }, + onChange: function(ev) { + this.setState({ + value: ev.target.value, + }); + }, + + onValidate: async function(fieldState) { + const result = await this.props.validator(fieldState); + this.setState({ + valid: result.valid, + }); + return result; + }, + render: function() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return ( -
@@ -74,19 +115,26 @@ export default createReactClass({
- + ref={this._field} + type="text" + label={this.props.placeholder} + value={this.state.value} + onChange={this.onChange} + onValidate={this.props.validator ? this.onValidate : undefined} + size="64" + />
- + onCancel={this.onCancel} + hasCancel={this.props.hasCancel} + />
); }, diff --git a/src/components/views/dialogs/UnknownDeviceDialog.js b/src/components/views/dialogs/UnknownDeviceDialog.js index d58961f964..69ebb72a6f 100644 --- a/src/components/views/dialogs/UnknownDeviceDialog.js +++ b/src/components/views/dialogs/UnknownDeviceDialog.js @@ -122,7 +122,6 @@ export default createReactClass({ }, render: function() { - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); if (this.props.devices === null) { const Spinner = sdk.getComponent("elements.Spinner"); return ; @@ -168,7 +167,7 @@ export default createReactClass({ title={_t('Room contains unknown sessions')} contentId='mx_Dialog_content' > - +

{ _t('"%(RoomName)s" contains sessions that you haven\'t seen before.', {RoomName: this.props.room.name}) }

@@ -176,7 +175,7 @@ export default createReactClass({ { _t("Unknown sessions") }: - +
diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index cb6a015d86..2fabda1a74 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -1,6 +1,7 @@ /* Copyright 2016 OpenMarket Ltd Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> +Copyright 2020 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,241 +16,275 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, {useEffect, useState} from 'react'; import PropTypes from 'prop-types'; + import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {instanceForInstanceId} from '../../../utils/DirectoryUtils'; +import { + ContextMenu, + useContextMenu, + ContextMenuButton, + MenuItemRadio, + MenuItem, + MenuGroup, +} from "../../structures/ContextMenu"; +import {_t} from "../../../languageHandler"; +import SdkConfig from "../../../SdkConfig"; +import {useSettingValue} from "../../../hooks/useSettings"; +import * as sdk from "../../../index"; +import Modal from "../../../Modal"; +import SettingsStore from "../../../settings/SettingsStore"; +import withValidation from "../elements/Validation"; -const DEFAULT_ICON_URL = require("../../../../res/img/network-matrix.svg"); +export const ALL_ROOMS = Symbol("ALL_ROOMS"); -export default class NetworkDropdown extends React.Component { - constructor(props) { - super(props); +const SETTING_NAME = "room_directory_servers"; - this.dropdownRootElement = null; - this.ignoreEvent = null; +const inPlaceOf = (elementRect) => ({ + right: window.innerWidth - elementRect.right, + top: elementRect.top, + chevronOffset: 0, + chevronFace: "none", +}); - this.onInputClick = this.onInputClick.bind(this); - this.onRootClick = this.onRootClick.bind(this); - this.onDocumentClick = this.onDocumentClick.bind(this); - this.onMenuOptionClick = this.onMenuOptionClick.bind(this); - this.onInputKeyUp = this.onInputKeyUp.bind(this); - this.collectRoot = this.collectRoot.bind(this); - this.collectInputTextBox = this.collectInputTextBox.bind(this); +const validServer = withValidation({ + rules: [ + { + key: "required", + test: async ({ value }) => !!value, + invalid: () => _t("Enter a server name"), + }, { + key: "available", + final: true, + test: async ({ value }) => { + try { + const opts = { + limit: 1, + server: value, + }; + // check if we can successfully load this server's room directory + await MatrixClientPeg.get().publicRooms(opts); + return true; + } catch (e) { + return false; + } + }, + valid: () => _t("Looks good"), + invalid: () => _t("Can't find this server or its room list"), + }, + ], +}); - this.inputTextBox = null; +// This dropdown sources homeservers from three places: +// + your currently connected homeserver +// + homeservers in config.json["roomDirectory"] +// + homeservers in SettingsStore["room_directory_servers"] +// if a server exists in multiple, only keep the top-most entry. - const server = MatrixClientPeg.getHomeserverName(); - this.state = { - expanded: false, - selectedServer: server, - selectedInstanceId: null, - includeAllNetworks: false, +const NetworkDropdown = ({onOptionChange, protocols = {}, selectedServerName, selectedInstanceId}) => { + const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu(); + const _userDefinedServers = useSettingValue(SETTING_NAME); + const [userDefinedServers, _setUserDefinedServers] = useState(_userDefinedServers); + + const handlerFactory = (server, instanceId) => { + return () => { + onOptionChange(server, instanceId); + closeMenu(); }; - } + }; - componentWillMount() { - // Listen for all clicks on the document so we can close the - // menu when the user clicks somewhere else - document.addEventListener('click', this.onDocumentClick, false); + const setUserDefinedServers = servers => { + _setUserDefinedServers(servers); + SettingsStore.setValue(SETTING_NAME, null, "account", servers); + }; + // keep local echo up to date with external changes + useEffect(() => { + _setUserDefinedServers(_userDefinedServers); + }, [_userDefinedServers]); - // fire this now so the defaults can be set up - const {selectedServer, selectedInstanceId, includeAllNetworks} = this.state; - this.props.onOptionChange(selectedServer, selectedInstanceId, includeAllNetworks); - } + // we either show the button or the dropdown in its place. + let content; + if (menuDisplayed) { + const config = SdkConfig.get(); + const roomDirectory = config.roomDirectory || {}; - componentWillUnmount() { - document.removeEventListener('click', this.onDocumentClick, false); - } + const hsName = MatrixClientPeg.getHomeserverName(); + const configServers = new Set(roomDirectory.servers); - componentDidUpdate() { - if (this.state.expanded && this.inputTextBox) { - this.inputTextBox.focus(); - } - } - - onDocumentClick(ev) { - // Close the dropdown if the user clicks anywhere that isn't - // within our root element - if (ev !== this.ignoreEvent) { - this.setState({ - expanded: false, - }); - } - } - - onRootClick(ev) { - // This captures any clicks that happen within our elements, - // such that we can then ignore them when they're seen by the - // click listener on the document handler, ie. not close the - // dropdown immediately after opening it. - // NB. We can't just stopPropagation() because then the event - // doesn't reach the React onClick(). - this.ignoreEvent = ev; - } - - onInputClick(ev) { - this.setState({ - expanded: !this.state.expanded, - }); - ev.preventDefault(); - } - - onMenuOptionClick(server, instance, includeAll) { - this.setState({ - expanded: false, - selectedServer: server, - selectedInstanceId: instance ? instance.instance_id : null, - includeAllNetworks: includeAll, - }); - this.props.onOptionChange(server, instance ? instance.instance_id : null, includeAll); - } - - onInputKeyUp(e) { - if (e.key === 'Enter') { - this.setState({ - expanded: false, - selectedServer: e.target.value, - selectedNetwork: null, - includeAllNetworks: false, - }); - this.props.onOptionChange(e.target.value, null); - } - } - - collectRoot(e) { - if (this.dropdownRootElement) { - this.dropdownRootElement.removeEventListener('click', this.onRootClick, false); - } - if (e) { - e.addEventListener('click', this.onRootClick, false); - } - this.dropdownRootElement = e; - } - - collectInputTextBox(e) { - this.inputTextBox = e; - } - - _getMenuOptions() { - const options = []; - const roomDirectory = this.props.config.roomDirectory || {}; - - let servers = []; - if (roomDirectory.servers) { - servers = servers.concat(roomDirectory.servers); - } - - if (!servers.includes(MatrixClientPeg.getHomeserverName())) { - servers.unshift(MatrixClientPeg.getHomeserverName()); - } + // configured servers take preference over user-defined ones, if one occurs in both ignore the latter one. + const removableServers = new Set(userDefinedServers.filter(s => !configServers.has(s) && s !== hsName)); + const servers = [ + // we always show our connected HS, this takes precedence over it being configured or user-defined + hsName, + ...Array.from(configServers).filter(s => s !== hsName).sort(), + ...Array.from(removableServers).sort(), + ]; // For our own HS, we can use the instance_ids given in the third party protocols // response to get the server to filter the room list by network for us. // We can't get thirdparty protocols for remote server yet though, so for those // we can only show the default room list. - for (const server of servers) { - options.push(this._makeMenuOption(server, null, true)); - if (server === MatrixClientPeg.getHomeserverName()) { - options.push(this._makeMenuOption(server, null, false)); - if (this.props.protocols) { - for (const proto of Object.keys(this.props.protocols)) { - if (!this.props.protocols[proto].instances) continue; + const options = servers.map(server => { + const serverSelected = server === selectedServerName; + const entries = []; - const sortedInstances = this.props.protocols[proto].instances; - sortedInstances.sort(function(x, y) { - const a = x.desc; - const b = y.desc; - if (a < b) { - return -1; - } else if (a > b) { - return 1; - } else { - return 0; - } - }); - - for (const instance of sortedInstances) { - if (!instance.instance_id) continue; - options.push(this._makeMenuOption(server, instance, false)); - } - } - } + const protocolsList = server === hsName ? Object.values(protocols) : []; + if (protocolsList.length > 0) { + // add a fake protocol with the ALL_ROOMS symbol + protocolsList.push({ + instances: [{ + instance_id: ALL_ROOMS, + desc: _t("All rooms"), + }], + }); } - } - return options; - } + protocolsList.forEach(({instances=[]}) => { + [...instances].sort((b, a) => { + return a.desc.localeCompare(b.desc); + }).forEach(({desc, instance_id: instanceId}) => { + entries.push( + + { desc } + ); + }); + }); - _makeMenuOption(server, instance, includeAll, handleClicks) { - if (handleClicks === undefined) handleClicks = true; + let subtitle; + if (server === hsName) { + subtitle = ( +
+ {_t("Your server")} +
+ ); + } - let icon; - let name; - let key; + let removeButton; + if (removableServers.has(server)) { + const onClick = async () => { + closeMenu(); + const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); + const {finished} = Modal.createTrackedDialog("Network Dropdown", "Remove server", QuestionDialog, { + title: _t("Are you sure?"), + description: _t("Are you sure you want to remove %(serverName)s", { + serverName: server, + }, { + b: serverName => { serverName }, + }), + button: _t("Remove"), + fixedWidth: false, + }, "mx_NetworkDropdown_dialog"); - if (!instance && includeAll) { - key = server; - name = server; - } else if (!instance) { - key = server + '_all'; - name = 'Matrix'; - icon = ; - } else { - key = server + '_inst_' + instance.instance_id; - const imgUrl = instance.icon ? - MatrixClientPeg.get().mxcUrlToHttp(instance.icon, 25, 25, 'crop', true) : - DEFAULT_ICON_URL; - icon = ; - name = instance.desc; - } + const [ok] = await finished; + if (!ok) return; - const clickHandler = handleClicks ? this.onMenuOptionClick.bind(this, server, instance, includeAll) : null; + // delete from setting + setUserDefinedServers(servers.filter(s => s !== server)); - return
- {icon} - {name} -
; - } + // the selected server is being removed, reset to our HS + if (serverSelected === server) { + onOptionChange(hsName, undefined); + } + }; + removeButton = ; + } - render() { - let currentValue; + // ARIA: in actual fact the entire menu is one large radio group but for better screen reader support + // we use group to notate server wrongly. + return ( + +
+ { server } + { removeButton } +
+ { subtitle } - let menu; - if (this.state.expanded) { - const menuOptions = this._getMenuOptions(); - menu =
- {menuOptions} -
; - currentValue = ; - } else { - const instance = instanceForInstanceId(this.props.protocols, this.state.selectedInstanceId); - currentValue = this._makeMenuOption( - this.state.selectedServer, instance, this.state.includeAllNetworks, false, + + {_t("Matrix")} + + { entries } +
); + }); + + const onClick = async () => { + closeMenu(); + const TextInputDialog = sdk.getComponent("dialogs.TextInputDialog"); + const { finished } = Modal.createTrackedDialog("Network Dropdown", "Add a new server", TextInputDialog, { + title: _t("Add a new server"), + description: _t("Enter the name of a new server you want to explore."), + button: _t("Add"), + hasCancel: false, + placeholder: _t("Server name"), + validator: validServer, + fixedWidth: false, + }, "mx_NetworkDropdown_dialog"); + + const [ok, newServer] = await finished; + if (!ok) return; + + if (!userDefinedServers.includes(newServer)) { + setUserDefinedServers([...userDefinedServers, newServer]); + } + + onOptionChange(newServer); // change filter to the new server + }; + + const buttonRect = handle.current.getBoundingClientRect(); + content = +
+ {options} + + {_t("Add a new server...")} + +
+
; + } else { + let currentValue; + if (selectedInstanceId === ALL_ROOMS) { + currentValue = _t("All rooms"); + } else if (selectedInstanceId) { + const instance = instanceForInstanceId(protocols, selectedInstanceId); + currentValue = _t("%(networkName)s rooms", { + networkName: instance.desc, + }); + } else { + currentValue = _t("Matrix rooms"); } - return
-
+ content = + {currentValue} - - {menu} -
-
; + + ({selectedServerName}) + + ; } -} + + return
+ {content} +
; +}; NetworkDropdown.propTypes = { onOptionChange: PropTypes.func.isRequired, protocols: PropTypes.object, - // The room directory config. May have a 'servers' key that is a list of server names to include in the dropdown - config: PropTypes.object, }; -NetworkDropdown.defaultProps = { - protocols: {}, - config: {}, -}; +export default NetworkDropdown; diff --git a/src/components/views/elements/EditableItemList.js b/src/components/views/elements/EditableItemList.js index ae3473ef0d..6e649e777a 100644 --- a/src/components/views/elements/EditableItemList.js +++ b/src/components/views/elements/EditableItemList.js @@ -78,8 +78,7 @@ export class EditableItem extends React.Component { return (
- {_t("Remove")} +
{this.props.value}
); diff --git a/src/components/views/elements/GeminiScrollbarWrapper.js b/src/components/views/elements/GeminiScrollbarWrapper.js deleted file mode 100644 index 13eb14ecc3..0000000000 --- a/src/components/views/elements/GeminiScrollbarWrapper.js +++ /dev/null @@ -1,35 +0,0 @@ -/* -Copyright 2018 New Vector Ltd. - -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 GeminiScrollbar from 'react-gemini-scrollbar'; - -function GeminiScrollbarWrapper(props) { - const {wrappedRef, ...wrappedProps} = props; - - // Enable forceGemini so that gemini is always enabled. This is - // to avoid future issues where a feature is implemented without - // doing QA on every OS/browser combination. - // - // By default GeminiScrollbar allows native scrollbars to be used - // on macOS. Use forceGemini to enable Gemini's non-native - // scrollbars on all OSs. - return - { props.children } - ; -} -export default GeminiScrollbarWrapper; - diff --git a/src/components/views/groups/GroupMemberInfo.js b/src/components/views/groups/GroupMemberInfo.js index e659352b74..f70c769ad7 100644 --- a/src/components/views/groups/GroupMemberInfo.js +++ b/src/components/views/groups/GroupMemberInfo.js @@ -27,6 +27,7 @@ import { GroupMemberType } from '../../../groups'; import GroupStore from '../../../stores/GroupStore'; import AccessibleButton from '../elements/AccessibleButton'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; export default createReactClass({ displayName: 'GroupMemberInfo', @@ -182,10 +183,9 @@ export default createReactClass({ this.props.groupMember.displayname || this.props.groupMember.userId ); - const GeminiScrollbarWrapper = sdk.getComponent('elements.GeminiScrollbarWrapper'); return (
- + @@ -199,7 +199,7 @@ export default createReactClass({
{ adminTools } - +
); }, diff --git a/src/components/views/groups/GroupMemberList.js b/src/components/views/groups/GroupMemberList.js index 05af70b266..2853e70afa 100644 --- a/src/components/views/groups/GroupMemberList.js +++ b/src/components/views/groups/GroupMemberList.js @@ -26,6 +26,7 @@ import { showGroupInviteDialog } from '../../../GroupAddressPicker'; import AccessibleButton from '../elements/AccessibleButton'; import TintableSvg from '../elements/TintableSvg'; import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases"; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; const INITIAL_LOAD_NUM_MEMBERS = 30; @@ -172,7 +173,6 @@ export default createReactClass({ }, render: function() { - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); if (this.state.fetching || this.state.fetchingInvitedMembers) { const Spinner = sdk.getComponent("elements.Spinner"); return (
@@ -225,10 +225,10 @@ export default createReactClass({ return (
{ inviteButton } - + { joined } { invited } - + { inputBox }
); diff --git a/src/components/views/groups/GroupRoomInfo.js b/src/components/views/groups/GroupRoomInfo.js index 7b9f43f15f..91d84be4d1 100644 --- a/src/components/views/groups/GroupRoomInfo.js +++ b/src/components/views/groups/GroupRoomInfo.js @@ -24,6 +24,7 @@ import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import GroupStore from '../../../stores/GroupStore'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; export default createReactClass({ displayName: 'GroupRoomInfo', @@ -153,7 +154,6 @@ export default createReactClass({ render: function() { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const InlineSpinner = sdk.getComponent('elements.InlineSpinner'); - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); if (this.state.groupRoomRemoveLoading || !this.state.groupRoom) { const Spinner = sdk.getComponent("elements.Spinner"); return
@@ -216,7 +216,7 @@ export default createReactClass({ const groupRoomName = this.state.groupRoom.displayname; return (
- + @@ -231,7 +231,7 @@ export default createReactClass({
{ adminTools } - +
); }, diff --git a/src/components/views/groups/GroupRoomList.js b/src/components/views/groups/GroupRoomList.js index 5fd8c9f31d..dee304e1f6 100644 --- a/src/components/views/groups/GroupRoomList.js +++ b/src/components/views/groups/GroupRoomList.js @@ -22,6 +22,7 @@ import PropTypes from 'prop-types'; import { showGroupAddRoomDialog } from '../../../GroupAddressPicker'; import AccessibleButton from '../elements/AccessibleButton'; import TintableSvg from '../elements/TintableSvg'; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; const INITIAL_LOAD_NUM_ROOMS = 30; @@ -150,17 +151,16 @@ export default createReactClass({ placeholder={_t('Filter community rooms')} autoComplete="off" /> ); - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); const TruncatedList = sdk.getComponent("elements.TruncatedList"); return (
{ inviteButton } - + { this.makeGroupRoomTiles(this.state.searchQuery) } - + { inputBox }
); diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js index 0a7bd1d333..857a80c34a 100644 --- a/src/components/views/room_settings/AliasSettings.js +++ b/src/components/views/room_settings/AliasSettings.js @@ -25,6 +25,7 @@ import Field from "../elements/Field"; import ErrorDialog from "../dialogs/ErrorDialog"; import AccessibleButton from "../elements/AccessibleButton"; import Modal from "../../../Modal"; +import RoomPublishSetting from "./RoomPublishSetting"; class EditableAliasesList extends EditableItemList { constructor(props) { @@ -97,6 +98,7 @@ export default class AliasSettings extends React.Component { canonicalAlias: null, // #canonical:domain.tld updatingCanonicalAlias: false, localAliasesLoading: false, + detailsOpen: false, }; if (props.canonicalAliasEvent) { @@ -234,8 +236,7 @@ export default class AliasSettings extends React.Component { // TODO: In future, we should probably be making sure that the alias actually belongs // to this room. See https://github.com/vector-im/riot-web/issues/7353 MatrixClientPeg.get().deleteAlias(alias).then(() => { - const localAliases = this.state.localAliases.slice(); - localAliases.splice(index); + const localAliases = this.state.localAliases.filter(a => a !== alias); this.setState({localAliases}); if (this.state.canonicalAlias === alias) { @@ -243,12 +244,18 @@ export default class AliasSettings extends React.Component { } }).catch((err) => { console.error(err); - Modal.createTrackedDialog('Error removing alias', '', ErrorDialog, { - title: _t("Error removing alias"), - description: _t( + let description; + if (err.errcode === "M_FORBIDDEN") { + description = _t("You don't have permission to delete the alias."); + } else { + description = _t( "There was an error removing that alias. It may no longer exist or a temporary " + "error occurred.", - ), + ); + } + Modal.createTrackedDialog('Error removing alias', '', ErrorDialog, { + title: _t("Error removing alias"), + description, }); }); }; @@ -261,6 +268,7 @@ export default class AliasSettings extends React.Component { this.loadLocalAliases(); } } + this.setState({detailsOpen: event.target.open}); }; onCanonicalAliasChange = (event) => { @@ -340,16 +348,18 @@ export default class AliasSettings extends React.Component { onItemAdded={this.onLocalAliasAdded} onItemRemoved={this.onLocalAliasDeleted} noItemsLabel={_t('This room has no local addresses')} - placeholder={_t( - 'New address (e.g. #foo:%(localDomain)s)', {localDomain: localDomain}, - )} + placeholder={_t('Local address')} domain={localDomain} />); } return (
+ {_t("Published Addresses")} +

{_t("Published addresses can be used by anyone on any server to join your room. " + + "To publish an address, it needs to be set as a local address first.")}

{canonicalAliasSection} + {this._getLocalNonAltAliases().map(alias => { return
diff --git a/src/components/views/room_settings/RoomPublishSetting.js b/src/components/views/room_settings/RoomPublishSetting.js new file mode 100644 index 0000000000..bac2dfc656 --- /dev/null +++ b/src/components/views/room_settings/RoomPublishSetting.js @@ -0,0 +1,60 @@ +/* +Copyright 2020 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 LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; +import {_t} from "../../../languageHandler"; +import {MatrixClientPeg} from "../../../MatrixClientPeg"; + +export default class RoomPublishSetting extends React.PureComponent { + constructor(props) { + super(props); + this.state = {isRoomPublished: false}; + } + + onRoomPublishChange = (e) => { + const valueBefore = this.state.isRoomPublished; + const newValue = !valueBefore; + this.setState({isRoomPublished: newValue}); + const client = MatrixClientPeg.get(); + + client.setRoomDirectoryVisibility( + this.props.roomId, + newValue ? 'public' : 'private', + ).catch(() => { + // Roll back the local echo on the change + this.setState({isRoomPublished: valueBefore}); + }); + }; + + componentDidMount() { + const client = MatrixClientPeg.get(); + client.getRoomDirectoryVisibility(this.props.roomId).then((result => { + this.setState({isRoomPublished: result.visibility === 'public'}); + })); + } + + render() { + const client = MatrixClientPeg.get(); + + return (); + } +} diff --git a/src/components/views/rooms/BasicMessageComposer.js b/src/components/views/rooms/BasicMessageComposer.js index dabf04ab99..147f3c0af8 100644 --- a/src/components/views/rooms/BasicMessageComposer.js +++ b/src/components/views/rooms/BasicMessageComposer.js @@ -370,6 +370,16 @@ export default class BasicMessageEditor extends React.Component { } else if (modKey && event.key === Key.GREATER_THAN) { this._onFormatAction("quote"); handled = true; + // redo + } else if ((!IS_MAC && modKey && event.key === Key.Y) || + (IS_MAC && modKey && event.shiftKey && event.key === Key.Z)) { + if (this.historyManager.canRedo()) { + const {parts, caret} = this.historyManager.redo(); + // pass matching inputType so historyManager doesn't push echo + // when invoked from rerender callback. + model.reset(parts, caret, "historyRedo"); + } + handled = true; // undo } else if (modKey && event.key === Key.Z) { if (this.historyManager.canUndo()) { @@ -379,15 +389,6 @@ export default class BasicMessageEditor extends React.Component { model.reset(parts, caret, "historyUndo"); } handled = true; - // redo - } else if (modKey && event.key === Key.Y) { - if (this.historyManager.canRedo()) { - const {parts, caret} = this.historyManager.redo(); - // pass matching inputType so historyManager doesn't push echo - // when invoked from rerender callback. - model.reset(parts, caret, "historyRedo"); - } - handled = true; // insert newline on Shift+Enter } else if (event.key === Key.ENTER && (event.shiftKey || (IS_MAC && event.altKey))) { this._insertText("\n"); diff --git a/src/components/views/rooms/ForwardMessage.js b/src/components/views/rooms/ForwardMessage.js index c7c954dc9f..78466f7cb5 100644 --- a/src/components/views/rooms/ForwardMessage.js +++ b/src/components/views/rooms/ForwardMessage.js @@ -33,7 +33,6 @@ export default createReactClass({ componentWillMount: function() { dis.dispatch({ action: 'panel_disable', - rightDisabled: true, middleDisabled: true, }); }, @@ -45,7 +44,6 @@ export default createReactClass({ componentWillUnmount: function() { dis.dispatch({ action: 'panel_disable', - sideDisabled: false, middleDisabled: false, }); document.removeEventListener('keydown', this._onKeyDown); diff --git a/src/components/views/rooms/JumpToBottomButton.js b/src/components/views/rooms/JumpToBottomButton.js index 487071855f..d3305f498a 100644 --- a/src/components/views/rooms/JumpToBottomButton.js +++ b/src/components/views/rooms/JumpToBottomButton.js @@ -24,7 +24,7 @@ export default (props) => { } return (
{ badge } diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 557a58412a..c86bcb2ff0 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -178,6 +178,7 @@ export default class MessageComposer extends React.Component { isQuoting: Boolean(RoomViewStore.getQuotingEvent()), tombstone: this._getRoomTombstone(), canSendMessages: this.props.room.maySendMessage(), + showCallButtons: SettingsStore.getValue("showCallButtonsInComposer"), }; } @@ -325,10 +326,20 @@ export default class MessageComposer extends React.Component { permalinkCreator={this.props.permalinkCreator} />, , , - callInProgress ? : null, - callInProgress ? null : , - callInProgress ? null : , ); + + if (this.state.showCallButtons) { + if (callInProgress) { + controls.push( + , + ); + } else { + controls.push( + , + , + ); + } + } } else if (this.state.tombstone) { const replacementRoomId = this.state.tombstone.getContent()['replacement_room']; diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 0fe0ff3d8c..2143c7f1a8 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -780,7 +780,7 @@ export default createReactClass({ aria-label={_t("Rooms")} // Firefox sometimes makes this element focusable due to // overflow:scroll;, so force it out of tab order. - tabindex="-1" + tabIndex="-1" onMouseMove={this.onMouseMove} onMouseLeave={this.onMouseLeave} > diff --git a/src/components/views/rooms/SearchableEntityList.js b/src/components/views/rooms/SearchableEntityList.js deleted file mode 100644 index 807ddbf729..0000000000 --- a/src/components/views/rooms/SearchableEntityList.js +++ /dev/null @@ -1,186 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket Ltd -Copyright 2019 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 PropTypes from 'prop-types'; -import createReactClass from 'create-react-class'; -import * as sdk from "../../../index"; -import { _t } from '../../../languageHandler'; - -// A list capable of displaying entities which conform to the SearchableEntity -// interface which is an object containing getJsx(): Jsx and matches(query: string): boolean -const SearchableEntityList = createReactClass({ - displayName: 'SearchableEntityList', - - propTypes: { - emptyQueryShowsAll: PropTypes.bool, - showInputBox: PropTypes.bool, - onQueryChanged: PropTypes.func, // fn(inputText) - onSubmit: PropTypes.func, // fn(inputText) - entities: PropTypes.array, - truncateAt: PropTypes.number, - }, - - getDefaultProps: function() { - return { - showInputBox: true, - entities: [], - emptyQueryShowsAll: false, - onSubmit: function() {}, - onQueryChanged: function(input) {}, - }; - }, - - getInitialState: function() { - return { - query: "", - focused: false, - truncateAt: this.props.truncateAt, - results: this.getSearchResults("", this.props.entities), - }; - }, - - componentWillReceiveProps: function(newProps) { - // recalculate the search results in case we got new entities - this.setState({ - results: this.getSearchResults(this.state.query, newProps.entities), - }); - }, - - componentWillUnmount: function() { - // pretend the query box was blanked out else filters could still be - // applied to other components which rely on onQueryChanged. - this.props.onQueryChanged(""); - }, - - /** - * Public-facing method to set the input query text to the given input. - * @param {string} input - */ - setQuery: function(input) { - this.setState({ - query: input, - results: this.getSearchResults(input, this.props.entities), - }); - }, - - onQueryChanged: function(ev) { - const q = ev.target.value; - this.setState({ - query: q, - // reset truncation if they back out the entire text - truncateAt: (q.length === 0 ? this.props.truncateAt : this.state.truncateAt), - results: this.getSearchResults(q, this.props.entities), - }, () => { - // invoke the callback AFTER we've flushed the new state. We need to - // do this because onQueryChanged can result in new props being passed - // to this component, which will then try to recalculate the search - // list. If we do this without flushing, we'll recalc with the last - // search term and not the current one! - this.props.onQueryChanged(q); - }); - }, - - onQuerySubmit: function(ev) { - ev.preventDefault(); - this.props.onSubmit(this.state.query); - }, - - getSearchResults: function(query, entities) { - if (!query || query.length === 0) { - return this.props.emptyQueryShowsAll ? entities : []; - } - return entities.filter(function(e) { - return e.matches(query); - }); - }, - - _showAll: function() { - this.setState({ - truncateAt: -1, - }); - }, - - _createOverflowEntity: function(overflowCount, totalCount) { - const EntityTile = sdk.getComponent("rooms.EntityTile"); - const BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); - const text = _t("and %(count)s others...", { count: overflowCount }); - return ( - - } name={text} presenceState="online" suppressOnHover={true} - onClick={this._showAll} /> - ); - }, - - render: function() { - let inputBox; - - if (this.props.showInputBox) { - inputBox = ( -
- { this.setState({ focused: true }); }} - onBlur= {() => { this.setState({ focused: false }); }} - placeholder={_t("Search")} /> -
- ); - } - - let list; - if (this.state.results.length > 1 || this.state.focused) { - if (this.props.truncateAt) { // caller wants list truncated - const TruncatedList = sdk.getComponent("elements.TruncatedList"); - list = ( - - { this.state.results.map((entity) => { - return entity.getJsx(); - }) } - - ); - } else { - list = ( -
- { this.state.results.map((entity) => { - return entity.getJsx(); - }) } -
- ); - } - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); - list = ( - - { list } - - ); - } - - return ( -
- { inputBox } - { list } - { list ?

: '' } -
- ); - }, -}); - -export default SearchableEntityList; diff --git a/src/components/views/settings/KeyBackupPanel.js b/src/components/views/settings/KeyBackupPanel.js index 73be2bad9f..27fdb2cb56 100644 --- a/src/components/views/settings/KeyBackupPanel.js +++ b/src/components/views/settings/KeyBackupPanel.js @@ -277,25 +277,25 @@ export default class KeyBackupPanel extends React.PureComponent { "Backup has an invalid signature from this session", {}, { validity }, ); - } else if (sig.valid && sig.device.isVerified()) { + } else if (sig.valid && sig.deviceTrust.isVerified()) { sigStatus = _t( "Backup has a valid signature from " + "verified session ", {}, { validity, verify, device }, ); - } else if (sig.valid && !sig.device.isVerified()) { + } else if (sig.valid && !sig.deviceTrust.isVerified()) { sigStatus = _t( "Backup has a valid signature from " + "unverified session ", {}, { validity, verify, device }, ); - } else if (!sig.valid && sig.device.isVerified()) { + } else if (!sig.valid && sig.deviceTrust.isVerified()) { sigStatus = _t( "Backup has an invalid signature from " + "verified session ", {}, { validity, verify, device }, ); - } else if (!sig.valid && !sig.device.isVerified()) { + } else if (!sig.valid && !sig.deviceTrust.isVerified()) { sigStatus = _t( "Backup has an invalid signature from " + "unverified session ", diff --git a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js index b65f8d49a4..99882ae400 100644 --- a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js +++ b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js @@ -21,7 +21,6 @@ import RoomProfileSettings from "../../../room_settings/RoomProfileSettings"; import * as sdk from "../../../../.."; import AccessibleButton from "../../../elements/AccessibleButton"; import dis from "../../../../../dispatcher"; -import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; export default class GeneralRoomSettingsTab extends React.Component { @@ -39,26 +38,6 @@ export default class GeneralRoomSettingsTab extends React.Component { }; } - componentWillMount() { - this.context.getRoomDirectoryVisibility(this.props.roomId).then((result => { - this.setState({isRoomPublished: result.visibility === 'public'}); - })); - } - - onRoomPublishChange = (e) => { - const valueBefore = this.state.isRoomPublished; - const newValue = !valueBefore; - this.setState({isRoomPublished: newValue}); - - this.context.setRoomDirectoryVisibility( - this.props.roomId, - newValue ? 'public' : 'private', - ).catch(() => { - // Roll back the local echo on the change - this.setState({isRoomPublished: valueBefore}); - }); - }; - _onLeaveClick = () => { dis.dispatch({ action: 'leave_room', @@ -75,7 +54,6 @@ export default class GeneralRoomSettingsTab extends React.Component { const room = client.getRoom(this.props.roomId); const canSetAliases = true; // Previously, we arbitrarily only allowed admins to do this - const canActuallySetAliases = room.currentState.mayClientSendStateEvent("m.room.aliases", client); const canSetCanonical = room.currentState.mayClientSendStateEvent("m.room.canonical_alias", client); const canonicalAliasEv = room.currentState.getStateEvents("m.room.canonical_alias", ''); const aliasEvents = room.currentState.getStateEvents("m.room.aliases"); @@ -90,21 +68,13 @@ export default class GeneralRoomSettingsTab extends React.Component {
- {_t("Room Addresses")} +
{_t("Room Addresses")}
-
- -
- +
{_t("Other")}
{_t("Flair")}
{ + let currentThemes = SettingsStore.getValue("custom_themes"); + if (!currentThemes) currentThemes = []; + currentThemes = currentThemes.map(c => c); // cheap clone + + if (this._themeTimer) { + clearTimeout(this._themeTimer); + } + + try { + const r = await fetch(this.state.customThemeUrl); + const themeInfo = await r.json(); + if (!themeInfo || typeof(themeInfo['name']) !== 'string' || typeof(themeInfo['colors']) !== 'object') { + this.setState({customThemeMessage: {text: _t("Invalid theme schema."), isError: true}}); + return; + } + currentThemes.push(themeInfo); + } catch (e) { + console.error(e); + this.setState({customThemeMessage: {text: _t("Error downloading theme information."), isError: true}}); + return; // Don't continue on error + } + + await SettingsStore.setValue("custom_themes", null, SettingLevel.ACCOUNT, currentThemes); + this.setState({customThemeUrl: "", customThemeMessage: {text: _t("Theme added!"), isError: false}}); + + this._themeTimer = setTimeout(() => { + this.setState({customThemeMessage: {text: "", isError: false}}); + }, 3000); + }; + + _onCustomThemeChange = (e) => { + this.setState({customThemeUrl: e.target.value}); + }; + _renderProfileSection() { return (
@@ -368,6 +405,45 @@ export default class GeneralUserSettingsTab extends React.Component { />
; } + + let customThemeForm; + if (SettingsStore.isFeatureEnabled("feature_custom_themes")) { + let messageElement = null; + if (this.state.customThemeMessage.text) { + if (this.state.customThemeMessage.isError) { + messageElement =
{this.state.customThemeMessage.text}
; + } else { + messageElement =
{this.state.customThemeMessage.text}
; + } + } + customThemeForm = ( +
+
+ + {_t("Add theme")} + {messageElement} + +
+ ); + } + + const themes = Object.entries(enumerateThemes()) + .map(p => ({id: p[0], name: p[1]})); // convert pairs to objects for code readability + const builtInThemes = themes.filter(p => !p.id.startsWith("custom-")); + const customThemes = themes.filter(p => !builtInThemes.includes(p)) + .sort((a, b) => a.name.localeCompare(b.name)); + const orderedThemes = [...builtInThemes, ...customThemes]; return (
{_t("Theme")} @@ -376,10 +452,11 @@ export default class GeneralUserSettingsTab extends React.Component { value={this.state.theme} onChange={this._onThemeChange} disabled={this.state.useSystemTheme} > - {Object.entries(enumerateThemes()).map(([theme, text]) => { - return ; + {orderedThemes.map(theme => { + return ; })} + {customThemeForm}
); diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.js b/src/components/views/settings/tabs/user/HelpUserSettingsTab.js index aca2f010b6..9a2db8113e 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.js @@ -24,6 +24,7 @@ import createRoom from "../../../../../createRoom"; import Modal from "../../../../../Modal"; import * as sdk from "../../../../../"; import PlatformPeg from "../../../../../PlatformPeg"; +import * as KeyboardShortcuts from "../../../../../accessibility/KeyboardShortcuts"; export default class HelpUserSettingsTab extends React.Component { static propTypes = { @@ -224,6 +225,9 @@ export default class HelpUserSettingsTab extends React.Component {
{faqText}
+ + { _t("Keyboard Shortcuts") } +
{_t("Versions")} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 5c49bc6bad..37ac1ee947 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -27,7 +27,7 @@ "Dismiss": "Dismiss", "Call Failed": "Call Failed", "There are unknown sessions in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "There are unknown sessions in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.", - "Review Devices": "Review Devices", + "Review Sessions": "Review Sessions", "Call Anyway": "Call Anyway", "Answer Anyway": "Answer Anyway", "Call": "Call", @@ -385,6 +385,7 @@ "Multiple integration managers": "Multiple integration managers", "Try out new ways to ignore people (experimental)": "Try out new ways to ignore people (experimental)", "Show a presence dot next to DMs in the room list": "Show a presence dot next to DMs in the room list", + "Support adding custom themes": "Support adding custom themes", "Enable cross-signing to verify per-user instead of per-session (in development)": "Enable cross-signing to verify per-user instead of per-session (in development)", "Enable local event indexing and E2EE search (requires restart)": "Enable local event indexing and E2EE search (requires restart)", "Show info about bridges in room settings": "Show info about bridges in room settings", @@ -708,12 +709,17 @@ "Failed to change password. Is your password correct?": "Failed to change password. Is your password correct?", "Success": "Success", "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them", + "Invalid theme schema.": "Invalid theme schema.", + "Error downloading theme information.": "Error downloading theme information.", + "Theme added!": "Theme added!", "Profile": "Profile", "Email addresses": "Email addresses", "Phone numbers": "Phone numbers", "Set a new account password...": "Set a new account password...", "Account": "Account", "Language and region": "Language and region", + "Custom theme URL": "Custom theme URL", + "Add theme": "Add theme", "Theme": "Theme", "Agree to the identity server (%(serverName)s) Terms of Service to allow yourself to be discoverable by email address or phone number.": "Agree to the identity server (%(serverName)s) Terms of Service to allow yourself to be discoverable by email address or phone number.", "Account management": "Account management", @@ -736,6 +742,7 @@ "Clear cache and reload": "Clear cache and reload", "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.": "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.", "FAQ": "FAQ", + "Keyboard Shortcuts": "Keyboard Shortcuts", "Versions": "Versions", "riot-web version:": "riot-web version:", "olm version:": "olm version:", @@ -834,7 +841,6 @@ "This room isn’t bridging messages to any platforms. Learn more.": "This room isn’t bridging messages to any platforms. Learn more.", "Bridges": "Bridges", "Room Addresses": "Room Addresses", - "Publish this room to the public in %(domain)s's room directory?": "Publish this room to the public in %(domain)s's room directory?", "URL Previews": "URL Previews", "Uploaded sound": "Uploaded sound", "Sounds": "Sounds", @@ -955,7 +961,7 @@ "Encrypted by a deleted session": "Encrypted by a deleted session", "Please select the destination room for this message": "Please select the destination room for this message", "Invite only": "Invite only", - "Scroll to bottom of page": "Scroll to bottom of page", + "Scroll to most recent messages": "Scroll to most recent messages", "Close preview": "Close preview", "device id: ": "device id: ", "Disinvite": "Disinvite", @@ -1151,16 +1157,20 @@ "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.", "Error creating alias": "Error creating alias", "There was an error creating that alias. It may not be allowed by the server or a temporary failure occurred.": "There was an error creating that alias. It may not be allowed by the server or a temporary failure occurred.", - "Error removing alias": "Error removing alias", + "You don't have permission to delete the alias.": "You don't have permission to delete the alias.", "There was an error removing that alias. It may no longer exist or a temporary error occurred.": "There was an error removing that alias. It may no longer exist or a temporary error occurred.", + "Error removing alias": "Error removing alias", "Main address": "Main address", "not specified": "not specified", "This room has no local addresses": "This room has no local addresses", - "New address (e.g. #foo:%(localDomain)s)": "New address (e.g. #foo:%(localDomain)s)", - "Alternative addresses for this room:": "Alternative addresses for this room:", - "This room has no alternative addresses": "This room has no alternative addresses", - "New address (e.g. #foo:domain)": "New address (e.g. #foo:domain)", - "Local addresses (unmoderated content)": "Local addresses (unmoderated content)", + "Local address": "Local address", + "Published Addresses": "Published Addresses", + "Published addresses can be used by anyone on any server to join your room. To publish an address, it needs to be set as a local address first.": "Published addresses can be used by anyone on any server to join your room. To publish an address, it needs to be set as a local address first.", + "Other published addresses:": "Other published addresses:", + "No other published addresses yet, add one below": "No other published addresses yet, add one below", + "New published address (e.g. #alias:server)": "New published address (e.g. #alias:server)", + "Local Addresses": "Local Addresses", + "Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)": "Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)", "Error updating flair": "Error updating flair", "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.", "Invalid community ID": "Invalid community ID", @@ -1171,6 +1181,7 @@ "Room Name": "Room Name", "Room Topic": "Room Topic", "Room avatar": "Room avatar", + "Publish this room to the public in %(domain)s's room directory?": "Publish this room to the public in %(domain)s's room directory?", "You have enabled URL previews by default.": "You have enabled URL previews by default.", "You have disabled URL previews by default.": "You have disabled URL previews by default.", "URL previews are enabled by default for participants in this room.": "URL previews are enabled by default for participants in this room.", @@ -1439,6 +1450,20 @@ "And %(count)s more...|other": "And %(count)s more...", "ex. @bob:example.com": "ex. @bob:example.com", "Add User": "Add User", + "Enter a server name": "Enter a server name", + "Looks good": "Looks good", + "Can't find this server or its room list": "Can't find this server or its room list", + "All rooms": "All rooms", + "Your server": "Your server", + "Are you sure you want to remove %(serverName)s": "Are you sure you want to remove %(serverName)s", + "Remove server": "Remove server", + "Matrix": "Matrix", + "Add a new server": "Add a new server", + "Enter the name of a new server you want to explore.": "Enter the name of a new server you want to explore.", + "Server name": "Server name", + "Add a new server...": "Add a new server...", + "%(networkName)s rooms": "%(networkName)s rooms", + "Matrix rooms": "Matrix rooms", "Matrix ID": "Matrix ID", "Matrix Room ID": "Matrix Room ID", "email address": "email address", @@ -1966,7 +1991,9 @@ "Uploading %(filename)s and %(count)s others|one": "Uploading %(filename)s and %(count)s other", "Could not load user profile": "Could not load user profile", "Complete security": "Complete security", - "Verify this session to grant it access to encrypted messages.": "Verify this session to grant it access to encrypted messages.", + "Open an existing session & use it to verify this one, granting it access to encrypted messages.": "Open an existing session & use it to verify this one, granting it access to encrypted messages.", + "Waiting…": "Waiting…", + "If you can’t access one, ": "If you can’t access one, ", "Session verified": "Session verified", "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.", "Your new session is now verified. Other users will see it as trusted.": "Your new session is now verified. Other users will see it as trusted.", @@ -2143,5 +2170,42 @@ "Message downloading sleep time(ms)": "Message downloading sleep time(ms)", "Failed to set direct chat tag": "Failed to set direct chat tag", "Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room", - "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room" + "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room", + "Navigation": "Navigation", + "Calls": "Calls", + "Room List": "Room List", + "Autocomplete": "Autocomplete", + "Alt": "Alt", + "Alt Gr": "Alt Gr", + "Shift": "Shift", + "Super": "Super", + "Ctrl": "Ctrl", + "Toggle Bold": "Toggle Bold", + "Toggle Italics": "Toggle Italics", + "Toggle Quote": "Toggle Quote", + "Toggle Markdown": "Toggle Markdown", + "New line": "New line", + "Navigate recent messages to edit": "Navigate recent messages to edit", + "Jump to start/end of the composer": "Jump to start/end of the composer", + "Toggle microphone mute": "Toggle microphone mute", + "Toggle video on/off": "Toggle video on/off", + "Jump to room search": "Jump to room search", + "Navigate up/down in the room list": "Navigate up/down in the room list", + "Select room from the room list": "Select room from the room list", + "Collapse room list section": "Collapse room list section", + "Expand room list section": "Expand room list section", + "Clear room list filter field": "Clear room list filter field", + "Scroll up/down in the timeline": "Scroll up/down in the timeline", + "Toggle the top left menu": "Toggle the top left menu", + "Close dialog or context menu": "Close dialog or context menu", + "Activate selected button": "Activate selected button", + "Toggle this dialog": "Toggle this dialog", + "Move autocomplete selection up/down": "Move autocomplete selection up/down", + "Cancel autocomplete": "Cancel autocomplete", + "Page Up": "Page Up", + "Page Down": "Page Down", + "Esc": "Esc", + "Enter": "Enter", + "Space": "Space", + "End": "End" } diff --git a/src/indexing/BaseEventIndexManager.js b/src/indexing/BaseEventIndexManager.js index 66904f9264..f780c8e9ce 100644 --- a/src/indexing/BaseEventIndexManager.js +++ b/src/indexing/BaseEventIndexManager.js @@ -123,6 +123,10 @@ export default class BaseEventIndexManager { throw new Error("Unimplemented"); } + async deleteEvent(eventId: string): Promise { + throw new Error("Unimplemented"); + } + /** * Check if our event index is empty. */ diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index c8a9a4c1fa..abd6bcab6c 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -61,6 +61,7 @@ export default class EventIndex extends EventEmitter { client.on('Room.timeline', this.onRoomTimeline); client.on('Event.decrypted', this.onEventDecrypted); client.on('Room.timelineReset', this.onTimelineReset); + client.on('Room.redaction', this.onRedaction); } /** @@ -74,6 +75,7 @@ export default class EventIndex extends EventEmitter { client.removeListener('Room.timeline', this.onRoomTimeline); client.removeListener('Event.decrypted', this.onEventDecrypted); client.removeListener('Room.timelineReset', this.onTimelineReset); + client.removeListener('Room.redaction', this.onRedaction); } /** @@ -210,6 +212,23 @@ export default class EventIndex extends EventEmitter { await this.addLiveEventToIndex(ev); } + /* + * The Room.redaction listener. + * + * Removes a redacted event from our event index. + */ + onRedaction = async (ev, room) => { + // We only index encrypted rooms locally. + if (!MatrixClientPeg.get().isRoomEncrypted(room.roomId)) return; + const indexManager = PlatformPeg.get().getEventIndexingManager(); + + try { + await indexManager.deleteEvent(ev.getAssociatedId()); + } catch (e) { + console.log("EventIndex: Error deleting event from index", e); + } + } + /* * The Room.timelineReset listener. * @@ -373,6 +392,21 @@ export default class EventIndex extends EventEmitter { checkpoint.roomId, checkpoint.token, this._eventsPerCrawl, checkpoint.direction); } catch (e) { + if (e.httpStatus === 403) { + console.log("EventIndex: Removing checkpoint as we don't have ", + "permissions to fetch messages from this room.", checkpoint); + try { + await indexManager.removeCrawlerCheckpoint(checkpoint); + } catch (e) { + console.log("EventIndex: Error removing checkpoint", checkpoint, e); + // We don't push the checkpoint here back, it will + // hopefully be removed after a restart. But let us + // ignore it for now as we don't want to hammer the + // endpoint. + } + continue; + } + console.log("EventIndex: Error crawling events:", e); this.crawlerCheckpoints.push(checkpoint); continue; @@ -431,12 +465,17 @@ export default class EventIndex extends EventEmitter { // Let us wait for all the events to get decrypted. await Promise.all(decryptionPromises); - // TODO if there are no events at this point we're missing a lot // decryption keys, do we want to retry this checkpoint at a later // stage? const filteredEvents = matrixEvents.filter(this.isValidEvent); + // Collect the redaction events so we can delete the redacted events + // from the index. + const redactionEvents = matrixEvents.filter((ev) => { + return ev.getType() === "m.room.redaction"; + }); + // Let us convert the events back into a format that EventIndex can // consume. const events = filteredEvents.map((ev) => { @@ -468,6 +507,11 @@ export default class EventIndex extends EventEmitter { ); try { + for (let i = 0; i < redactionEvents.length; i++) { + const ev = redactionEvents[i]; + await indexManager.deleteEvent(ev.getAssociatedId()); + } + const eventsAlreadyAdded = await indexManager.addHistoricEvents( events, newCheckpoint, checkpoint); // If all events were already indexed we assume that we catched @@ -520,7 +564,8 @@ export default class EventIndex extends EventEmitter { const indexManager = PlatformPeg.get().getEventIndexingManager(); this.removeListeners(); this.stopCrawler(); - return indexManager.closeEventIndex(); + await indexManager.closeEventIndex(); + return; } /** diff --git a/src/indexing/EventIndexPeg.js b/src/indexing/EventIndexPeg.js index 067aea3a7f..9aa7e78eda 100644 --- a/src/indexing/EventIndexPeg.js +++ b/src/indexing/EventIndexPeg.js @@ -135,7 +135,7 @@ class EventIndexPeg { */ async unset() { if (this.index === null) return; - this.index.close(); + await this.index.close(); this.index = null; } @@ -151,7 +151,7 @@ class EventIndexPeg { const indexManager = PlatformPeg.get().getEventIndexingManager(); if (indexManager !== null) { - this.unset(); + await this.unset(); console.log("EventIndex: Deleting event index."); await indexManager.deleteEventIndex(); } diff --git a/src/settings/Settings.js b/src/settings/Settings.js index b77fb392e9..461761dfa2 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -134,6 +134,12 @@ export const SETTINGS = { supportedLevels: LEVELS_FEATURE, default: false, }, + "feature_custom_themes": { + isFeature: true, + displayName: _td("Support adding custom themes"), + supportedLevels: LEVELS_FEATURE, + default: false, + }, "mjolnirRooms": { supportedLevels: ['account'], default: [], @@ -324,6 +330,10 @@ export const SETTINGS = { supportedLevels: ['account'], default: [], }, + "room_directory_servers": { + supportedLevels: ['account'], + default: [], + }, "integrationProvisioning": { supportedLevels: ['account'], default: true, @@ -511,4 +521,8 @@ export const SETTINGS = { displayName: _td("How fast should messages be downloaded."), default: 3000, }, + "showCallButtonsInComposer": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, + default: true, + }, }; diff --git a/src/stores/RightPanelStore.js b/src/stores/RightPanelStore.js index 1b3cb3d64b..ccdeb006f4 100644 --- a/src/stores/RightPanelStore.js +++ b/src/stores/RightPanelStore.js @@ -42,8 +42,6 @@ const GROUP_PHASES = Object.keys(RIGHT_PANEL_PHASES).filter(k => k.startsWith("G export default class RightPanelStore extends Store { static _instance; - _inhibitUpdates = false; - constructor() { super(dis); @@ -116,11 +114,6 @@ export default class RightPanelStore extends Store { } __onDispatch(payload) { - if (payload.action === 'panel_disable') { - this._inhibitUpdates = payload.rightDisabled || payload.sideDisabled || false; - return; - } - if (payload.action === 'view_room' || payload.action === 'view_group') { // Reset to the member list if we're viewing member info const memberInfoPhases = [ @@ -138,7 +131,7 @@ export default class RightPanelStore extends Store { } } - if (payload.action !== 'set_right_panel_phase' || this._inhibitUpdates) return; + if (payload.action !== 'set_right_panel_phase') return; const targetPhase = payload.phase; if (!RIGHT_PANEL_PHASES[targetPhase]) { diff --git a/src/utils/replaceableComponent.ts b/src/utils/replaceableComponent.ts index 9f617b27f3..8c29fdf037 100644 --- a/src/utils/replaceableComponent.ts +++ b/src/utils/replaceableComponent.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import * as React from 'react'; import * as sdk from '../index'; /** diff --git a/src/verification.js b/src/verification.js index 6f1bb07344..4443079b95 100644 --- a/src/verification.js +++ b/src/verification.js @@ -23,6 +23,7 @@ import {RIGHT_PANEL_PHASES} from "./stores/RightPanelStorePhases"; import {findDMForUser} from './createRoom'; import {accessSecretStorage} from './CrossSigningManager'; import SettingsStore from './settings/SettingsStore'; +import {verificationMethods} from 'matrix-js-sdk/src/crypto'; async function enable4SIfNeeded() { const cli = MatrixClientPeg.get(); @@ -57,9 +58,10 @@ export async function verifyDevice(user, device) { return; } const cli = MatrixClientPeg.get(); - const verificationRequestPromise = cli.requestVerification( + const verificationRequestPromise = cli.legacyDeviceVerification( user.userId, - [device.deviceId], + device.deviceId, + verificationMethods.SAS, ); dis.dispatch({ action: "set_right_panel_phase", @@ -77,7 +79,7 @@ export async function legacyVerifyUser(user) { return; } const cli = MatrixClientPeg.get(); - const verificationRequestPromise = cli.requestVerification(user.userId); + const verificationRequestPromise = cli.beginKeyVerification(user.userId); dis.dispatch({ action: "set_right_panel_phase", phase: RIGHT_PANEL_PHASES.EncryptionPanel, diff --git a/tsconfig.json b/tsconfig.json index ec1531e429..d70e0a85f0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,11 +9,14 @@ "sourceMap": false, "outDir": "./lib", "declaration": true, + "jsx": "react", "types": [ - "node" + "node", + "react" ] }, "include": [ - "./src/**/*.ts" + "./src/**/*.ts", + "./src/**/*.tsx" ] } diff --git a/yarn.lock b/yarn.lock index f6c4915a84..d0934ffc31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25,27 +25,27 @@ dependencies: "@babel/highlight" "^7.8.3" -"@babel/compat-data@^7.8.4": - version "7.8.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.8.5.tgz#d28ce872778c23551cbb9432fc68d28495b613b9" - integrity sha512-jWYUqQX/ObOhG1UiEkbH5SANsE/8oKXiQWjj7p7xgj9Zmnt//aUvyz4dBkK0HNsS8/cbyC5NmmH87VekW+mXFg== +"@babel/compat-data@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.8.6.tgz#7eeaa0dfa17e50c7d9c0832515eee09b56f04e35" + integrity sha512-CurCIKPTkS25Mb8mz267vU95vy+TyUpnctEX2lV33xWNmHAfjruztgiPBbXZRh3xZZy1CYvGx6XfxyTVS+sk7Q== dependencies: browserslist "^4.8.5" invariant "^2.2.4" semver "^5.5.0" "@babel/core@>=7.2.2", "@babel/core@^7.1.0", "@babel/core@^7.7.5": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e" - integrity sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA== + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.7.tgz#b69017d221ccdeb203145ae9da269d72cf102f3b" + integrity sha512-rBlqF3Yko9cynC5CCFy6+K/w2N+Sq/ff2BPy+Krp7rHlABIr5epbA7OxVeKoMHB39LZOp1UY5SuLjy6uWi35yA== dependencies: "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.4" + "@babel/generator" "^7.8.7" "@babel/helpers" "^7.8.4" - "@babel/parser" "^7.8.4" - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.4" - "@babel/types" "^7.8.3" + "@babel/parser" "^7.8.7" + "@babel/template" "^7.8.6" + "@babel/traverse" "^7.8.6" + "@babel/types" "^7.8.7" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" @@ -55,12 +55,12 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.4.0", "@babel/generator@^7.8.3", "@babel/generator@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e" - integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA== +"@babel/generator@^7.4.0", "@babel/generator@^7.8.3", "@babel/generator@^7.8.6", "@babel/generator@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.7.tgz#870b3cf7984f5297998152af625c4f3e341400f7" + integrity sha512-DQwjiKJqH4C3qGiyQCAExJHoZssn49JTMJgZ8SANGgVFdkupcUhLOdkAeoC6kmHZCPfoDG5M0b6cFlSN5wW7Ew== dependencies: - "@babel/types" "^7.8.3" + "@babel/types" "^7.8.7" jsesc "^2.5.1" lodash "^4.17.13" source-map "^0.5.0" @@ -88,43 +88,44 @@ "@babel/types" "^7.8.3" esutils "^2.0.0" -"@babel/helper-call-delegate@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692" - integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A== +"@babel/helper-call-delegate@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.7.tgz#28a279c2e6c622a6233da548127f980751324cab" + integrity sha512-doAA5LAKhsFCR0LAFIf+r2RSMmC+m8f/oQ+URnUET/rWeEzC0yTRmAGyWkD4sSu3xwbS7MYQ2u+xlt1V5R56KQ== dependencies: "@babel/helper-hoist-variables" "^7.8.3" "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/types" "^7.8.7" -"@babel/helper-compilation-targets@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.4.tgz#03d7ecd454b7ebe19a254f76617e61770aed2c88" - integrity sha512-3k3BsKMvPp5bjxgMdrFyq0UaEO48HciVrOVF0+lon8pp95cyJ2ujAh0TrBHNMnJGT2rr0iKOJPFFbSqjDyf/Pg== +"@babel/helper-compilation-targets@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz#dac1eea159c0e4bd46e309b5a1b04a66b53c1dde" + integrity sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw== dependencies: - "@babel/compat-data" "^7.8.4" - browserslist "^4.8.5" + "@babel/compat-data" "^7.8.6" + browserslist "^4.9.1" invariant "^2.2.4" levenary "^1.1.1" semver "^5.5.0" "@babel/helper-create-class-features-plugin@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz#5b94be88c255f140fd2c10dd151e7f98f4bff397" - integrity sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA== + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.6.tgz#243a5b46e2f8f0f674dc1387631eb6b28b851de0" + integrity sha512-klTBDdsr+VFFqaDHm5rR69OpEQtO2Qv8ECxHS1mNhJJvaHArR6a1xTf5K/eZW7eZpJbhCx3NW1Yt/sKsLXLblg== dependencies: "@babel/helper-function-name" "^7.8.3" "@babel/helper-member-expression-to-functions" "^7.8.3" "@babel/helper-optimise-call-expression" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" "@babel/helper-split-export-declaration" "^7.8.3" "@babel/helper-create-regexp-features-plugin@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz#c774268c95ec07ee92476a3862b75cc2839beb79" - integrity sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q== + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.6.tgz#7fa040c97fb8aebe1247a5c645330c32d083066b" + integrity sha512-bPyujWfsHhV/ztUkwGHz/RPV1T1TDEsSZDsN42JPehndA+p1KKTh3npvTadux0ZhCrytx9tvjpWNowKby3tM6A== dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" "@babel/helper-regex" "^7.8.3" regexpu-core "^4.6.0" @@ -183,15 +184,16 @@ "@babel/types" "^7.8.3" "@babel/helper-module-transforms@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590" - integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q== + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.6.tgz#6a13b5eecadc35692047073a64e42977b97654a4" + integrity sha512-RDnGJSR5EFBJjG3deY0NiL0K9TO8SXxS9n/MPsbPK/s9LbQymuLNtlzvDiNS7IpecuL45cMeLVkA+HfmlrnkRg== dependencies: "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" "@babel/helper-simple-access" "^7.8.3" "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/template" "^7.8.6" + "@babel/types" "^7.8.6" lodash "^4.17.13" "@babel/helper-optimise-call-expression@^7.8.3": @@ -224,15 +226,15 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helper-replace-supers@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc" - integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA== +"@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" + integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== dependencies: "@babel/helper-member-expression-to-functions" "^7.8.3" "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/traverse" "^7.8.6" + "@babel/types" "^7.8.6" "@babel/helper-simple-access@^7.8.3": version "7.8.3" @@ -277,10 +279,10 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.7.0", "@babel/parser@^7.8.3", "@babel/parser@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8" - integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw== +"@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.7.0", "@babel/parser@^7.8.6", "@babel/parser@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.7.tgz#7b8facf95d25fef9534aad51c4ffecde1a61e26a" + integrity sha512-9JWls8WilDXFGxs0phaXAZgpxTZhSk/yOYH2hTHC0X1yC7Z78IJfvR1vJ+rmJKq3I35td2XzXzN6ZLYlna+r/A== "@babel/plugin-proposal-async-generator-functions@^7.8.3": version "7.8.3" @@ -509,17 +511,17 @@ "@babel/helper-plugin-utils" "^7.8.3" lodash "^4.17.13" -"@babel/plugin-transform-classes@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8" - integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w== +"@babel/plugin-transform-classes@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.6.tgz#77534447a477cbe5995ae4aee3e39fbc8090c46d" + integrity sha512-k9r8qRay/R6v5aWZkrEclEhKO6mc1CCQr2dLsVHBmOQiMpN6I2bpjX3vgnldUWeEI1GHVNByULVxZ4BdP4Hmdg== dependencies: "@babel/helper-annotate-as-pure" "^7.8.3" "@babel/helper-define-map" "^7.8.3" "@babel/helper-function-name" "^7.8.3" "@babel/helper-optimise-call-expression" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" "@babel/helper-split-export-declaration" "^7.8.3" globals "^11.1.0" @@ -577,10 +579,10 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-flow" "^7.8.3" -"@babel/plugin-transform-for-of@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz#6fe8eae5d6875086ee185dd0b098a8513783b47d" - integrity sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A== +"@babel/plugin-transform-for-of@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.6.tgz#a051bd1b402c61af97a27ff51b468321c7c2a085" + integrity sha512-M0pw4/1/KI5WAxPsdcUL/w2LJ7o89YHN3yLkzNjg7Yl15GlVGgzHyCU+FMeAxevHGsLVmUqbirlUIKTafPmzdw== dependencies: "@babel/helper-plugin-utils" "^7.8.3" @@ -665,12 +667,12 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/helper-replace-supers" "^7.8.3" -"@babel/plugin-transform-parameters@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.4.tgz#1d5155de0b65db0ccf9971165745d3bb990d77d3" - integrity sha512-IsS3oTxeTsZlE5KqzTbcC2sV0P9pXdec53SU+Yxv7o/6dvGM5AkTotQKhoSffhNgZ/dftsSiOoxy7evCYJXzVA== +"@babel/plugin-transform-parameters@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.7.tgz#66fa2f1de4129b4e0447509223ac71bda4955395" + integrity sha512-brYWaEPTRimOctz2NDA3jnBbDi7SVN2T4wYuu0aqSzxC3nozFZngGaw29CJ9ZPweB7k+iFmZuoG3IVPIcXmD2g== dependencies: - "@babel/helper-call-delegate" "^7.8.3" + "@babel/helper-call-delegate" "^7.8.7" "@babel/helper-get-function-arity" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" @@ -713,12 +715,12 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-jsx" "^7.8.3" -"@babel/plugin-transform-regenerator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8" - integrity sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA== +"@babel/plugin-transform-regenerator@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" + integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== dependencies: - regenerator-transform "^0.14.0" + regenerator-transform "^0.14.2" "@babel/plugin-transform-reserved-words@^7.8.3": version "7.8.3" @@ -775,9 +777,9 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-transform-typescript@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.8.3.tgz#be6f01a7ef423be68e65ace1f04fc407e6d88917" - integrity sha512-Ebj230AxcrKGZPKIp4g4TdQLrqX95TobLUWKd/CwG7X1XHUH1ZpkpFvXuXqWbtGRWb7uuEWNlrl681wsOArAdQ== + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.8.7.tgz#48bccff331108a7b3a28c3a4adc89e036dc3efda" + integrity sha512-7O0UsPQVNKqpHeHLpfvOG4uXmlw+MOxYvUv6Otc9uH5SYMIxvF6eBdjkWvC3f9G+VXe0RsNExyAQBeTRug/wqQ== dependencies: "@babel/helper-create-class-features-plugin" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" @@ -792,12 +794,12 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/preset-env@^7.7.6": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.4.tgz#9dac6df5f423015d3d49b6e9e5fa3413e4a72c4e" - integrity sha512-HihCgpr45AnSOHRbS5cWNTINs0TwaR8BS8xIIH+QwiW8cKL0llV91njQMpeMReEPVs+1Ao0x3RLEBLtt1hOq4w== + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.7.tgz#1fc7d89c7f75d2d70c2b6768de6c2e049b3cb9db" + integrity sha512-BYftCVOdAYJk5ASsznKAUl53EMhfBbr8CJ1X+AJLfGPscQkwJFiaV/Wn9DPH/7fzm2v6iRYJKYHSqyynTGw0nw== dependencies: - "@babel/compat-data" "^7.8.4" - "@babel/helper-compilation-targets" "^7.8.4" + "@babel/compat-data" "^7.8.6" + "@babel/helper-compilation-targets" "^7.8.7" "@babel/helper-module-imports" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-proposal-async-generator-functions" "^7.8.3" @@ -820,13 +822,13 @@ "@babel/plugin-transform-async-to-generator" "^7.8.3" "@babel/plugin-transform-block-scoped-functions" "^7.8.3" "@babel/plugin-transform-block-scoping" "^7.8.3" - "@babel/plugin-transform-classes" "^7.8.3" + "@babel/plugin-transform-classes" "^7.8.6" "@babel/plugin-transform-computed-properties" "^7.8.3" "@babel/plugin-transform-destructuring" "^7.8.3" "@babel/plugin-transform-dotall-regex" "^7.8.3" "@babel/plugin-transform-duplicate-keys" "^7.8.3" "@babel/plugin-transform-exponentiation-operator" "^7.8.3" - "@babel/plugin-transform-for-of" "^7.8.4" + "@babel/plugin-transform-for-of" "^7.8.6" "@babel/plugin-transform-function-name" "^7.8.3" "@babel/plugin-transform-literals" "^7.8.3" "@babel/plugin-transform-member-expression-literals" "^7.8.3" @@ -837,9 +839,9 @@ "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" "@babel/plugin-transform-new-target" "^7.8.3" "@babel/plugin-transform-object-super" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.8.4" + "@babel/plugin-transform-parameters" "^7.8.7" "@babel/plugin-transform-property-literals" "^7.8.3" - "@babel/plugin-transform-regenerator" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.7" "@babel/plugin-transform-reserved-words" "^7.8.3" "@babel/plugin-transform-shorthand-properties" "^7.8.3" "@babel/plugin-transform-spread" "^7.8.3" @@ -847,7 +849,7 @@ "@babel/plugin-transform-template-literals" "^7.8.3" "@babel/plugin-transform-typeof-symbol" "^7.8.4" "@babel/plugin-transform-unicode-regex" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/types" "^7.8.7" browserslist "^4.8.5" core-js-compat "^3.6.2" invariant "^2.2.2" @@ -882,9 +884,9 @@ "@babel/plugin-transform-typescript" "^7.8.3" "@babel/register@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.8.3.tgz#5d5d30cfcc918437535d724b8ac1e4a60c5db1f8" - integrity sha512-t7UqebaWwo9nXWClIPLPloa5pN33A2leVs8Hf0e9g9YwUP8/H9NeR7DJU+4CXo23QtjChQv5a3DjEtT83ih1rg== + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.8.6.tgz#a1066aa6168a73a70c35ef28cc5865ccc087ea69" + integrity sha512-7IDO93fuRsbyml7bAafBQb3RcBGlCpU4hh5wADA2LJEEcYk92WkwFZ0pHyIi2fb5Auoz1714abETdZKCOxN0CQ== dependencies: find-cache-dir "^2.0.0" lodash "^4.17.13" @@ -892,41 +894,49 @@ pirates "^4.0.0" source-map-support "^0.5.16" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.8.3": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.4.tgz#d79f5a2040f7caa24d53e563aad49cbc05581308" - integrity sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ== +"@babel/runtime-corejs3@^7.8.3": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.8.7.tgz#8209d9dff2f33aa2616cb319c83fe159ffb07b8c" + integrity sha512-sc7A+H4I8kTd7S61dgB9RomXu/C+F4IrRr4Ytze4dnfx7AXEpCrejSNpjx7vq6y/Bak9S6Kbk65a/WgMLtg43Q== dependencies: - regenerator-runtime "^0.13.2" + core-js-pure "^3.0.0" + regenerator-runtime "^0.13.4" -"@babel/template@^7.4.0", "@babel/template@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" - integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.7.tgz#8fefce9802db54881ba59f90bb28719b4996324d" + integrity sha512-+AATMUFppJDw6aiR5NVPHqIQBlV/Pj8wY/EZH+lmvRdUo9xBaz/rF3alAwFJQavvKfeOlPE7oaaDHVbcySbCsg== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.4.0", "@babel/template@^7.8.3", "@babel/template@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" + integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== dependencies: "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/parser" "^7.8.6" + "@babel/types" "^7.8.6" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.4.tgz#f0845822365f9d5b0e312ed3959d3f827f869e3c" - integrity sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg== +"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4", "@babel/traverse@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.6.tgz#acfe0c64e1cd991b3e32eae813a6eb564954b5ff" + integrity sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A== dependencies: "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.4" + "@babel/generator" "^7.8.6" "@babel/helper-function-name" "^7.8.3" "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.8.4" - "@babel/types" "^7.8.3" + "@babel/parser" "^7.8.6" + "@babel/types" "^7.8.6" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.13" -"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.7.0", "@babel/types@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" - integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg== +"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.7.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.7.tgz#1fc9729e1acbb2337d5b6977a63979b4819f5d1d" + integrity sha512-k2TreEHxFA4CjGkL+GYjRyx35W0Mr7DP5+9q6WMkyKXB+904bYmG40syjMFV0oLlhhFCwWl0vA0DyzTDkwAiJw== dependencies: esutils "^2.0.2" lodash "^4.17.13" @@ -1109,7 +1119,7 @@ asn1js "^2.0.22" tslib "^1.9.3" -"@peculiar/json-schema@^1.1.6": +"@peculiar/json-schema@^1.1.9": version "1.1.9" resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.9.tgz#b746e046b787607a1b2804f64437fda2527b3e62" integrity sha512-F2ST2y/IQPgY+1QMw1Q33sqJbGDCeO3lGqI69SL3Hgo0++7iHqprUB1QyxB/A7bN3tuM65MBxoM2JLbwh42lsQ== @@ -1117,15 +1127,15 @@ tslib "^1.10.0" "@peculiar/webcrypto@^1.0.22": - version "1.0.22" - resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.0.22.tgz#9dae652fce6bacd9df15bc91965797cee33adf67" - integrity sha512-NP6H6ZGXUvJnQJCWzUgnRcQv+9nMCNwLUDhTwOxRUwPFvtHauMOl0oPTKUjbhInCMaE55gJqB4yc0YKbde6Exw== + version "1.0.23" + resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.0.23.tgz#5519b839fba2cf8603bbbd6764dc41b108093dad" + integrity sha512-Ssb4xpQI3BJ0itAtT9y9jyeeiWNjcFvP6Wt/ehITxRYrEnlSfnrP7Ytc7BwN8XtnKmXDS2cWvppPldw5QsFCcw== dependencies: "@peculiar/asn1-schema" "^1.0.3" - "@peculiar/json-schema" "^1.1.6" + "@peculiar/json-schema" "^1.1.9" asn1js "^2.0.26" pvtsutils "^1.0.9" - tslib "^1.10.0" + tslib "^1.11.1" webcrypto-core "^1.0.17" "@sinonjs/commons@^1.7.0": @@ -1168,6 +1178,11 @@ dependencies: "@babel/types" "^7.3.0" +"@types/classnames@^2.2.10": + version "2.2.10" + resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.10.tgz#cc658ca319b6355399efc1f5b9e818f1a24bf999" + integrity sha512-1UzDldn9GfYYEsWWnn/P4wkTlkZDH7lDb0wBMGbtIQc9zXEQq7FlKBdZUn6OBqD8sKZZ2RQO2mAjGpXiDGoRmQ== + "@types/events@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" @@ -1213,9 +1228,22 @@ integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== "@types/node@*": - version "13.7.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.6.tgz#cb734a7c191472ae6a2b3a502b4dfffcea974113" - integrity sha512-eyK7MWD0R1HqVTp+PtwRgFeIsemzuj4gBFSQxfPHY5iMjS7474e5wq+VFgTcdpyHeNxyKSaetYAjdMLJlKoWqA== + version "13.9.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.0.tgz#5b6ee7a77faacddd7de719017d0bc12f52f81589" + integrity sha512-0ARSQootUG1RljH2HncpsY2TJBfGQIKOOi7kxzUY6z54ePu/ZD+wJA8zI2Q6v8rol2qpG/rvqsReco8zNMPvhQ== + +"@types/prop-types@*": + version "15.7.3" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" + integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== + +"@types/react@16.9": + version "16.9.23" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.23.tgz#1a66c6d468ba11a8943ad958a8cb3e737568271c" + integrity sha512-SsGVT4E7L2wLN3tPYLiF20hmZTPGuzaayVunfgXzUn1x4uHVsKH6QDJQ/TdpHqwsTLd4CwrmQ2vOgxN7gE24gw== + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" "@types/stack-utils@^1.0.1": version "1.0.1" @@ -1256,18 +1284,18 @@ "@types/yargs-parser" "*" "@typescript-eslint/experimental-utils@^2.5.0": - version "2.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.21.0.tgz#71de390a3ec00b280b69138d80733406e6e86bfa" - integrity sha512-olKw9JP/XUkav4lq0I7S1mhGgONJF9rHNhKFn9wJlpfRVjNo3PPjSvybxEldvCXnvD+WAshSzqH5cEjPp9CsBA== + version "2.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.23.0.tgz#5d2261c8038ec1698ca4435a8da479c661dc9242" + integrity sha512-OswxY59RcXH3NNPmq+4Kis2CYZPurRU6mG5xPcn24CjFyfdVli5mySwZz/g/xDbJXgDsYqNGq7enV0IziWGXVQ== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.21.0" + "@typescript-eslint/typescript-estree" "2.23.0" eslint-scope "^5.0.0" -"@typescript-eslint/typescript-estree@2.21.0": - version "2.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.21.0.tgz#7e4be29f2e338195a2e8c818949ed0ff727cc943" - integrity sha512-NC/nogZNb9IK2MEFQqyDBAciOT8Lp8O3KgAfvHx2Skx6WBo+KmDqlU3R9KxHONaijfTIKtojRe3SZQyMjr3wBw== +"@typescript-eslint/typescript-estree@2.23.0": + version "2.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.23.0.tgz#d355960fab96bd550855488dcc34b9a4acac8d36" + integrity sha512-pmf7IlmvXdlEXvE/JWNNJpEvwBV59wtJqA8MLAxMKLXNKVRC3HZBXR/SlZLPWTCcwOSg9IM7GeRSV3SIerGVqw== dependencies: debug "^4.1.1" eslint-visitor-keys "^1.1.0" @@ -1457,14 +1485,14 @@ acorn-walk@^6.0.1: integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== acorn@^5.5.3: - version "5.7.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" - integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== + version "5.7.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" + integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== acorn@^6.0.1, acorn@^6.0.7, acorn@^6.2.1: - version "6.4.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784" - integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw== + version "6.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" + integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== agent-base@4, agent-base@^4.3.0: version "4.3.0" @@ -1951,10 +1979,10 @@ browser-encrypt-attachment@^0.3.0: resolved "https://registry.yarnpkg.com/browser-encrypt-attachment/-/browser-encrypt-attachment-0.3.0.tgz#205a94caadf0dc7e81413941812f655bd190ff1c" integrity sha1-IFqUyq3w3H6BQTlBgS9lW9GQ/xw= -browser-process-hrtime@^0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz#616f00faef1df7ec1b5bf9cfe2bdc3170f26c7b4" - integrity sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw== +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== browser-request@^0.3.3: version "0.3.3" @@ -2027,14 +2055,14 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.8.3, browserslist@^4.8.5: - version "4.8.7" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.7.tgz#ec8301ff415e6a42c949d0e66b405eb539c532d0" - integrity sha512-gFOnZNYBHrEyUML0xr5NJ6edFaaKbTFX9S9kQHlYfCP0Rit/boRIz4G+Avq6/4haEKJXdGGUnoolx+5MWW2BoA== +browserslist@^4.8.3, browserslist@^4.8.5, browserslist@^4.9.1: + version "4.9.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.9.1.tgz#01ffb9ca31a1aef7678128fc6a2253316aa7287c" + integrity sha512-Q0DnKq20End3raFulq6Vfp1ecB9fh8yUNV55s8sekaDDeqBaCtWlRHCUdaWyUeSSBJM7IbM6HcsyaeYqgeDhnw== dependencies: - caniuse-lite "^1.0.30001027" - electron-to-chromium "^1.3.349" - node-releases "^1.1.49" + caniuse-lite "^1.0.30001030" + electron-to-chromium "^1.3.363" + node-releases "^1.1.50" bs58@^4.0.1: version "4.0.1" @@ -2088,9 +2116,9 @@ buffer@^4.3.0: isarray "^1.0.0" buffer@^5.4.3: - version "5.4.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115" - integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A== + version "5.5.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.5.0.tgz#9c3caa3d623c33dd1c7ef584b89b88bf9c9bc1ce" + integrity sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww== dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -2189,10 +2217,10 @@ camelcase@^5.0.0, camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001027: - version "1.0.30001030" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001030.tgz#78076c4c6d67d3e41d6eb9399853fb27fe6e44ee" - integrity sha512-QGK0W4Ft/Ac+zTjEiRJfwDNATvS3fodDczBXrH42784kcfqcDKpEPfN08N0HQjrAp8He/Jw8QiSS9QRn7XAbUw== +caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001030: + version "1.0.30001033" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001033.tgz#60c328fb56860de60f9a2cb419c31fb80587cba0" + integrity sha512-8Ibzxee6ibc5q88cM1usPsMpJOG5CTq0s/dKOmlekPbDGKt+UrnOOTPSjQz3kVo6yL7N4SB5xd+FGLHQmbzh6A== capture-exit@^2.0.0: version "2.0.0" @@ -2523,6 +2551,11 @@ core-js-compat@^3.6.2: browserslist "^4.8.3" semver "7.0.0" +core-js-pure@^3.0.0: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.4.tgz#4bf1ba866e25814f149d4e9aaa08c36173506e3a" + integrity sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw== + core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" @@ -2664,6 +2697,11 @@ cssstyle@^1.0.0: dependencies: cssom "0.3.x" +csstype@^2.2.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.9.tgz#05141d0cd557a56b8891394c1911c40c8a98d098" + integrity sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q== + currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -2987,10 +3025,10 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" -electron-to-chromium@^1.3.349: - version "1.3.361" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.361.tgz#a820bf52da171c0024314745462cfe0dc944373e" - integrity sha512-OzSVjWpsRhJyr9PSAXkeloSe6e9viU2ToGt1wXlXFsGcxuI9vlsnalL+V/AM59Z2pEo3wRxIddtOGsT7Y6x/sQ== +electron-to-chromium@^1.3.363: + version "1.3.375" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.375.tgz#e290d59d316024e5499057944c10d05c518b7a24" + integrity sha512-zmaFnYVBtfpF8bGRYxgPeVAlXB7N3On8rjBE2ROc6wOpTPpzRWaiHo6KkbJMvlH07CH33uks/TEb6kuMMn8q6A== elliptic@^6.0.0: version "6.5.2" @@ -3252,21 +3290,21 @@ eslint-plugin-flowtype@^2.30.0: lodash "^4.17.10" eslint-plugin-jest@^23.0.4: - version "23.8.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.8.0.tgz#c978f959fa8395801742d13c5a3125a986d2661e" - integrity sha512-DKXmLxguZ1Lru4u5YM12ko3WLq6gqo7dhV2b63K731+/PNyZ/Ff6NGONQsGUtPLG9zU3kdz/N+2LTbweNZifeg== + version "23.8.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.8.2.tgz#6f28b41c67ef635f803ebd9e168f6b73858eb8d4" + integrity sha512-xwbnvOsotSV27MtAe7s8uGWOori0nUsrXh2f1EnpmXua8sDfY6VZhHAhHg2sqK7HBNycRQExF074XSZ7DvfoFg== dependencies: "@typescript-eslint/experimental-utils" "^2.5.0" eslint-plugin-react-hooks@^2.0.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.4.0.tgz#db6ee1cc953e3a217035da3d4e9d4356d3c672a4" - integrity sha512-bH5DOCP6WpuOqNaux2BlaDCrSgv8s5BitP90bTgtZ1ZsRn2bdIfeMDY5F2RnJVnyKDy6KRQRDbipPLZ1y77QtQ== + version "2.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.5.0.tgz#c50ab7ca5945ce6d1cf8248d9e185c80b54171b6" + integrity sha512-bzvdX47Jx847bgAYf0FPX3u1oxU+mKU8tqrpj4UX9A96SbAmj/HVEefEy6rJUog5u8QIlOPTKZcBpGn5kkKfAQ== eslint-plugin-react@^7.7.0: - version "7.18.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.18.3.tgz#8be671b7f6be095098e79d27ac32f9580f599bc8" - integrity sha512-Bt56LNHAQCoou88s8ViKRjMB2+36XRejCQ1VoLj716KI1MoE99HpTVvIThJ0rvFmG4E4Gsq+UgToEjn+j044Bg== + version "7.19.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz#6d08f9673628aa69c5559d33489e855d83551666" + integrity sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ== dependencies: array-includes "^3.1.1" doctrine "^2.1.0" @@ -3276,8 +3314,10 @@ eslint-plugin-react@^7.7.0: object.fromentries "^2.0.2" object.values "^1.1.1" prop-types "^15.7.2" - resolve "^1.14.2" + resolve "^1.15.1" + semver "^6.3.0" string.prototype.matchall "^4.0.2" + xregexp "^4.3.0" eslint-rule-composer@^0.3.0: version "0.3.0" @@ -3867,10 +3907,6 @@ fuse.js@^2.2.0: resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-2.7.4.tgz#96e420fde7ef011ac49c258a621314fe576536f9" integrity sha1-luQg/efvARrEnCWKYhMU/ldlNvk= -"gemini-scrollbar@github:matrix-org/gemini-scrollbar#91e1e566", gemini-scrollbar@matrix-org/gemini-scrollbar#91e1e566: - version "1.4.3" - resolved "https://codeload.github.com/matrix-org/gemini-scrollbar/tar.gz/91e1e566fa33324188f278801baf4a79f9f554ab" - gensync@^1.0.0-beta.1: version "1.0.0-beta.1" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" @@ -4158,9 +4194,9 @@ hosted-git-info@3.0.0: lru-cache "^5.1.1" hosted-git-info@^2.1.4: - version "2.8.6" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.6.tgz#3a6e6d0324c5371fc8c7ba7175e1e5d14578724d" - integrity sha512-Kp6rShEsCHhF5dD3EWKdkgVA8ix90oSUJ0VY4g9goxxa0+f4lx63muTftn0mlJ/+8IESGWyKnP//V2D7S4ZbIQ== + version "2.8.8" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== html-element-map@^1.2.0: version "1.2.0" @@ -5654,8 +5690,8 @@ mathml-tag-names@^2.0.1: integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== "matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": - version "5.1.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/86304fd037ac43a493000fa42f393eaafc0480ac" + version "5.1.1" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/b2e154377a4268441a3b27b183dd7f7018187035" dependencies: "@babel/runtime" "^7.8.3" another-json "^0.2.0" @@ -5840,11 +5876,16 @@ minimist@1.1.x: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" integrity sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag= -minimist@1.2.0, minimist@^1.1.1, minimist@^1.2.0, "minimist@~ 1.2.0": +minimist@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +minimist@^1.1.1, minimist@^1.2.0, "minimist@~ 1.2.0": + version "1.2.3" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.3.tgz#3db5c0765545ab8637be71f333a104a965a9ca3f" + integrity sha512-+bMdgqjMN/Z77a6NlY/I3U5LlRDbnmaAk6lDveAPKwSpcPM4tKAuYsvYF8xjhOPXhOYGe/73vVLVez5PW+jqhw== + mississippi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" @@ -6023,10 +6064,10 @@ node-notifier@^5.4.2: shellwords "^0.1.1" which "^1.3.0" -node-releases@^1.1.49: - version "1.1.50" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.50.tgz#803c40d2c45db172d0410e4efec83aa8c6ad0592" - integrity sha512-lgAmPv9eYZ0bGwUYAKlr8MG6K4CvWliWqnkcT2P8mMAgVrH3lqfBPorFlxiG1pHQnqmavJZ9vbMXUTNyMLbrgQ== +node-releases@^1.1.50: + version "1.1.51" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.51.tgz#70d0e054221343d2966006bfbd4d98622cc00bd0" + integrity sha512-1eQEs6HFYY1kMXQPOLzCf7HdjReErmvn85tZESMczdCNVWP3Y7URYLBAyYynuI7yef1zj4HN5q+oB2x67QU0lw== dependencies: semver "^6.3.0" @@ -6631,7 +6672,7 @@ pretty-format@^24.9.0: ansi-styles "^3.2.0" react-is "^16.8.4" -private@^0.1.6: +private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== @@ -6902,14 +6943,14 @@ react-clientside-effect@^1.2.2: "@babel/runtime" "^7.0.0" react-dom@^16.9.0: - version "16.12.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.12.0.tgz#0da4b714b8d13c2038c9396b54a92baea633fe11" - integrity sha512-LMxFfAGrcS3kETtQaCkTKjMiifahaMySFDn71fZUNpPHZQEzmk/GiAeIT8JSOrHB23fnuCOMruL2a8NYlw+8Gw== + version "16.13.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.0.tgz#cdde54b48eb9e8a0ca1b3dc9943d9bb409b81866" + integrity sha512-y09d2c4cG220DzdlFkPTnVvGTszVvNpC73v+AaLGLHbkpy3SSgvYq8x0rNwPJ/Rk/CicTNgk0hbHNw1gMEZAXg== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" prop-types "^15.6.2" - scheduler "^0.18.0" + scheduler "^0.19.0" react-focus-lock@^2.2.1: version "2.2.1" @@ -6923,16 +6964,10 @@ react-focus-lock@^2.2.1: use-callback-ref "^1.2.1" use-sidecar "^1.0.1" -"react-gemini-scrollbar@github:matrix-org/react-gemini-scrollbar#9cf17f63b7c0b0ec5f31df27da0f82f7238dc594": - version "2.1.5" - resolved "https://codeload.github.com/matrix-org/react-gemini-scrollbar/tar.gz/9cf17f63b7c0b0ec5f31df27da0f82f7238dc594" - dependencies: - gemini-scrollbar matrix-org/gemini-scrollbar#91e1e566 - react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0: - version "16.12.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" - integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== + version "16.13.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.0.tgz#0f37c3613c34fe6b37cd7f763a0d6293ab15c527" + integrity sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA== react-lifecycles-compat@^3.0.0: version "3.0.4" @@ -6962,14 +6997,14 @@ react-redux@^5.0.6: react-lifecycles-compat "^3.0.0" react-test-renderer@^16.0.0-0, react-test-renderer@^16.9.0: - version "16.12.0" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.12.0.tgz#11417ffda579306d4e841a794d32140f3da1b43f" - integrity sha512-Vj/teSqt2oayaWxkbhQ6gKis+t5JrknXfPVo+aIJ8QwYAqMPH77uptOdrlphyxl8eQI/rtkOYg86i/UWkpFu0w== + version "16.13.0" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.0.tgz#39ba3bf72cedc8210c3f81983f0bb061b14a3014" + integrity sha512-NQ2S9gdMUa7rgPGpKGyMcwl1d6D9MCF0lftdI3kts6kkiX+qvpC955jNjAZXlIDTjnN9jwFI8A8XhRh/9v0spA== dependencies: object-assign "^4.1.1" prop-types "^15.6.2" react-is "^16.8.6" - scheduler "^0.18.0" + scheduler "^0.19.0" react-transition-group@^1.2.0: version "1.2.1" @@ -6983,9 +7018,9 @@ react-transition-group@^1.2.0: warning "^3.0.0" react@^16.9.0: - version "16.12.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.12.0.tgz#0c0a9c6a142429e3614834d5a778e18aa78a0b83" - integrity sha512-fglqy3k5E+81pA8s+7K0/T3DBCF0ZDOher1elBFzF7O6arXJgzyu/FW+COxFvAWXJoJN9KIZbT2LXlukwphYTA== + version "16.13.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.13.0.tgz#d046eabcdf64e457bbeed1e792e235e1b9934cf7" + integrity sha512-TSavZz2iSLkq5/oiE7gnFzmURKZMltmi193rm5HEoUDAXpzT9Kzw6oNZnGoai/4+fUnm7FqS5dwgUL34TujcWQ== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -7115,17 +7150,18 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.13.2: - version "0.13.3" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" - integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== +regenerator-runtime@^0.13.4: + version "0.13.4" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz#e96bf612a3362d12bb69f7e8f74ffeab25c7ac91" + integrity sha512-plpwicqEzfEyTQohIKktWigcLzmNStMGwbOUbykx51/29Z3JOGYldaaNGK7ngNXV+UcoqvIMmloZ48Sr74sd+g== -regenerator-transform@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" - integrity sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ== +regenerator-transform@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.2.tgz#949d9d87468ff88d5a7e4734ebb994a892de1ff2" + integrity sha512-V4+lGplCM/ikqi5/mkkpJ06e9Bujq1NFmNLvsCs56zg3ZbzrnUzAtizZ24TXxtRX/W2jcdScwQCnbL0CICTFkQ== dependencies: - private "^0.1.6" + "@babel/runtime" "^7.8.4" + private "^0.1.8" regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" @@ -7174,9 +7210,9 @@ regjsgen@^0.5.0: integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== regjsparser@^0.6.0: - version "0.6.3" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.3.tgz#74192c5805d35e9f5ebe3c1fb5b40d40a8a38460" - integrity sha512-8uZvYbnfAtEm9Ab8NTb3hdLwL4g/LQzEYP7Xs27T96abJCCE2d6r3cPZPQEsLKy0vRSGVNG+/zVGtLr86HQduA== + version "0.6.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" + integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== dependencies: jsesc "~0.5.0" @@ -7352,7 +7388,7 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.3.2, resolve@^1.8.1: +resolve@^1.10.0, resolve@^1.12.0, resolve@^1.15.1, resolve@^1.3.2, resolve@^1.8.1: version "1.15.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== @@ -7400,9 +7436,9 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: inherits "^2.0.1" rollup-plugin-terser@^5.1.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.2.0.tgz#ba758adf769347b7f1eaf9ef35978d2e207dccc7" - integrity sha512-jQI+nYhtDBc9HFRBz8iGttQg7li9klmzR62RG2W2nN6hJ/FI2K2ItYQ7kJ7/zn+vs+BP1AEccmVRjRN989I+Nw== + version "5.3.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.3.0.tgz#9c0dd33d5771df9630cd027d6a2559187f65885e" + integrity sha512-XGMJihTIO3eIBsVGq7jiNYOdDMb3pVxuzY0uhOE/FM4x/u9nQgr3+McsjzqBn3QfHIpNSZmFnpoKAwHBEcsT7g== dependencies: "@babel/code-frame" "^7.5.5" jest-worker "^24.9.0" @@ -7509,10 +7545,10 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -scheduler@^0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4" - integrity sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ== +scheduler@^0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.0.tgz#a715d56302de403df742f4a9be11975b32f5698d" + integrity sha512-xowbVaTPe9r7y7RUejcK73/j8tt2jfiyTednOvHbA8JoClvMYCp+r8QegLwK/n8zWQAtZb1fFnER4XLBZXrCxA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -8161,9 +8197,9 @@ terser-webpack-plugin@^1.4.3: worker-farm "^1.7.0" terser@^4.1.2, terser@^4.6.2: - version "4.6.4" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.4.tgz#40a0b37afbe5b57e494536815efa68326840fc00" - integrity sha512-5fqgBPLgVHZ/fVvqRhhUp9YUiGXhFJ9ZkrZWD9vQtFBR4QIGTnbsb+/kKqSqfgp3WnBwGWAFnedGTtmX1YTn0w== + version "4.6.6" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.6.tgz#da2382e6cafbdf86205e82fb9a115bd664d54863" + integrity sha512-4lYPyeNmstjIIESr/ysHg2vUPRGf2tzF9z2yYwnowXVuVzLEamPN1Gfrz7f8I9uEPuHcbFlW4PLIAsJoxXyJ1g== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -8313,10 +8349,10 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== -tslib@^1.10.0, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: - version "1.11.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.0.tgz#f1f3528301621a53220d58373ae510ff747a66bc" - integrity sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg== +tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: + version "1.11.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" + integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== tslint@^5.20.1: version "5.20.1" @@ -8386,9 +8422,9 @@ typedarray@^0.0.6: integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= typescript@^3.7.3: - version "3.8.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a" - integrity sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ== + version "3.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" + integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== ua-parser-js@^0.7.18: version "0.7.21" @@ -8404,9 +8440,9 @@ unherit@^1.0.4: xtend "^4.0.0" unhomoglyph@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unhomoglyph/-/unhomoglyph-1.0.4.tgz#38d2ec9de84ab921623ebd9fb60f710963c601f4" - integrity sha512-+y+QeEXwm4f0H8Tmy9fFUWHM95YcFjJLlv83/p3+EARUkeJBxnSOBADVyeuSq0TsRJ/UexxCXBKXo40ksu715w== + version "1.0.5" + resolved "https://registry.yarnpkg.com/unhomoglyph/-/unhomoglyph-1.0.5.tgz#a68c6244f0ec140bfe58293a1f66a9bd2a244343" + integrity sha512-rNAw2rGogjq4BVhsCX8K6qXrCcHmUaMCHETlUG0ujGZ3OHwnzJHwdMyzy3n/c9Y7lvlbckOd9nkW33grUVE3bg== unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" @@ -8499,9 +8535,9 @@ unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: integrity sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ== unist-util-stringify-position@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.2.tgz#5a3866e7138d55974b640ec69a94bc19e0f3fa12" - integrity sha512-nK5n8OGhZ7ZgUwoUbL8uiVRwAbZyzBsB/Ddrlbu6jwwubFza4oe15KlyEaLNMXQW1svOQq4xesUeqA85YrIUQA== + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" + integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== dependencies: "@types/unist" "^2.0.2" @@ -8653,9 +8689,9 @@ vfile-location@^2.0.0: integrity sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA== vfile-message@*: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.2.tgz#75ba05090ec758fa8420f2c11ce049bcddd8cf3e" - integrity sha512-gNV2Y2fDvDOOqq8bEe7cF3DXU6QgV4uA9zMR2P8tix11l1r7zju3zry3wZ8sx+BEfuO6WQ7z2QzfWTvqHQiwsA== + version "2.0.3" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.3.tgz#0dd4f6879fb240a8099b22bd3755536c92e59ba5" + integrity sha512-qQg/2z8qnnBHL0psXyF72kCjb9YioIynvyltuNKFaUhRtqTIcIMP3xnBaPzirVZNuBrUe1qwFciSx2yApa4byw== dependencies: "@types/unist" "^2.0.0" unist-util-stringify-position "^2.0.0" @@ -8683,11 +8719,11 @@ vm-browserify@^1.0.1: integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== w3c-hr-time@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" - integrity sha1-gqwr/2PZUOqeMYmlimViX+3xkEU= + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== dependencies: - browser-process-hrtime "^0.1.2" + browser-process-hrtime "^1.0.0" walk@^2.3.9: version "2.3.14" @@ -8758,9 +8794,9 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1: source-map "~0.6.1" webpack@^4.20.2: - version "4.41.6" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.6.tgz#12f2f804bf6542ef166755050d4afbc8f66ba7e1" - integrity sha512-yxXfV0Zv9WMGRD+QexkZzmGIh54bsvEs+9aRWxnN8erLWEOehAKUTeNBoUbA6HPEZPlRo7KDi2ZcNveoZgK9MA== + version "4.42.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.42.0.tgz#b901635dd6179391d90740a63c93f76f39883eb8" + integrity sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w== dependencies: "@webassemblyjs/ast" "1.8.5" "@webassemblyjs/helper-module-context" "1.8.5" @@ -8787,9 +8823,9 @@ webpack@^4.20.2: webpack-sources "^1.4.1" what-input@^5.2.6: - version "5.2.6" - resolved "https://registry.yarnpkg.com/what-input/-/what-input-5.2.6.tgz#ac6f003bf8d3592a0031dea7a03565469b00020b" - integrity sha512-a0BcI5YR7xp87vSzGcbN0IszJKpUQuTmrZaTSQBl7TLDIdKj6rDhluQ7b/7lYGG81gWDvkySsEvwv4BW5an9kg== + version "5.2.7" + resolved "https://registry.yarnpkg.com/what-input/-/what-input-5.2.7.tgz#81afbb6b82882cff8c43fa7ff1054aa46f288ffa" + integrity sha512-ruCP2skyygi0ZHnMicHuZP7vXnJh8uJXs9R7RX488HlWigSdzngdmKo5Ti11Iatp1dnYp55VfioP/WevPaK+xQ== whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: version "1.0.5" @@ -8931,6 +8967,13 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xregexp@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50" + integrity sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g== + dependencies: + "@babel/runtime-corejs3" "^7.8.3" + xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"