From 4a16bf41276524819a3b066d43e576b9310ca4c3 Mon Sep 17 00:00:00 2001 From: Reza Mohseni Date: Thu, 4 Jul 2024 14:07:26 +0200 Subject: [PATCH 1/3] Revert "Merge branch 'verji-develop' of https://github.com/verji/matrix-react-sdk into develop" This reverts commit 68437a1086e5d2a968c77f0bb50e562f8ebc7962, reversing changes made to 80aa32ff923d59d36ce05ac8af04dcdd203b4458. --- .github/workflows/static_analysis.yaml | 38 +- .github/workflows/verji-release-drafter.yml | 9 - jest.config.ts | 3 +- package.json | 5 +- res/css/structures/_HomePage.pcss | 1 - res/css/structures/_LeftPanel.pcss | 11 - res/css/structures/_MiscHeader.scss | 61 - res/css/structures/_RoomView.pcss | 26 - res/css/structures/_UserMenu.pcss | 21 - .../_ConfirmInviteExternalUsersDialog.scss | 41 - .../dialogs/_InviteNewMembersDialog.scss | 210 -- res/css/views/elements/_Tooltip.pcss | 2 +- res/css/views/rooms/_NotificationBadge.pcss | 6 - res/img/verji/address-card.svg | 1 - res/img/verji/house-user.svg | 1 - res/img/verji/news.svg | 1 - res/img/verji/shield.svg | 22 - res/img/verji/signing.svg | 42 - src/LegacyCallHandler.tsx | 4 +- src/Lifecycle.ts | 3 +- src/Login.ts | 3 +- src/MatrixClientPeg.ts | 26 +- src/Roles.ts | 1 - src/SecurityManager.ts | 9 +- src/VerjiLocalSearch.ts | 424 ---- .../security/CreateSecretStorageDialog.tsx | 3 +- src/components/structures/HomePage.tsx | 55 +- src/components/structures/LeftPanel.tsx | 9 +- src/components/structures/LoggedInView.tsx | 99 +- src/components/structures/MatrixChat.tsx | 37 +- src/components/structures/RoomView.tsx | 244 +-- src/components/structures/SpaceRoomView.tsx | 22 +- src/components/structures/ViewSource.tsx | 20 +- src/components/structures/auth/Login.tsx | 41 +- .../structures/auth/SetupEncryptionBody.tsx | 32 +- .../structures/grouper/CreationGrouper.tsx | 6 +- .../context_menus/MessageContextMenu.tsx | 143 +- .../views/context_menus/RoomContextMenu.tsx | 4 +- .../views/context_menus/SpaceContextMenu.tsx | 2 +- .../views/context_menus/WidgetContextMenu.tsx | 3 +- .../views/dialogs/CreateRoomDialog.tsx | 69 +- .../views/dialogs/DevtoolsDialog.tsx | 24 +- src/components/views/dialogs/ExportDialog.tsx | 25 +- src/components/views/dialogs/InviteDialog.tsx | 512 +---- src/components/views/dialogs/LogoutDialog.tsx | 2 +- .../views/dialogs/RoomSettingsDialog.tsx | 42 +- .../views/dialogs/SpaceSettingsDialog.tsx | 16 +- .../views/dialogs/UserSettingsDialog.tsx | 58 +- .../views/dialogs/devtools/AccountData.tsx | 16 +- .../views/dialogs/devtools/BaseTool.tsx | 4 +- .../dialogs/spotlight/SpotlightDialog.tsx | 6 +- .../views/directory/NetworkDropdown.tsx | 86 +- .../views/elements/ErrorBoundary.tsx | 27 +- .../views/elements/PowerSelector.tsx | 5 +- .../views/elements/SearchWarning.tsx | 30 +- src/components/views/elements/Tooltip.tsx | 2 +- .../views/messages/ReactionsRow.tsx | 25 +- .../messages/ReactionsRowButtonTooltip.tsx | 52 +- .../views/right_panel/RoomSummaryCard.tsx | 19 +- src/components/views/right_panel/UserInfo.tsx | 13 +- src/components/views/rooms/AppsDrawer.tsx | 26 +- src/components/views/rooms/EntityTile.tsx | 40 +- .../views/rooms/LegacyRoomHeader.tsx | 47 +- src/components/views/rooms/NewRoomIntro.tsx | 25 +- .../StatelessNotificationBadge.tsx | 2 - src/components/views/rooms/RoomInfoLine.tsx | 6 +- src/components/views/rooms/RoomList.tsx | 62 +- src/components/views/rooms/RoomListHeader.tsx | 47 +- src/components/views/rooms/RoomPreviewBar.tsx | 5 +- .../views/settings/CrossSigningPanel.tsx | 4 +- .../views/settings/SecureBackupPanel.tsx | 10 +- .../views/settings/ThemeChoicePanel.tsx | 3 +- .../views/settings/account/EmailAddresses.tsx | 22 +- .../views/settings/account/PhoneNumbers.tsx | 22 +- .../tabs/room/GeneralRoomSettingsTab.tsx | 21 +- .../tabs/user/GeneralUserSettingsTab.tsx | 21 +- .../tabs/user/HelpUserSettingsTab.tsx | 113 +- .../tabs/user/PreferencesUserSettingsTab.tsx | 44 +- .../tabs/user/SidebarUserSettingsTab.tsx | 3 - .../tabs/user/VoiceUserSettingsTab.tsx | 42 +- src/components/views/spaces/SpacePanel.tsx | 84 +- src/dispatcher/actions.ts | 17 - src/i18n/strings/en_EN.json | 5 - src/settings/Settings.tsx | 250 +-- src/settings/UIFeature.ts | 63 - src/theme.ts | 11 +- src/toasts/BulkUnverifiedSessionsToast.ts | 32 +- src/toasts/SetupEncryptionToast.ts | 6 +- src/utils/FormattingUtils.ts | 43 - src/utils/direct-messages.ts | 5 +- test/DeviceListener-test.ts | 39 +- test/VerjiLocalSearch-test.ts | 258 --- .../components/structures/AppsDrawer-test.tsx | 54 - .../components/structures/EntityTile-test.tsx | 54 - .../structures/ErrorBoundary-test.tsx | 58 - test/components/structures/HomePage-test.tsx | 67 - test/components/structures/LeftPanel-test.tsx | 21 +- .../structures/LoggedInView-test.tsx | 106 +- .../structures/MessagePanel-test.tsx | 54 - .../ReactionsRowButtonTooltip-test.tsx | 94 - test/components/structures/RoomView-test.tsx | 70 - .../structures/SpaceRoomView-test.tsx | 64 - .../ReactionsRowButtonTooltip-test.tsx.snap | 7 - .../components/structures/auth/Login-test.tsx | 19 +- .../context_menus/MessageContextMenu-test.tsx | 38 - .../context_menus/RoomContextMenu-test.tsx | 24 +- .../context_menus/SpaceContextMenu-test.tsx | 37 - .../views/dialogs/CreateRoomDialog-test.tsx | 62 +- .../views/dialogs/ExportDialog-test.tsx | 80 - .../views/dialogs/InviteDialog-test.tsx | 7 - .../views/dialogs/RoomSettingsDialog-test.tsx | 63 +- .../views/dialogs/UserSettingsDialog-test.tsx | 67 +- .../RoomSettingsDialog-test.tsx.snap | 18 + .../UserSettingsDialog-test.tsx.snap | 36 + .../views/elements/PowerSelector-test.tsx | 17 - .../views/messages/ReactionsRow-test.tsx | 99 - .../right_panel/RoomSummaryCard-test.tsx | 90 - .../views/right_panel/UserInfo-test.tsx | 35 +- .../RoomSummaryCard-test.tsx.snap | 397 ---- .../views/rooms/LegacyRoomHeader-test.tsx | 34 - .../views/rooms/RoomKnocksBar-test.tsx | 8 +- test/components/views/rooms/RoomList-test.tsx | 79 +- .../views/rooms/RoomListHeader-test.tsx | 59 +- .../views/rooms/RoomPreviewBar-test.tsx | 25 +- .../RoomPreviewBar-test.tsx.snap | 7 + .../views/settings/CrossSigningPanel-test.tsx | 28 - .../views/settings/SecureBackupPanel-test.tsx | 59 - .../views/settings/ThemeChoicePanel-test.tsx | 22 +- .../settings/account/EmailAddresses-test.tsx | 108 - .../settings/account/PhoneNumbers-test.tsx | 75 +- .../EmailAddresses-test.tsx.snap | 187 -- .../__snapshots__/PhoneNumbers-test.tsx.snap | 358 ---- .../tabs/room/PeopleRoomSettingsTab-test.tsx | 18 +- .../tabs/user/GeneralUserSettingsTab-test.tsx | 98 +- .../tabs/user/HelpUserSettingsTab-test.tsx | 81 - .../user/PreferencesUserSettingsTab-test.tsx | 212 +- .../tabs/user/SidebarUserSettingsTab-test.tsx | 39 - .../tabs/user/VoiceUserSettingsTab-test.tsx | 38 - .../GeneralUserSettingsTab-test.tsx.snap | 8 +- .../PreferencesUserSettingsTab-test.tsx.snap | 303 ++- .../views/spaces/SpacePanel-test.tsx | 51 +- .../ThreadsActivityCentre-test.tsx.snap | 2 +- yarn.lock | 1815 ++++++++++++----- 143 files changed, 2316 insertions(+), 7238 deletions(-) delete mode 100644 .github/workflows/verji-release-drafter.yml delete mode 100644 res/css/structures/_MiscHeader.scss delete mode 100644 res/css/views/dialogs/_ConfirmInviteExternalUsersDialog.scss delete mode 100644 res/css/views/dialogs/_InviteNewMembersDialog.scss delete mode 100644 res/img/verji/address-card.svg delete mode 100644 res/img/verji/house-user.svg delete mode 100644 res/img/verji/news.svg delete mode 100644 res/img/verji/shield.svg delete mode 100644 res/img/verji/signing.svg delete mode 100644 src/VerjiLocalSearch.ts delete mode 100644 test/VerjiLocalSearch-test.ts delete mode 100644 test/components/structures/AppsDrawer-test.tsx delete mode 100644 test/components/structures/EntityTile-test.tsx delete mode 100644 test/components/structures/ErrorBoundary-test.tsx delete mode 100644 test/components/structures/HomePage-test.tsx delete mode 100644 test/components/structures/ReactionsRowButtonTooltip-test.tsx delete mode 100644 test/components/structures/SpaceRoomView-test.tsx delete mode 100644 test/components/structures/__snapshots__/ReactionsRowButtonTooltip-test.tsx.snap delete mode 100644 test/components/views/messages/ReactionsRow-test.tsx delete mode 100644 test/components/views/settings/account/EmailAddresses-test.tsx delete mode 100644 test/components/views/settings/account/__snapshots__/EmailAddresses-test.tsx.snap delete mode 100644 test/components/views/settings/tabs/user/HelpUserSettingsTab-test.tsx diff --git a/.github/workflows/static_analysis.yaml b/.github/workflows/static_analysis.yaml index 78da84e8dd0..070ac5f8544 100644 --- a/.github/workflows/static_analysis.yaml +++ b/.github/workflows/static_analysis.yaml @@ -1,6 +1,5 @@ name: Static Analysis on: - workflow_dispatch: pull_request: {} merge_group: types: [checks_requested] @@ -22,44 +21,14 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: cache: "yarn" - # VERJI SPECIFIC - yarn link FOR matrix-react-sdk-module-api on verji-main branch - #- name: "Veri - Clone Github Repo Action - Download verji-main of module-api" - # # You may pin to the exact commit or the version. - # # uses: GuillaumeFalourd/clone-github-repo-action@19817562c346ff60f9935158dede6c5ece8fd0ac - # uses: GuillaumeFalourd/clone-github-repo-action@v2.3 - # with: - # # Repository Owner - # owner: verji - # # Repository name - # repository: "matrix-react-sdk-module-api" - # # PAT with repository scope (https://github.com/settings/tokens) - # access-token: ${{secrets.PAT}} - # # Depth of the clone (default: full history) - # depth: 1 - # # Branch name (default: main) - # branch: "verji-main" - # # Clone with submodules - # submodule: false # optional, default is false - # - name: "Verji - Build and yarn link matrix-react-sdk-module-api (prepublish)" - # uses: Azure/powershell@v2 - # with: - # # Yarn link matrix-react-sdk-module-api #--skipLibCheck build --skipLibCheck - # inlineScript: "cd matrix-react-sdk-module-api && yarn && yarn link && yarn prepublishOnly && cd .. && cd .. && cd 'matrix-react-sdk'" - # azPSVersion: "latest" - #END VERJI SPECIFIC + - name: Install Deps run: "./scripts/ci/install-deps.sh --ignore-scripts" - # VERJI - # - name: "Verji - yarn link matrix-react-sdk-module-api/verji-main into matrix-react-sdk" - # uses: Azure/powershell@v2 - # with: - # # Yarn link matrix-react-sdk-module-api #--skipLibCheck - # inlineScript: "yarn link '@matrix-org/react-sdk-module-api'" - # azPSVersion: "latest" - # VERJI END + - name: Typecheck run: "yarn run lint:types" @@ -86,7 +55,6 @@ jobs: i18n_lint: name: "i18n Check" - if: ${{ github.ref_name != 'verji-develop' }} uses: matrix-org/matrix-web-i18n/.github/workflows/i18n_check.yml@main with: hardcoded-words: "Element" diff --git a/.github/workflows/verji-release-drafter.yml b/.github/workflows/verji-release-drafter.yml deleted file mode 100644 index 585834d6014..00000000000 --- a/.github/workflows/verji-release-drafter.yml +++ /dev/null @@ -1,9 +0,0 @@ -name: Verji Release Drafter -on: - push: - branches: [verji-staging] - workflow_dispatch: {} -concurrency: ${{ github.workflow }} -jobs: - draft: - uses: verji/matrix-js-sdk/.github/workflows/release-drafter-workflow.yml@verji-develop diff --git a/jest.config.ts b/jest.config.ts index 7fc8dec3feb..182c28f68ae 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -20,11 +20,10 @@ import type { Config } from "jest"; const config: Config = { testEnvironment: "jsdom", - testMatch: ["/test/**/*-test.[jt]s?(x)", "/test/**/**/*-test.[jt]s?(x)"], + testMatch: ["/test/**/*-test.[jt]s?(x)"], globalSetup: "/test/globalSetup.ts", setupFiles: ["jest-canvas-mock"], setupFilesAfterEnv: ["/test/setupTests.ts"], - moduleFileExtensions: ["js", "jsx", "json", "ts", "tsx"], moduleNameMapper: { "\\.(gif|png|ttf|woff2)$": "/__mocks__/imageMock.js", "\\.svg$": "/__mocks__/svg.js", diff --git a/package.json b/package.json index d6e3fc1d51c..84aff161039 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ }, "dependencies": { "@babel/runtime": "^7.12.5", - "@matrix-org/analytics-events": "^0.21.0", + "@matrix-org/analytics-events": "^0.20.0", "@matrix-org/emojibase-bindings": "^1.1.2", "@matrix-org/matrix-wysiwyg": "2.17.0", "@matrix-org/olm": "3.2.15", @@ -128,7 +128,6 @@ "react-focus-lock": "^2.5.1", "react-transition-group": "^4.4.1", "rfc4648": "^1.4.0", - "rss-parser": "^3.12.0", "sanitize-filename": "^1.6.3", "sanitize-html": "2.13.0", "tar-js": "^0.3.0", @@ -183,7 +182,6 @@ "@types/react-dom": "17.0.25", "@types/react-transition-group": "^4.4.0", "@types/sanitize-html": "2.11.0", - "@types/scheduler": "^0.23.0", "@types/sdp-transform": "^2.4.6", "@types/seedrandom": "<3.0.5", "@types/tar-js": "^0.3.2", @@ -222,7 +220,6 @@ "postcss-scss": "^4.0.4", "prettier": "3.2.5", "raw-loader": "^4.0.2", - "react-test-renderer": "17.0.2", "rimraf": "^5.0.0", "stylelint": "^16.1.0", "stylelint-config-standard": "^36.0.0", diff --git a/res/css/structures/_HomePage.pcss b/res/css/structures/_HomePage.pcss index 6bd2e05af6e..b2f607f8226 100644 --- a/res/css/structures/_HomePage.pcss +++ b/res/css/structures/_HomePage.pcss @@ -22,7 +22,6 @@ limitations under the License. height: 100%; margin-left: auto; margin-right: auto; - max-height: 100%; } .mx_HomePage_default { diff --git a/res/css/structures/_LeftPanel.pcss b/res/css/structures/_LeftPanel.pcss index 2a65a6f17c8..9cbffc77d4a 100644 --- a/res/css/structures/_LeftPanel.pcss +++ b/res/css/structures/_LeftPanel.pcss @@ -148,8 +148,6 @@ limitations under the License. } } - .mx_LeftPanel_omButton, - .mx_LeftPanel_newsButton, .mx_LeftPanel_exploreButton, .mx_LeftPanel_recentsButton { width: 32px; @@ -181,15 +179,6 @@ limitations under the License. } } - //Verji start - .mx_LeftPanel_newsButton::before { - mask-image: url("$(res)/img/verji/news.svg"); - } - .mx_LeftPanel_omButton::before { - mask-image: url("$(res)/img/verji/shield.svg"); - } - //Verji end - .mx_LeftPanel_exploreButton::before { mask-image: url("$(res)/img/element-icons/roomlist/explore.svg"); } diff --git a/res/css/structures/_MiscHeader.scss b/res/css/structures/_MiscHeader.scss deleted file mode 100644 index a932e6cd78e..00000000000 --- a/res/css/structures/_MiscHeader.scss +++ /dev/null @@ -1,61 +0,0 @@ -/* - ROSBERG FILE -*/ - -.mx_MiscHeaderButtons { - display: flex; - &::before { - content: unset; - } -} - -.mx_MiscHeaderButtons::before { - content: ""; - //background-color: $header-divider-color; - opacity: 0.5; - margin: 6px 8px; - border-radius: 1px; - width: 1px; -} - -.mx_MiscHeader_miscButton { - cursor: pointer; - flex: 0 0 auto; - margin-left: 1px; - margin-right: 1px; - height: 32px; - width: 32px; - position: relative; - border-radius: 100%; - - &::before { - content: ""; - position: absolute; - top: 4px; // center with parent of 32px - left: 4px; // center with parent of 32px - height: 24px; - width: 24px; - background-color: $icon-button-color; - mask-repeat: no-repeat; - mask-size: contain; - } - - &:hover { - //background: rgba($accent-color, 0.1); - - &::before { - //background-color: $accent-color; - } - } -} - -.mx_MiscHeader_miscButton_highlight { - &::before { - //background-color: $accent-color !important; - } -} - -.mx_MiscHeader_roomSupportButton::before { - mask-image: url("$(res)/img/element-icons/settings/help.svg"); - mask-position: center; -} diff --git a/res/css/structures/_RoomView.pcss b/res/css/structures/_RoomView.pcss index 3430a22b06f..30583384b7a 100644 --- a/res/css/structures/_RoomView.pcss +++ b/res/css/structures/_RoomView.pcss @@ -162,32 +162,6 @@ limitations under the License. margin-bottom: 80px; /* visually center the content (intentional offset) */ } -// Verji start -@keyframes fade1 { - 0% { - opacity: 0; - } - 100% { - opacity: 1; - } -} -.mx_RoomView_News1 { - animation: 0.2s ease-out 0s 0.2 fade1; -} - -@keyframes fade2 { - 0% { - transform: translateX(70px); - } - 100% { - transform: translateX(0); - } -} -.mx_RoomView_News2 { - animation: 0.2s ease 0s 0.2 fade2; -} -// Verji end - .mx_RoomView_MessageList { list-style-type: none; padding: var(--RoomView_MessageList-padding); /* mx_ProfileResizer depends on this value */ diff --git a/res/css/structures/_UserMenu.pcss b/res/css/structures/_UserMenu.pcss index 78a86511344..f25c15e48e6 100644 --- a/res/css/structures/_UserMenu.pcss +++ b/res/css/structures/_UserMenu.pcss @@ -207,27 +207,6 @@ limitations under the License. .mx_UserMenu_iconSignOut::before { mask-image: url("$(res)/img/element-icons/leave.svg"); } - /* Verji start */ - .mx_UserMenu_iconMembers::before { - mask-image: url("$(res)/img/element-icons/room/members.svg"); - } - - .mx_UserMenu_iconInvite::before { - mask-image: url("$(res)/img/element-icons/room/invite.svg"); - } - - .mx_UserMenu_oidcmanage::before { - mask-image: url("$(res)/img/verji/address-card.svg"); - } - - .mx_UserMenu_portal::before { - mask-image: url("$(res)/img/verji/house-user.svg"); - } - - .mx_UserMenu_signing::before { - mask-image: url("$(res)/img/verji/signing.svg"); - } - /* Verji end */ } .mx_UserMenu_CustomStatusSection { diff --git a/res/css/views/dialogs/_ConfirmInviteExternalUsersDialog.scss b/res/css/views/dialogs/_ConfirmInviteExternalUsersDialog.scss deleted file mode 100644 index ebef647adbd..00000000000 --- a/res/css/views/dialogs/_ConfirmInviteExternalUsersDialog.scss +++ /dev/null @@ -1,41 +0,0 @@ -/* ROSBERG style module */ -/* NOTE: This code (and any other Rosberg .pcss/.scss files) has to be imported in here: res\css\_components.pcss */ - -.mx_ConfirmInviteExternalUsersDialog { - &.mx_BaseDialog { - width: 480px; - } -} - -.mx_Dialog_content { - margin-bottom: 24px; -} - -.vmx_all_users { - display: flex; - flex-direction: row; - flex-wrap: wrap; - width: 100%; - gap: 20px; -} - -.mx_ConfirmInviteExternalUsersDialog_user { - display: flex; - flex-direction: column; - flex: 1; - padding: 8px; - border: 1px solid #ccc; - border-radius: 4px; - - :first-child { - margin-top: 0; - } - - &_email, - &_project, - &_phoneNr { - margin-top: 4px; - font-style: italic; - white-space: nowrap; - } -} diff --git a/res/css/views/dialogs/_InviteNewMembersDialog.scss b/res/css/views/dialogs/_InviteNewMembersDialog.scss deleted file mode 100644 index 49fd04be651..00000000000 --- a/res/css/views/dialogs/_InviteNewMembersDialog.scss +++ /dev/null @@ -1,210 +0,0 @@ -/* ROSBERG style module */ -/* NOTE: This code (and any other Rosberg .pcss files) has to be imported in here: res\css\_components.pcss */ - -.vmx_main_dialog { - @at-root .mx_Dialog & { - height: auto !important; - } -} - -.vmx_no_external_user_found { - display: flex; - flex-direction: row; - position: relative; - justify-content: space-between; - padding-bottom: 12px; - margin-bottom: 12px; - - padding: 8px; - border: 1px solid #dec802; - border-radius: 4px; - - .vmx_no_external_user_found_warning_icon { - margin-right: 20px; - } - - .vmx_no_external_user_found_close_btn { - right: 10px; - display: none; - scale: 0.8; - } - &:hover { - .vmx_no_external_user_found_close_btn { - display: block !important; - } - } -} - -.vmx_invite_external_user { - display: flex; - flex-wrap: wrap; - position: relative; - justify-content: space-between; - padding-bottom: 12px; - margin-bottom: 12px; - // border-bottom: 1px solid var(--quinary-content, #6F7882) - - padding: 8px; - border: 1px solid #ccc; - border-radius: 4px; - // margin-bottom: 8px; - - .vmx_invite_external_user_close_btn { - right: 10px; - display: none; - scale: 0.8; - } - &:hover { - .vmx_invite_external_user_close_btn { - display: block !important; - } - } -} - -.vmx_invite_external_user_tenant_info { - display: flex; - flex-direction: row; - width: 100%; - align-items: center; - :last-child { - margin-left: 20px; - scale: 0.8; - } -} - -.vmx_invite_external_user_field { - flex: 1 1 0; - /* min-width: 300px; */ - padding: 1rem; - box-sizing: border-box; -} - -@media (max-width: 960px) { - .vmx_invite_external_user_field { - flex-basis: 100%; - } -} - -.vmx_phone_nr_invalid { - border-color: red !important; -} - -.vmx_phone_input_flag > :first-child { - margin-left: 10px; -} - -.vmx_input { - margin: 0 !important; -} - -.vmx_infoText { - margin-bottom: 40px !important; -} - -.vmx_input_readonly { - background-color: var(--quinary-content, #6f7882); - color: var(--primary-content, #ffffff); -} - -.vmx_dialog_footer { - display: flex; - flex-direction: row; - align-items: center; - justify-content: end; - margin-top: 40px; - padding: 0 !important; - width: 100%; -} - -.vmx_divider { - height: 1em; - display: block; -} - -.vmx_InviteDialog_roomTile { - cursor: pointer; - padding: 5px 10px; - - &:hover { - background-color: $header-panel-bg-color; - border-radius: 4px; - } - - * { - vertical-align: middle; - } - - .vmx_InviteDialog_roomTile_avatarStack { - display: inline-block; - position: relative; - width: 36px; - height: 36px; - - & > * { - position: absolute; - top: 0; - left: 0; - } - } - - .vmx_InviteDialog_roomTile_selected { - width: 36px; - height: 36px; - border-radius: 36px; - background-color: $username-variant1-color; - display: inline-block; - position: relative; - - &::before { - content: ""; - width: 24px; - height: 24px; - grid-column: 1; - grid-row: 1; - mask-image: url("$(res)/img/feather-customised/check.svg"); - mask-size: 100%; - mask-repeat: no-repeat; - position: absolute; - top: 6px; // 50% - left: 6px; // 50% - background-color: #ffffff; // this is fine without a var because it's for both themes - } - } - - .vmx_InviteDialog_roomTile_nameStack { - display: inline-block; - overflow: hidden; - } - - .vmx_InviteDialog_roomTile_name { - font-weight: 600; - font-size: $font-14px; - color: $primary-content; - margin-left: 7px; - } - - .vmx_InviteDialog_roomTile_userId { - font-size: $font-12px; - color: $muted-fg-color; - margin-left: 7px; - } - - .vmx_InviteDialog_roomTile_name, - .vmx_InviteDialog_roomTile_userId { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .vmx_InviteDialog_roomTile_time { - text-align: right; - font-size: $font-12px; - color: $muted-fg-color; - float: right; - line-height: 3.6rem; // Height of the avatar to keep the time vertically aligned - } - - .vmx_InviteDialog_roomTile_highlight { - font-weight: 900; - } -} diff --git a/res/css/views/elements/_Tooltip.pcss b/res/css/views/elements/_Tooltip.pcss index 99e96784e3b..54a16a0cbf0 100644 --- a/res/css/views/elements/_Tooltip.pcss +++ b/res/css/views/elements/_Tooltip.pcss @@ -68,7 +68,7 @@ limitations under the License. line-height: $font-14px; font-size: $font-12px; font-weight: 500; - max-width: 320px; + max-width: 300px; word-break: break-word; background-color: var(--cpd-color-alpha-gray-1400); diff --git a/res/css/views/rooms/_NotificationBadge.pcss b/res/css/views/rooms/_NotificationBadge.pcss index 05dcf6ce5cb..6ffe7d9da71 100644 --- a/res/css/views/rooms/_NotificationBadge.pcss +++ b/res/css/views/rooms/_NotificationBadge.pcss @@ -33,12 +33,6 @@ limitations under the License. align-items: center; justify-content: center; - //Verji start - &.mx_NotificationBadge_green { - background-color: $accent; - } - // Verji end - /* These are the 3 background types */ &.mx_NotificationBadge_dot { diff --git a/res/img/verji/address-card.svg b/res/img/verji/address-card.svg deleted file mode 100644 index 2258c1f3aa1..00000000000 --- a/res/img/verji/address-card.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/res/img/verji/house-user.svg b/res/img/verji/house-user.svg deleted file mode 100644 index 42b75783e86..00000000000 --- a/res/img/verji/house-user.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/res/img/verji/news.svg b/res/img/verji/news.svg deleted file mode 100644 index 1db2488e24a..00000000000 --- a/res/img/verji/news.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/res/img/verji/shield.svg b/res/img/verji/shield.svg deleted file mode 100644 index 3d9a8fcb7d9..00000000000 --- a/res/img/verji/shield.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - diff --git a/res/img/verji/signing.svg b/res/img/verji/signing.svg deleted file mode 100644 index 67cf21788fc..00000000000 --- a/res/img/verji/signing.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - diff --git a/src/LegacyCallHandler.tsx b/src/LegacyCallHandler.tsx index fd5a6a51b0b..7abdb236aeb 100644 --- a/src/LegacyCallHandler.tsx +++ b/src/LegacyCallHandler.tsx @@ -991,9 +991,7 @@ export default class LegacyCallHandler extends EventEmitter { await this.placeMatrixCall(roomId, type, transferee); } else { // > 2 - if (SettingsStore.getValue(UIFeature.MultipleCallsInRoom)) { - await this.placeJitsiCall(roomId, type); - } + await this.placeJitsiCall(roomId, type); } } diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index be1479196c4..8b04f74afcb 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -864,8 +864,7 @@ async function persistCredentials(credentials: IMatrixClientCreds): Promise void, ): Promise { - // const keyFromCustomisations = SecurityCustomisations.getSecretStorageKey?.(); - const keyFromCustomisations = ModuleRunner.instance.extensions.cryptoSetup?.getSecretStorageKey(); + const keyFromCustomisations = ModuleRunner.instance.extensions.cryptoSetup.getSecretStorageKey(); if (keyFromCustomisations) { logger.log("CryptoSetupExtension: Using key from extension (dehydration)"); return keyFromCustomisations; @@ -432,8 +430,7 @@ async function doAccessSecretStorage(func: () => Promise, forceReset: bool // inner operation completes. return await func(); } catch (e) { - // SecurityCustomisations.catchAccessSecretStorageError?.(e as Error); - ModuleRunner.instance.extensions.cryptoSetup?.catchAccessSecretStorageError(e as Error); + ModuleRunner.instance.extensions.cryptoSetup.catchAccessSecretStorageError(e as Error); logger.error(e); // Re-throw so that higher level logic can abort as needed throw e; diff --git a/src/VerjiLocalSearch.ts b/src/VerjiLocalSearch.ts deleted file mode 100644 index 58c1c0fe172..00000000000 --- a/src/VerjiLocalSearch.ts +++ /dev/null @@ -1,424 +0,0 @@ -/* - Copyright 2024 Verji Tech AS. All rights reserved. - Unauthorized copying or distribution of this file, via any medium, is strictly prohibited. -*/ - -import { - EventTimeline, - MatrixClient, - MatrixEvent, - Room, - RoomMember, - SearchResult, - ISearchResults, - ISearchResponse, - // ISearchResult, - // IEventWithRoomId -} from "matrix-js-sdk/src/matrix"; -import { EventContext } from "matrix-js-sdk/src/models/event-context"; // eslint-disable-line - -interface WordHighlight { - word: string; - highlight: boolean; -} - -export interface SearchTerm { - searchTypeAdvanced: boolean; - searchTypeNormal: boolean; - searchExpression?: RegExp | null; - regExpHighlightMap?: { [key: string]: boolean }; - fullText?: string; - words: WordHighlight[]; - regExpHighlights: any[]; - isEmptySearch?: boolean; -} - -interface Member { - userId: string; -} - -interface MemberObj { - [key: string]: Member; -} - -export interface SearchResultItem { - result: MatrixEvent; - context: EventContext; -} - -/** - * Searches all events locally based on the provided search term and room ID. - * - * @param {MatrixClient} client - The Matrix client instance. - * @param {string} term - The search term. - * @param {string | undefined} roomId - The ID of the room to search in. - * @returns {Promise} A promise that resolves to the search results. - * @throws {Error} If the Matrix client is not initialized or the room is not found. - */ -export default async function searchAllEventsLocally( - client: MatrixClient, - term: string, - roomId: string | undefined, -): Promise { - const searchResults: ISearchResults = { - results: [], - highlights: [], - count: 0, - }; - - if (!client) { - throw new Error("Matrix client is not initialized"); - } - - const room: Room | null = client.getRoom(roomId); - if (!room) { - throw new Error("Room not found"); - } - - const members = room.getLiveTimeline().getState(EventTimeline.FORWARDS)?.getMembers(); - const termObj: SearchTerm = makeSearchTermObject(term.trim()); - - if (termObj.isEmptySearch) { - return searchResults; - } - - let matchingMembers: Member[] = []; - if (Array.isArray(members) && members.length) { - matchingMembers = members.filter((member: RoomMember) => isMemberMatch(member, termObj)); - } - - const memberObj: MemberObj = {}; - for (let i = 0; i < matchingMembers.length; i++) { - memberObj[matchingMembers[i].userId] = matchingMembers[i]; - } - - await loadFullHistory(client, room); - - // Search and return intermediary form of matches - const matches = findAllMatches(termObj, room, memberObj); - - // search context is reversed there ☝️, so fix - //matches.forEach(m => m.context = reverseEventContext(m.context)); - - // Process the matches to produce the equivalent result from a client.search() call - const searchResponse = getClientSearchResponse(searchResults, matches); - - // mimic the original code - const results = client.processRoomEventsSearch(searchResults, searchResponse); - - return results; -} - -/** - * Loads the full history of events for a given room. - * - * @param client - The Matrix client instance. - * @param room - The room for which to load the history. - * @returns A promise that resolves when the full history is loaded. - * @throws {Error} If the Matrix client is not initialized. - */ -async function loadFullHistory(client: MatrixClient | null, room: Room): Promise { - let hasMoreEvents = true; - do { - try { - // get the first neighbour of the live timeline on every iteration - // as each time we paginate, two timelines could have overlapped and connected, and the new - // pagination token ends up on the first one. - const timeline: EventTimeline | null = getFirstLiveTimelineNeighbour(room); - if (!timeline) { - throw new Error("Timeline not found"); - } - if (client && timeline) { - hasMoreEvents = await client.paginateEventTimeline(timeline, { limit: 100, backwards: true }); - } else { - throw new Error("Matrix client is not initialized"); - } - } catch (err: any) { - // deal with rate-limit error - if (err.name === "M_LIMIT_EXCEEDED") { - const waitTime = err.data.retry_after_ms; - await new Promise((r) => setTimeout(r, waitTime)); - } else { - throw err; - } - } - } while (hasMoreEvents); -} - -/** - * Retrieves the first live timeline neighbour of a given room. - * A live timeline neighbour is a timeline that is adjacent to the current timeline in the backwards direction. - * - * @param room - The room for which to retrieve the first live timeline neighbour. - * @returns The first live timeline neighbour if found, otherwise null. - */ -function getFirstLiveTimelineNeighbour(room: Room): EventTimeline | null { - const liveTimeline = room.getLiveTimeline(); - let timeline = liveTimeline; - while (timeline) { - const neighbour = timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS); - if (!neighbour) { - return timeline; - } - timeline = neighbour; - } - return null; -} - -/** - * Finds all matches in a room based on the given search term object and matching members. - * - * @param {SearchTerm} termObj - The search term object. - * @param {Room} room - The room to search in. - * @param {MemberObj} matchingMembers - The matching members. - * @returns {SearchResultItem[]} An array of search result items. - */ -export function findAllMatches(termObj: SearchTerm, room: Room, matchingMembers: MemberObj): SearchResultItem[] { - const matches: SearchResultItem[] = []; - let searchHit: SearchResultItem | null = null; - let prevEvent: MatrixEvent | null = null; - let timeline: EventTimeline | null = room.getLiveTimeline(); - - const iterationCallback = (roomEvent: MatrixEvent): void => { - if (searchHit !== null) { - searchHit.context.addEvents([roomEvent], false); - } - searchHit = null; - - if (roomEvent.getType() === "m.room.message" && !roomEvent.isRedacted()) { - if (eventMatchesSearchTerms(termObj, roomEvent, matchingMembers)) { - const evCtx = new EventContext(roomEvent); - if (prevEvent !== null) { - evCtx.addEvents([prevEvent], true); - } - - const resObj: SearchResultItem = { result: roomEvent, context: evCtx }; - matches.push(resObj); - searchHit = resObj; - } - - prevEvent = roomEvent; - } - }; - - // This code iterates over a timeline, retrieves events from the timeline, and invokes a callback function for each event in reverse order. - while (timeline) { - const events = timeline.getEvents(); - for (let i = events.length - 1; i >= 0; i--) { - iterationCallback(events[i]); - } - timeline = timeline.getNeighbouringTimeline(EventTimeline.FORWARDS); - } - - return matches; -} - -/** - * Checks if a room member matches the given search term. - * @param member - The room member to check. - * @param termObj - The search term object. - * @returns True if the member matches the search term, false otherwise. - */ -export function isMemberMatch(member: RoomMember, termObj: SearchTerm): boolean { - const memberName = member.name.toLowerCase(); - if (termObj.searchTypeAdvanced === true) { - const expResults = termObj.searchExpression && memberName.match(termObj.searchExpression); - if (expResults && expResults.length > 0) { - for (let i = 0; i < expResults.length; i++) { - if (termObj.regExpHighlightMap && !termObj.regExpHighlightMap[expResults[i]]) { - termObj.regExpHighlightMap[expResults[i]] = true; - termObj.regExpHighlights.push(expResults[i]); - } - } - return true; - } - return false; - } - - if (termObj.fullText && memberName.indexOf(termObj.fullText) > -1) { - return true; - } - - for (let i = 0; i < termObj.words.length; i++) { - const word = termObj.words[i].word; - if (memberName.indexOf(word) === -1) { - return false; - } - } - - return true; -} - -/** - * Checks if an event matches the given search terms. - * @param searchTermObj - The search term object containing the search criteria. - * @param evt - The Matrix event to be checked. - * @param matchingMembers - The object containing matching members. - * @returns True if the event matches the search terms, false otherwise. - */ -export function eventMatchesSearchTerms( - searchTermObj: SearchTerm, - evt: MatrixEvent, - matchingMembers: MemberObj, -): boolean { - const content = evt.getContent(); - const sender = evt.getSender(); - const loweredEventContent = content.body.toLowerCase(); - - const evtDate = evt.getDate(); - const dateIso = evtDate && evtDate.toISOString(); - const dateLocale = evtDate && evtDate.toLocaleString(); - - // if (matchingMembers[sender?.userId] !== undefined) { - if (sender && matchingMembers[sender] !== undefined) { - return true; - } - - if (searchTermObj.searchTypeAdvanced === true) { - const expressionResults = loweredEventContent.match(searchTermObj.searchExpression); - if (expressionResults && expressionResults.length > 0) { - for (let i = 0; i < expressionResults.length; i++) { - if (searchTermObj.regExpHighlightMap && !searchTermObj.regExpHighlightMap[expressionResults[i]]) { - searchTermObj.regExpHighlightMap[expressionResults[i]] = true; - searchTermObj.regExpHighlights.push(expressionResults[i]); - } - } - return true; - } - - let dateIsoExprResults; - let dateLocaleExprResults; - if (dateIso && dateLocale && searchTermObj.searchExpression instanceof RegExp) { - dateIsoExprResults = dateIso.match(searchTermObj.searchExpression); - dateLocaleExprResults = dateLocale.match(searchTermObj.searchExpression); - } - - if ( - (dateIsoExprResults && dateIsoExprResults.length > 0) || - (dateLocaleExprResults && dateLocaleExprResults.length > 0) - ) { - return true; - } - - return false; - } - - if (loweredEventContent.indexOf(searchTermObj.fullText) > -1) { - return true; - } - - if ( - (dateIso && searchTermObj.fullText && dateIso.indexOf(searchTermObj.fullText) > -1) || - (dateLocale && searchTermObj.fullText && dateLocale.indexOf(searchTermObj.fullText) > -1) - ) { - return true; - } - - if (searchTermObj.words.length > 0) { - for (let i = 0; i < searchTermObj.words.length; i++) { - const word = searchTermObj.words[i]; - if (loweredEventContent.indexOf(word) === -1) { - return false; - } - } - return true; - } - - return false; -} - -/** - * Creates a search term object based on the provided search term. - * @param searchTerm - The search term to create the object from. - * @returns The created search term object. - */ -export function makeSearchTermObject(searchTerm: string): SearchTerm { - let term = searchTerm.toLowerCase(); - if (term.indexOf("rx:") === 0) { - term = searchTerm.substring(3).trim(); - return { - searchTypeAdvanced: true, - searchTypeNormal: false, - searchExpression: new RegExp(term), - words: [], - regExpHighlights: [], - regExpHighlightMap: {}, - isEmptySearch: term.length === 0, - }; - } - - const words = term - .split(" ") - .filter((w) => w) - .map(function (w) { - return { word: w, highlight: false }; - }); - - return { - searchTypeAdvanced: false, - searchTypeNormal: true, - fullText: term, - words: words, - regExpHighlights: [], - isEmptySearch: term.length === 0, - }; -} - -/** - * Reverses the order of events in the given event context. - * - * @param {EventContext} context - The event context to reverse. - * @returns {EventContext} The reversed event context. - */ -export function reverseEventContext(eventContext: EventContext): EventContext { - const contextTimeline = eventContext.getTimeline(); - const ourEventIndex = eventContext.getOurEventIndex(); - const ourEvent = eventContext.getEvent(); - const reversedContext = new EventContext(contextTimeline[ourEventIndex]); - let afterOurEvent = false; - - for (let i = 0; i < contextTimeline.length; i++) { - const event = contextTimeline[i]; - if (event.getId() === ourEvent.getId()) { - afterOurEvent = true; - continue; - } - if (afterOurEvent) { - reversedContext.addEvents([event], true); - } else { - reversedContext.addEvents([event], false); - } - } - - return reversedContext; -} - -/** - * Transform the matches by projecting them into a ISearchResponse - * - * @param searchResults - The search results object to be updated. - * @param matches - An array of matches. - * @param termObj - The search term object. - * @returns The updated searchResults object. - */ -function getClientSearchResponse(searchResults: ISearchResults, matches: SearchResultItem[]): ISearchResponse { - const response: ISearchResponse = { - search_categories: { - room_events: { - count: 0, - highlights: [], - results: [], - }, - }, - }; - - response.search_categories.room_events.count = matches.length; - for (let i = 0; i < matches.length; i++) { - const reversedContext = reverseEventContext(matches[i].context); - - const sr = new SearchResult(0, reversedContext); - searchResults.results.push(sr); - } - - return response; -} diff --git a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx index 82a4456d5af..0316c43994d 100644 --- a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx +++ b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx @@ -181,8 +181,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { PosthogTrackers.trackInteraction("WebHomeCreateChatButton", ev); @@ -66,8 +63,7 @@ const getOwnProfile = ( }); const UserWelcomeTop: React.FC = () => { - // const cli = useContext(MatrixClientContext); - const cli = MatrixClientPeg.safeGet(); + const cli = useContext(MatrixClientContext); const userId = cli.getUserId()!; const [ownProfile, setOwnProfile] = useState(getOwnProfile(userId)); useEventEmitter(OwnProfileStore.instance, UPDATE_EVENT, () => { @@ -98,38 +94,6 @@ const UserWelcomeTop: React.FC = () => { ); }; -// //Buttons on homepage can be enabled (true), or disabled (false) setting the UIFeature.HomePageButtons in settings.tsx -// const ShowButtons = () => { -// return ( -//
-// -// {_tDom("onboarding|send_dm")} -// -// -// {_tDom("onboarding|explore_rooms")} -// -// -// {_tDom("onboarding|create_room")} -// -//
-// ) -// } - -//Buttons on homepage can be enabled (true), or disabled (false) setting the UIFeature.HomePageButtons in settings.tsx -const showButtons = ( -
- - {_tDom("onboarding|send_dm")} - - - {_tDom("onboarding|explore_rooms")} - - - {_tDom("onboarding|create_room")} - -
-); - const HomePage: React.FC = ({ justRegistered = false }) => { const cli = useMatrixClientContext(); const config = SdkConfig.get(); @@ -159,8 +123,17 @@ const HomePage: React.FC = ({ justRegistered = false }) => {
{introSection} - {/* {SettingsStore.getValue(UIFeature.HomePageButtons) && } */} - {SettingsStore.getValue(UIFeature.HomePageButtons) && showButtons} +
+ + {_tDom("onboarding|send_dm")} + + + {_tDom("onboarding|explore_rooms")} + + + {_tDom("onboarding|create_room")} + +
); diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx index 7002236bf63..084afdaf8ba 100644 --- a/src/components/structures/LeftPanel.tsx +++ b/src/components/structures/LeftPanel.tsx @@ -39,12 +39,11 @@ import IndicatorScrollbar from "./IndicatorScrollbar"; import RoomBreadcrumbs from "../views/rooms/RoomBreadcrumbs"; import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts"; import { shouldShowComponent } from "../../customisations/helpers/UIComponents"; -import { UIComponent, UIFeature } from "../../settings/UIFeature"; +import { UIComponent } from "../../settings/UIFeature"; import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton"; import PosthogTrackers from "../../PosthogTrackers"; import PageType from "../../PageTypes"; import { UserOnboardingButton } from "../views/user-onboarding/UserOnboardingButton"; -import SettingsStore from "../../settings/SettingsStore"; interface IProps { isMinimized: boolean; @@ -342,11 +341,7 @@ export default class LeftPanel extends React.Component { } let rightButton: JSX.Element | undefined; - if ( - SettingsStore.getValue(UIFeature.ShowExploreRoomsButton) && - this.state.activeSpace === MetaSpace.Home && - shouldShowComponent(UIComponent.ExploreRooms) - ) { + if (this.state.activeSpace === MetaSpace.Home && shouldShowComponent(UIComponent.ExploreRooms)) { rightButton = ( { OwnProfileStore.instance.on(UPDATE_EVENT, this.refreshBackgroundImage); this.loadResizerPreferences(); this.refreshBackgroundImage(); - this.attachFreshworksWidget(); //Verji } public componentWillUnmount(): void { @@ -216,20 +210,6 @@ class LoggedInView extends React.Component { this.resizer?.detach(); } - // Verji start - private attachFreshworksWidget(): void { - const head = document.querySelector("head"); - const script = document.createElement("script"); - const scriptExt = document.createElement("script"); - script.setAttribute("src", "./scripts/freshworks.js"); - scriptExt.setAttribute("src", "https://euc-widget.freshworks.com/widgets/80000004505.js"); - scriptExt.async = true; - scriptExt.defer = true; - head?.appendChild(script); - head?.appendChild(scriptExt); - } - // Verji end - private onCallState = (): void => { const activeCalls = LegacyCallHandler.instance.getAllActiveCalls(); if (activeCalls === this.state.activeCalls) return; @@ -691,58 +671,43 @@ class LoggedInView extends React.Component { return ; }); - const customLoggedInViewOpts = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke( - CustomComponentLifecycle.LoggedInView, - customLoggedInViewOpts as CustomComponentOpts, - ); - const customSpacePanelOpts = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke(CustomComponentLifecycle.SpacePanel, customSpacePanelOpts as CustomComponentOpts); - const customLeftPanelOpts = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke(CustomComponentLifecycle.LeftPanel, customLeftPanelOpts as CustomComponentOpts); return ( - - -
- -
-
- -
- - - - - -
- - - -
+ +
+ +
+
+ +
+ + + +
+
- -
{pageElement}
+ +
{pageElement}
- - - {audioFeedArraysForCalls} - - +
+ + + {audioFeedArraysForCalls} +
); } } diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index c43d3179ab7..5e50f68b48c 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -32,12 +32,9 @@ import { logger } from "matrix-js-sdk/src/logger"; import { throttle } from "lodash"; import { CryptoEvent } from "matrix-js-sdk/src/crypto"; import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup"; + // what-input helps improve keyboard accessibility import "what-input"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; import type NewRecoveryMethodDialog from "../../async-components/views/dialogs/security/NewRecoveryMethodDialog"; import type RecoveryMethodRemovedDialog from "../../async-components/views/dialogs/security/RecoveryMethodRemovedDialog"; @@ -443,9 +440,8 @@ export default class MatrixChat extends React.PureComponent { // if the user has previously set up cross-signing, verify this device so we can fetch the // private keys. - // if (SecurityCustomisations.SHOW_ENCRYPTION_SETUP_UI === false) { const cryptoExtension = ModuleRunner.instance.extensions.cryptoSetup; - if (cryptoExtension !== undefined && cryptoExtension.SHOW_ENCRYPTION_SETUP_UI == false) { + if (cryptoExtension.SHOW_ENCRYPTION_SETUP_UI == false) { this.onLoggedIn(); } else { this.setStateForNewView({ view: Views.COMPLETE_SECURITY }); @@ -945,35 +941,6 @@ export default class MatrixChat extends React.PureComponent { true, ); break; - // VERJI - case Action.OpenInviteExternalUsersDialog: { - const customOnboardingOpts = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke( - CustomComponentLifecycle.Experimental, - customOnboardingOpts as CustomComponentOpts, - ); - const Props = (props: any): React.JSX.Element =>
{props}
; - const customOnboardingDialog = (props: any): React.JSX.Element => ( - - - - ); - console.log("[Verji.Onboarding - Action.OpenInviteExternalUsers]", payload.data); - Modal.createDialog( - customOnboardingDialog, - { - initialText: payload.initialText, - data: payload?.data, - onFinished: () => { - Modal.toggleCurrentDialogVisibility(); - }, - }, - "mx_RoomDirectory_dialogWrapper", - false, - true, - ); - } - // END VERJI } }; diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 4aae7987628..a15ddbf7742 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -44,10 +44,6 @@ import { CallState, MatrixCall } from "matrix-js-sdk/src/webrtc/call"; import { throttle } from "lodash"; import { CryptoEvent } from "matrix-js-sdk/src/crypto"; import { ViewRoomOpts } from "@matrix-org/react-sdk-module-api/lib/lifecycles/RoomViewLifecycle"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; import shouldHideEvent from "../../shouldHideEvent"; import { _t } from "../../languageHandler"; @@ -125,6 +121,7 @@ import { SDKContext } from "../../contexts/SDKContext"; import { CallStore, CallStoreEvent } from "../../stores/CallStore"; import { Call } from "../../models/Call"; import { RoomSearchView } from "./RoomSearchView"; +import eventSearch from "../../Searching"; import VoipUserMapper from "../../VoipUserMapper"; import { isCallEvent } from "./LegacyCallEventGrouper"; import { WidgetType } from "../../widgets/WidgetType"; @@ -136,10 +133,6 @@ import { CancelAskToJoinPayload } from "../../dispatcher/payloads/CancelAskToJoi import { SubmitAskToJoinPayload } from "../../dispatcher/payloads/SubmitAskToJoinPayload"; import RightPanelStore from "../../stores/right-panel/RightPanelStore"; import { onView3pidInvite } from "../../stores/right-panel/action-handlers"; -import { ModuleRunner } from "../../modules/ModuleRunner"; -// import eventSearch from "../../Searching"; -import searchAllEventsLocally from "../../VerjiLocalSearch"; // VERJI -import eventSearch from "../../Searching"; const DEBUG = false; const PREVENT_MULTIPLE_JITSI_WITHIN = 30_000; @@ -321,33 +314,30 @@ function LocalRoomView(props: LocalRoomViewProps): ReactElement { /> ); } - const customRoomHeaderOpts = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke(CustomComponentLifecycle.RoomHeader, customRoomHeaderOpts as CustomComponentOpts); + return (
- - {SettingsStore.getValue("feature_new_room_decoration_ui") ? ( - - ) : ( - - )} - + {SettingsStore.getValue("feature_new_room_decoration_ui") ? ( + + ) : ( + + )}
@@ -378,33 +368,29 @@ interface ILocalRoomCreateLoaderProps { */ function LocalRoomCreateLoader(props: ILocalRoomCreateLoaderProps): ReactElement { const text = _t("room|creating_room_text", { names: props.names }); - const customRoomHeaderOpts = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke(CustomComponentLifecycle.RoomHeader, customRoomHeaderOpts as CustomComponentOpts); return (
- - {SettingsStore.getValue("feature_new_room_decoration_ui") ? ( - - ) : ( - - )} - + {SettingsStore.getValue("feature_new_room_decoration_ui") ? ( + + ) : ( + + )}
@@ -1736,16 +1722,7 @@ export class RoomView extends React.Component { const roomId = scope === SearchScope.Room ? this.getRoomId() : undefined; debuglog("sending search request"); const abortController = new AbortController(); - - // VERJI START - let promise: Promise; - // currently, we use the local search for all events. edit this 'if' statement to change that. - if (scope === SearchScope.Room || scope === SearchScope.All) { - promise = searchAllEventsLocally(this.context.client!, term, roomId); - } else { - promise = eventSearch(this.context.client!, term, roomId, abortController.signal); - } - // VERJI END + const promise = eventSearch(this.context.client!, term, roomId, abortController.signal); this.setState({ search: { @@ -2538,9 +2515,6 @@ export class RoomView extends React.Component { const showChatEffects = SettingsStore.getValue("showChatEffects"); - const customAppsDrawerOpts = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke(CustomComponentLifecycle.AppsDrawer, customAppsDrawerOpts as CustomComponentOpts); - let mainSplitBody: JSX.Element | undefined; let mainSplitContentClassName: string | undefined; // Decide what to show in the main split @@ -2570,15 +2544,13 @@ export class RoomView extends React.Component { mainSplitContentClassName = "mx_MainSplit_maximisedWidget"; mainSplitBody = ( <> - - - + {previewBar} ); @@ -2633,70 +2605,62 @@ export class RoomView extends React.Component { (([KnownMembership.Leave, KnownMembership.Ban] as Array).includes(myMembership) || myMember?.isKicked()); - const CustomRoomView = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke(CustomComponentLifecycle.RoomView, CustomRoomView as CustomComponentOpts); - const customRoomHeaderOpts = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke(CustomComponentLifecycle.RoomHeader, customRoomHeaderOpts as CustomComponentOpts); return ( - - -
- {showChatEffects && this.roomView.current && ( - - )} - - +
+ {showChatEffects && this.roomView.current && ( + + )} + + +
-
- - {SettingsStore.getValue("feature_new_room_decoration_ui") ? ( - - ) : ( - - )} - - {mainSplitBody} -
- - -
- - + {SettingsStore.getValue("feature_new_room_decoration_ui") ? ( + + ) : ( + + )} + {mainSplitBody} +
+
+
+
+
); } } diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index b43b5ffeea9..a99a22687e0 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -279,25 +279,19 @@ const SpaceLanding: React.FC<{ space: Room }> = ({ space }) => {
- {SettingsStore.getValue(UIFeature.ShowMembersListForSpaces) && ( - - )} - {SettingsStore.getValue(UIFeature.ShowAddMoreButtonForSpaces) && inviteButton} + + {inviteButton} {settingsButton}
- {SettingsStore.getValue(UIFeature.ShowSpaceLandingPageDetails) && ( - <> - - - )} +
); }; diff --git a/src/components/structures/ViewSource.tsx b/src/components/structures/ViewSource.tsx index c93c2e7e9fe..edda7bd9d37 100644 --- a/src/components/structures/ViewSource.tsx +++ b/src/components/structures/ViewSource.tsx @@ -21,7 +21,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/matrix"; import SyntaxHighlight from "../views/elements/SyntaxHighlight"; import { _t } from "../../languageHandler"; import MatrixClientContext from "../../contexts/MatrixClientContext"; -// import { canEditContent } from "../../utils/EventUtils"; //Verji +import { canEditContent } from "../../utils/EventUtils"; import { MatrixClientPeg } from "../../MatrixClientPeg"; import BaseDialog from "../views/dialogs/BaseDialog"; import { DevtoolsContext } from "../views/dialogs/devtools/BaseTool"; @@ -155,9 +155,9 @@ export default class ViewSource extends React.Component { const isEditing = this.state.isEditing; const roomId = mxEvent.getRoomId()!; const eventId = mxEvent.getId()!; - // const canEdit = mxEvent.isState() //Verji - // ? this.canSendStateEvent(mxEvent) - // : canEditContent(MatrixClientPeg.safeGet(), this.props.mxEvent); + const canEdit = mxEvent.isState() + ? this.canSendStateEvent(mxEvent) + : canEditContent(MatrixClientPeg.safeGet(), this.props.mxEvent); return (
@@ -176,17 +176,11 @@ export default class ViewSource extends React.Component { )}
{isEditing ? this.editSourceContent() : this.viewSourceContent()} - {/* NOTE: Verji - Removed the Edit button as we have no use for it at the moment. */} - {/* {!isEditing && canEdit && ( + {!isEditing && canEdit && (
- +
- )} */} - -
- -
- {/* Verji end */} + )}
); } diff --git a/src/components/structures/auth/Login.tsx b/src/components/structures/auth/Login.tsx index 6911977d20b..5fadde7cbea 100644 --- a/src/components/structures/auth/Login.tsx +++ b/src/components/structures/auth/Login.tsx @@ -546,30 +546,23 @@ export default class LoginComponent extends React.PureComponent } return ( -
- {SettingsStore.getValue(UIFeature.EnableLoginPage) && ( - <> - - - -

- {_t("action|sign_in")} - {loader} -

- {errorTextSection} - {serverDeadSection} - - {this.renderLoginComponentForFlows()} - {footer} -
-
- - )} - ; -
+ + + +

+ {_t("action|sign_in")} + {loader} +

+ {errorTextSection} + {serverDeadSection} + + {this.renderLoginComponentForFlows()} + {footer} +
+
); } } diff --git a/src/components/structures/auth/SetupEncryptionBody.tsx b/src/components/structures/auth/SetupEncryptionBody.tsx index 61b72e77866..684a7b5af4e 100644 --- a/src/components/structures/auth/SetupEncryptionBody.tsx +++ b/src/components/structures/auth/SetupEncryptionBody.tsx @@ -28,8 +28,6 @@ import { SetupEncryptionStore, Phase } from "../../../stores/SetupEncryptionStor import EncryptionPanel from "../../views/right_panel/EncryptionPanel"; import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleButton"; import Spinner from "../../views/elements/Spinner"; -import { UIFeature } from "../../../settings/UIFeature"; -import SettingsStore from "../../../settings/SettingsStore"; function keyHasPassphrase(keyInfo: SecretStorageKeyDescription): boolean { return Boolean(keyInfo.passphrase && keyInfo.passphrase.salt && keyInfo.passphrase.iterations); @@ -205,23 +203,19 @@ export default class SetupEncryptionBody extends React.Component {verifyButton} {useRecoveryKeyButton}
- {SettingsStore.getValue(UIFeature.SetupEncryptionResetButton) && ( - <> -
- {_t("encryption|reset_all_button", undefined, { - a: (sub) => ( - - {sub} - - ), - })} -
- - )} +
+ {_t("encryption|reset_all_button", undefined, { + a: (sub) => ( + + {sub} + + ), + })} +
); } diff --git a/src/components/structures/grouper/CreationGrouper.tsx b/src/components/structures/grouper/CreationGrouper.tsx index bde86724753..fa91a1bd90c 100644 --- a/src/components/structures/grouper/CreationGrouper.tsx +++ b/src/components/structures/grouper/CreationGrouper.tsx @@ -27,8 +27,6 @@ import DateSeparator from "../../views/messages/DateSeparator"; import NewRoomIntro from "../../views/rooms/NewRoomIntro"; import GenericEventListSummary from "../../views/elements/GenericEventListSummary"; import { SeparatorKind } from "../../views/messages/TimelineSeparator"; -import SettingsStore from "../../../settings/SettingsStore"; -import { UIFeature } from "../../../settings/UIFeature"; // Wrap initial room creation events into a GenericEventListSummary // Grouping only events sent by the same user that sent the `m.room.create` and only until @@ -143,9 +141,7 @@ export class CreationGrouper extends BaseGrouper { summaryText = _t("timeline|creation_summary_room", { creator }); } - { - SettingsStore.getValue(UIFeature.EnableNewRoomIntro) && ret.push(); - } + ret.push(); ret.push( private checkPermissions = (): void => { const cli = MatrixClientPeg.safeGet(); const room = cli.getRoom(this.props.mxEvent.getRoomId()); - const roomState = room?.getLiveTimeline().getState(EventTimeline.FORWARDS); // Verji // We explicitly decline to show the redact option on ACL events as it has a potential // to obliterate the room - https://github.com/matrix-org/synapse/issues/4042 // Similarly for encryption events, since redacting them "breaks everything" - // Verji start, adds more events to prevent redact - let redactable = true; - if ( - this.props.mxEvent?.event?.type?.includes(".avatar") || - this.props.mxEvent?.event?.type?.includes(".topic") || - this.props.mxEvent.getType() === EventType.RoomMember || - this.props.mxEvent.getType() === EventType.RoomJoinRules || - this.props.mxEvent.getType() === EventType.RoomPowerLevels || - this.props.mxEvent.getType() === EventType.RoomHistoryVisibility || - this.props.mxEvent.getType() === EventType.RoomGuestAccess || - this.props.mxEvent.getType() === EventType.RoomName || - this.props.mxEvent.getType() === EventType.RoomTopic - ) { - redactable = false; - } const canRedact = - //!!roomState?.maySendRedactionForEvent(this.props.mxEvent, cli.getSafeUserId()) && !!room?.currentState.maySendRedactionForEvent(this.props.mxEvent, cli.getSafeUserId()) && this.props.mxEvent.getType() !== EventType.RoomServerAcl && - this.props.mxEvent.getType() !== EventType.RoomEncryption && - redactable; - //Verji end + this.props.mxEvent.getType() !== EventType.RoomEncryption; let canPin = - !!roomState?.mayClientSendStateEvent(EventType.RoomPinnedEvents, cli) && canPinEvent(this.props.mxEvent); + !!room?.currentState.mayClientSendStateEvent(EventType.RoomPinnedEvents, cli) && + canPinEvent(this.props.mxEvent); // HACK: Intentionally say we can't pin if the user doesn't want to use the functionality if (!SettingsStore.getValue("feature_pinning")) canPin = false; @@ -213,19 +189,16 @@ export default class MessageContextMenu extends React.Component private isPinned(): boolean { const room = MatrixClientPeg.safeGet().getRoom(this.props.mxEvent.getRoomId()); - const roomState = room?.getLiveTimeline().getState(EventTimeline.FORWARDS); // Verji - const pinnedEvent = roomState?.getStateEvents(EventType.RoomPinnedEvents, ""); + const pinnedEvent = room?.currentState.getStateEvents(EventType.RoomPinnedEvents, ""); if (!pinnedEvent) return false; const content = pinnedEvent.getContent(); return content.pinned && Array.isArray(content.pinned) && content.pinned.includes(this.props.mxEvent.getId()); } private canEndPoll(mxEvent: MatrixEvent): boolean { - // ROSBERG isMyEvent to overide verji strict canRedact rules - in case where ender of the poll is the owner of the poll - const isMyEvent = mxEvent.sender?.userId === MatrixClientPeg.safeGet().getSafeUserId(); return ( M_POLL_START.matches(mxEvent.getType()) && - (this.state.canRedact || isMyEvent) && // Verji - evaluates to true if you are admin OR the event is yours + this.state.canRedact && !isPollEnded(mxEvent, MatrixClientPeg.safeGet()) ); } @@ -409,7 +382,7 @@ export default class MessageContextMenu extends React.Component public render(): React.ReactNode { const cli = MatrixClientPeg.safeGet(); - // const me = cli.getUserId(); //Verji + const me = cli.getUserId(); const { mxEvent, rightClick, link, eventTileOps, reactions, collapseReplyChain, ...other } = this.props; delete other.getRelationsForEvent; delete other.permalinkCreator; @@ -417,7 +390,7 @@ export default class MessageContextMenu extends React.Component const eventStatus = mxEvent.status; const unsentReactionsCount = this.getUnsentReactions().length; const contentActionable = isContentActionable(mxEvent); - // const permalink = this.props.permalinkCreator?.forEvent(this.props.mxEvent.getId()!); //Verji + const permalink = this.props.permalinkCreator?.forEvent(this.props.mxEvent.getId()!); // status is SENT before remote-echo, null after const isSent = !eventStatus || eventStatus === EventStatus.SENT; const { timelineRenderingType, canReact, canSendMessages } = this.context; @@ -510,27 +483,25 @@ export default class MessageContextMenu extends React.Component ); } - // Verji start - // let permalinkButton: JSX.Element | undefined; - // if (permalink) { - // permalinkButton = ( - // - // ); - // } - // Verji end + let permalinkButton: JSX.Element | undefined; + if (permalink) { + permalinkButton = ( + + ); + } let endPollButton: JSX.Element | undefined; if (this.canEndPoll(mxEvent)) { @@ -590,18 +561,16 @@ export default class MessageContextMenu extends React.Component ); } - // Verji start - // let reportEventButton: JSX.Element | undefined; - // if (mxEvent.getSender() !== me) { - // reportEventButton = ( - // - // ); - // } - // Verji end + let reportEventButton: JSX.Element | undefined; + if (mxEvent.getSender() !== me) { + reportEventButton = ( + + ); + } let copyLinkButton: JSX.Element | undefined; if (link) { @@ -720,8 +689,8 @@ export default class MessageContextMenu extends React.Component {endPollButton} {forwardButton} {pinButton} - {/*Verji removed {permalinkButton} */} - {/*Verji removed {reportEventButton} */} + {permalinkButton} + {reportEventButton} {externalURLButton} {jumpToRelatedEventButton} {unhidePreviewButton} @@ -746,29 +715,21 @@ export default class MessageContextMenu extends React.Component ); } - const CustomMessageContextMenu = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke( - CustomComponentLifecycle.MessageContextMenu, - CustomMessageContextMenu as CustomComponentOpts, - ); - return ( - - - - {nativeItemsList} - {quickItemsList} - {commonItemsList} - {redactItemList} - - {reactionPicker} - - + + + {nativeItemsList} + {quickItemsList} + {commonItemsList} + {redactItemList} + + {reactionPicker} + ); } } diff --git a/src/components/views/context_menus/RoomContextMenu.tsx b/src/components/views/context_menus/RoomContextMenu.tsx index 7a85a602a70..3c77f32cb37 100644 --- a/src/components/views/context_menus/RoomContextMenu.tsx +++ b/src/components/views/context_menus/RoomContextMenu.tsx @@ -49,7 +49,7 @@ import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import SettingsStore from "../../../settings/SettingsStore"; import { SdkContextClass } from "../../../contexts/SDKContext"; import { shouldShowComponent } from "../../../customisations/helpers/UIComponents"; -import { UIComponent, UIFeature } from "../../../settings/UIFeature"; +import { UIComponent } from "../../../settings/UIFeature"; import { DeveloperToolsOption } from "./DeveloperToolsOption"; import { tagRoom } from "../../../utils/room/tagRoom"; @@ -254,7 +254,7 @@ const RoomContextMenu: React.FC = ({ room, onFinished, ...props }) => { } let filesOption: JSX.Element | undefined; - if (!isVideoRoom && SettingsStore.getValue(UIFeature.RoomSummaryFilesOption)) { + if (!isVideoRoom) { filesOption = ( { diff --git a/src/components/views/context_menus/SpaceContextMenu.tsx b/src/components/views/context_menus/SpaceContextMenu.tsx index 383e399cf84..13a5463ab73 100644 --- a/src/components/views/context_menus/SpaceContextMenu.tsx +++ b/src/components/views/context_menus/SpaceContextMenu.tsx @@ -193,7 +193,7 @@ const SpaceContextMenu: React.FC = ({ space, hideHeader, onFinished, ... )} - {SettingsStore.getValue(UIFeature.AddSubSpace) && canAddSubSpaces && ( + {canAddSubSpaces && ( , "children"> { app: IWidget; @@ -273,7 +272,7 @@ export const WidgetContextMenu: React.FC = ({ {streamAudioStreamButton} {editButton} {revokeButton} - {SettingsStore.getValue(UIFeature.WidgetContextDeleteButton) && deleteButton} + {deleteButton} {snapshotButton} {moveLeftButton} {moveRightButton} diff --git a/src/components/views/dialogs/CreateRoomDialog.tsx b/src/components/views/dialogs/CreateRoomDialog.tsx index 2d2d376e01d..a1fdc13f299 100644 --- a/src/components/views/dialogs/CreateRoomDialog.tsx +++ b/src/components/views/dialogs/CreateRoomDialog.tsx @@ -34,7 +34,6 @@ import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { privateShouldBeEncrypted } from "../../../utils/rooms"; import SettingsStore from "../../../settings/SettingsStore"; import LabelledCheckbox from "../elements/LabelledCheckbox"; -import { UIFeature } from "../../../settings/UIFeature"; interface IProps { type?: RoomType; @@ -413,51 +412,37 @@ export default class CreateRoomDialog extends React.Component { className="mx_CreateRoomDialog_topic" /> - {/* For those who only want to create private room, set the CreateRoomShowJoinRuleDropdown to false in settings.tsx, - for public rooms and knock rooms, set the flag to true */} - {SettingsStore.getValue(UIFeature.CreateRoomShowJoinRuleDropdown) && ( - <> - - - )} + {publicPrivateLabel} {visibilitySection} - {/* To create only encrypted room, the options can be hidden by setting the flag to false in in settings.tsx, */} - {SettingsStore.getValue(UIFeature.CreateRoomE2eeSection) && e2eeSection} + {e2eeSection} {aliasField} - {/* To limit the usage to only your server, set flag to false in in settings.tsx, */} - {SettingsStore.getValue(UIFeature.CreateRoomShowAdvancedSettings) && ( - <> -
- - {this.state.detailsOpen - ? _t("action|hide_advanced") - : _t("action|show_advanced")} - - -

{federateLabel}

-
- - )} +
+ + {this.state.detailsOpen ? _t("action|hide_advanced") : _t("action|show_advanced")} + + +

{federateLabel}

+
= ({ roomId, threadRootId, onFinished })

{_t(categoryLabels[category as unknown as Category])}

{tools.map(([label, tool]) => { - if ( - (tool != VerificationExplorer && tool != TimelineEventEditor) || - ((tool === VerificationExplorer || tool === TimelineEventEditor) && - SettingsStore.getValue(UIFeature.EnableRoomDevTools)) - ) { - const onClick = (): void => { - setTool([label, tool]); - }; - return ( - - ); - } + const onClick = (): void => { + setTool([label, tool]); + }; + return ( + + ); })}
))} diff --git a/src/components/views/dialogs/ExportDialog.tsx b/src/components/views/dialogs/ExportDialog.tsx index 39e4629f66f..6645ce0b016 100644 --- a/src/components/views/dialogs/ExportDialog.tsx +++ b/src/components/views/dialogs/ExportDialog.tsx @@ -42,8 +42,6 @@ import Spinner from "../elements/Spinner"; import InfoDialog from "./InfoDialog"; import ChatExport from "../../../customisations/ChatExport"; import { validateNumberInRange } from "../../../utils/validate"; -import SettingsStore from "../../../settings/SettingsStore"; -import { UIFeature } from "../../../settings/UIFeature"; interface IProps { room: Room; @@ -72,20 +70,10 @@ const useExportFormState = (): ExportConfig => { const config = ChatExport.getForceChatExportParameters(); const [exportFormat, setExportFormat] = useState(config.format ?? ExportFormat.Html); - const [exportType, setExportType] = useState( - SettingsStore.getValue(UIFeature.AllExportTypes) == false - ? ExportType.Beginning - : config.range ?? ExportType.Timeline, - ); - const [includeAttachments, setAttachments] = useState( - SettingsStore.getValue(UIFeature.ExportAttatchmentsDefaultOff) == false - ? true - : config.includeAttachments ?? false, - ); + const [exportType, setExportType] = useState(config.range ?? ExportType.Timeline); + const [includeAttachments, setAttachments] = useState(config.includeAttachments ?? false); const [numberOfMessages, setNumberOfMessages] = useState(config.numberOfMessages ?? 100); - const [sizeLimit, setSizeLimit] = useState( - SettingsStore.getValue(UIFeature.ExportDefaultSizeLimit) == false ? 20 : config.sizeMb ?? 8, - ); + const [sizeLimit, setSizeLimit] = useState(config.sizeMb ?? 8); return { exportFormat, @@ -131,9 +119,6 @@ const ExportDialog: React.FC = ({ room, onFinished }) => { }, ); - // setExporter(ExportType.[Beginning as ExportTypeKey]); - // setNumberOfMessages(parseInt(e.target.value)); - const startExport = async (): Promise => { const exportOptions = { numberOfMessages, @@ -363,7 +348,7 @@ const ExportDialog: React.FC = ({ room, onFinished }) => { )} - {!!setExportType && SettingsStore.getValue(UIFeature.AllExportTypes) && ( + {!!setExportType && ( <> {_t("export_chat|messages")} @@ -381,7 +366,7 @@ const ExportDialog: React.FC = ({ room, onFinished }) => { )} - {setSizeLimit && SettingsStore.getValue(UIFeature.ExportDefaultSizeLimit) && ( + {setSizeLimit && ( <> {_t("export_chat|size_limit")} diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index d798ad56d2a..bb81d7a05f0 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -16,7 +16,7 @@ limitations under the License. import React, { createRef, ReactNode, SyntheticEvent } from "react"; import classNames from "classnames"; -import { RoomMember, Room, EventType } from "matrix-js-sdk/src/matrix"; //VERJI remove: MatrixError, EventType +import { RoomMember, Room, MatrixError, EventType } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; import { MatrixCall } from "matrix-js-sdk/src/webrtc/call"; import { logger } from "matrix-js-sdk/src/logger"; @@ -70,39 +70,37 @@ import Modal from "../../../Modal"; import dis from "../../../dispatcher/dispatcher"; import { privateShouldBeEncrypted } from "../../../utils/rooms"; import { NonEmptyArray } from "../../../@types/common"; -// VERJI Remove: import { UNKNOWN_PROFILE_ERRORS } from "../../../utils/MultiInviter"; -// VERJI Remove: import AskInviteAnywayDialog, { UnknownProfiles } from "./AskInviteAnywayDialog"; +import { UNKNOWN_PROFILE_ERRORS } from "../../../utils/MultiInviter"; +import AskInviteAnywayDialog, { UnknownProfiles } from "./AskInviteAnywayDialog"; import { SdkContextClass } from "../../../contexts/SDKContext"; import { UserProfilesStore } from "../../../stores/UserProfilesStore"; -import { Key } from "../../../Keyboard"; // we have a number of types defined from the Matrix spec which can't reasonably be altered here. /* eslint-disable camelcase */ -// const extractTargetUnknownProfiles = async ( -// targets: Member[], -// targetEmails: string[], // Verji -// profilesStores: UserProfilesStore, -// ): Promise => { -// const directoryMembers = targets.filter((t): t is DirectoryMember => t instanceof DirectoryMember); -// await Promise.all(directoryMembers.map((t) => profilesStores.getOrFetchProfile(t.userId))); -// return directoryMembers.reduce((unknownProfiles: UnknownProfiles, target: DirectoryMember) => { -// const lookupError = profilesStores.getProfileLookupError(target.userId); - -// if ( -// lookupError instanceof MatrixError && -// lookupError.errcode && -// UNKNOWN_PROFILE_ERRORS.includes(lookupError.errcode) -// ) { -// unknownProfiles.push({ -// userId: target.userId, -// errorText: lookupError.data.error || "", -// }); -// } - -// return unknownProfiles; -// }, []); -// }; +const extractTargetUnknownProfiles = async ( + targets: Member[], + profilesStores: UserProfilesStore, +): Promise => { + const directoryMembers = targets.filter((t): t is DirectoryMember => t instanceof DirectoryMember); + await Promise.all(directoryMembers.map((t) => profilesStores.getOrFetchProfile(t.userId))); + return directoryMembers.reduce((unknownProfiles: UnknownProfiles, target: DirectoryMember) => { + const lookupError = profilesStores.getProfileLookupError(target.userId); + + if ( + lookupError instanceof MatrixError && + lookupError.errcode && + UNKNOWN_PROFILE_ERRORS.includes(lookupError.errcode) + ) { + unknownProfiles.push({ + userId: target.userId, + errorText: lookupError.data.error || "", + }); + } + + return unknownProfiles; + }, []); +}; interface Result { userId: string; @@ -156,72 +154,7 @@ class DMUserTile extends React.PureComponent { ); } } -/* VERJI START */ -class DMEmailTile extends React.PureComponent { - private onRemove = (e: any): void => { - // Stop the browser from highlighting text - e.preventDefault(); - e.stopPropagation(); - console.log(e); - const asMember: Member = { - name: this.props.email, - userId: this.props.email, - getMxcAvatarUrl: () => { - return ""; - }, - }; - if (this.props.onRemove) { - this.props.onRemove(asMember); - } - }; - public render(): any { - let closeButton; - if (this.props.onRemove) { - closeButton = ( - - - - - - - - - - - - - - - - - - - ); - } - - return ( - - - {this.props?.email ?? ""} - - {closeButton} - - ); - } -} -/* VERJI END */ /** * Converts a RoomMember to a Member. * Returns the Member if it is already a Member. @@ -393,7 +326,6 @@ type Props = InviteDMProps | InviteRoomProps | InviteCallProps; interface IInviteDialogState { targets: Member[]; // array of Member objects (see interface above) - targetEmails: string[]; // Verji filterText: string; recents: Result[]; numRecentsShown: number; @@ -424,7 +356,6 @@ export default class InviteDialog extends React.PureComponent { - // rosberg start - this.setState({ busy: true }); - - let foundUser = false; - try { - await MatrixClientPeg.get() - ?.searchUserDirectory({ term: this.state.filterText.trim().split(":")[0] ?? this.state.filterText }) - .then(async (r) => { - this.setState({ busy: false }); - - if (r.results.find((e) => e.user_id == this.state.filterText.trim())) { - foundUser = true; - } - }); - } catch (error) { - console.error("Failed to searchUserDirectory: ", error); - } - - const currentUserId: string | undefined = MatrixClientPeg.getCredentials()?.userId.trim(); - if (currentUserId && currentUserId == this.state.filterText.trim()) { - this.setState({ busy: false }); - return [{ userId: currentUserId }] as Member[]; - } - - if (foundUser == false) { - // Look in other stores for user if search might have failed unexpectedly - const possibleMembers = [ - ...this.state.recents, - ...this.state.suggestions, - ...this.state.serverResultsMixin, - ...this.state.threepidResultsMixin, - ]; - const toAdd = []; - const potentialAddresses = this.state.filterText - .split(/[\s,]+/) - .map((p) => p.trim()) - .filter((p) => !!p); // filter empty strings - for (const address of potentialAddresses) { - const member = possibleMembers.find((m) => m.userId === address); - if (member) { - toAdd.push(member.user); - continue; - } - } - - if (!toAdd?.length || toAdd?.length == 0) { - //return [] as Member[]; - } - } + private convertFilter(): Member[] { // Check to see if there's anything to convert first if (!this.state.filterText || !this.state.filterText.includes("@")) return this.state.targets || []; @@ -675,80 +536,45 @@ export default class InviteDialog extends React.PureComponent { - if (_email == newEmail) { - this.setState({ filterText: text ? this.state.filterText : "" }); - return this.state.targetEmails; - } - }); - const newTargetsToInvite = [...(this.state.targetEmails || []), newEmail]; - - this.setState({ targets: [], targetEmails: newTargetsToInvite, filterText: text ? this.state.filterText : "" }); - - console.log("[Verji.InviteDialog] - Onboarding: " + newTargetsToInvite); - return newTargetsToInvite; - } - private startInviteByEmail = async (): Promise => { - this.props.onFinished(false); - let _externals = this.state.targetEmails; - if (_externals == null) _externals = []; - if (Email.looksValid(this.state.filterText)) { - _externals.push(this.state.filterText); - } - - dis.dispatch({ - action: Action.OpenInviteExternalUsersDialog, - data: { - externals: _externals, - }, - }); - }; - /* VERJI END */ /** * Check if there are unknown profiles if promptBeforeInviteUnknownUsers setting is enabled. * If so show the "invite anyway?" dialog. Otherwise directly create the DM local room. */ - // VERJI COMMENT OUT CheckProfileAndStartDM - // private checkProfileAndStartDm = async (): Promise => { - // this.setBusy(true); - // const targets = this.convertFilter(); + private checkProfileAndStartDm = async (): Promise => { + this.setBusy(true); + const targets = this.convertFilter(); - // if (SettingsStore.getValue("promptBeforeInviteUnknownUsers")) { - // const unknownProfileUsers = await extractTargetUnknownProfiles(targets, this.profilesStore); + if (SettingsStore.getValue("promptBeforeInviteUnknownUsers")) { + const unknownProfileUsers = await extractTargetUnknownProfiles(targets, this.profilesStore); - // if (unknownProfileUsers.length) { - // this.showAskInviteAnywayDialog(unknownProfileUsers); - // return; - // } - // } + if (unknownProfileUsers.length) { + this.showAskInviteAnywayDialog(unknownProfileUsers); + return; + } + } - // await this.startDm(); - // }; + await this.startDm(); + }; private startDm = async (): Promise => { this.setBusy(true); try { const cli = MatrixClientPeg.safeGet(); - const targets = await this.convertFilter(); // Verji: convert now async, await response + const targets = this.convertFilter(); await startDmOnFirstMessage(cli, targets); this.props.onFinished(true); } catch (err) { @@ -765,25 +591,25 @@ export default class InviteDialog extends React.PureComponent this.startDm(), - // onGiveUp: () => { - // this.setBusy(false); - // }, - // description: _t("invite|ask_anyway_description"), - // inviteNeverWarnLabel: _t("invite|ask_anyway_never_warn_label"), - // inviteLabel: _t("invite|ask_anyway_label"), - // }); - // } + + private showAskInviteAnywayDialog(unknownProfileUsers: { userId: string; errorText: string }[]): void { + Modal.createDialog(AskInviteAnywayDialog, { + unknownProfileUsers, + onInviteAnyways: () => this.startDm(), + onGiveUp: () => { + this.setBusy(false); + }, + description: _t("invite|ask_anyway_description"), + inviteNeverWarnLabel: _t("invite|ask_anyway_never_warn_label"), + inviteLabel: _t("invite|ask_anyway_label"), + }); + } private inviteUsers = async (): Promise => { if (this.props.kind !== InviteKind.Invite) return; this.setState({ busy: true }); this.convertFilter(); - const targets = await this.convertFilter(); // Verji: convert now async, await response + const targets = this.convertFilter(); const targetIds = targets.map((t) => t.userId); const cli = MatrixClientPeg.safeGet(); @@ -816,7 +642,7 @@ export default class InviteDialog extends React.PureComponent t.userId); if (targetIds.length > 1) { this.setState({ @@ -836,81 +662,33 @@ export default class InviteDialog extends React.PureComponent | any): Promise => { + private onKeyDown = (e: React.KeyboardEvent): void => { if (this.state.busy) return; let handled = false; const value = e.currentTarget.value.trim(); const action = getKeyBindingsManager().getAccessibilityAction(e); - console.log("[Verji.inviteDialog.tsx] - onKeyDown, allowOndboardingFlag: ", this.allowOnboardingFlag); - // VERJI START - if (!this.allowOnboardingFlag) { - if (this.state.busy) return; - const value = e.target.value.trim(); - const hasModifiers = e.ctrlKey || e.shiftKey || e.metaKey; - if (!value && this.state.targets.length > 0 && e.key === Key.BACKSPACE && !hasModifiers) { - // when the field is empty and the user hits backspace remove the right-most target - e.preventDefault(); - this.removeMember(this.state.targets[this.state.targets.length - 1]); - } else if (value && e.key === Key.ENTER && !hasModifiers) { - // when the user hits enter with something in their field try to convert it - e.preventDefault(); - await this.convertFilter(); - } else if (value && e.key === Key.SPACE && !hasModifiers && value.includes("@") && !value.includes(" ")) { - // when the user hits space and their input looks like an e-mail/MXID then try to convert it - e.preventDefault(); - await this.convertFilter(); - } - return; - } - // VERJI END + switch (action) { case KeyBindingAction.Backspace: - /* ROSBERG VERJI */ - if (value || (this.state.targets.length <= 0 && this.state.targetEmails?.length <= 0)) break; - if (this.allowOnboardingFlag) { - if (this.state.targetEmails?.length > 0) { - this.removeEmailInvite(this.state.targetEmails[this.state.targetEmails.length - 1]); - return; - } - } - /* VERJI END*/ + if (value || this.state.targets.length <= 0) break; + // when the field is empty and the user hits backspace remove the right-most target this.removeMember(this.state.targets[this.state.targets.length - 1]); handled = true; break; case KeyBindingAction.Space: - /* VERJI START */ - if (this.allowOnboardingFlag) { - if (value && Email.looksValid(value)) { - this.convertFilterOnboarding(); - break; - } else { - this.setState({ targetEmails: [] }); // dont allow combination of members - } - } - /* VERJI END*/ if (!value || !value.includes("@") || value.includes(" ")) break; // when the user hits space and their input looks like an e-mail/MXID then try to convert it - await this.convertFilter(); // VERJI ADD await + this.convertFilter(); handled = true; break; case KeyBindingAction.Enter: if (!value) break; - /* VERJI START */ - if (this.allowOnboardingFlag) { - if (value && Email.looksValid(value)) { - this.convertFilterOnboarding(); - break; - } else { - this.setState({ targetEmails: [] }); // dont allow combination of members - } - } - /* VERJI END*/ // when the user hits enter with something in their field try to convert it - await this.convertFilter(); // VERJI add await + this.convertFilter(); handled = true; break; } @@ -1054,11 +832,6 @@ export default class InviteDialog extends React.PureComponent { - // VERJI START - if (this.allowOnboardingFlag) { - this.setState({ targetEmails: [] }); - } - // VERJI END if (!this.state.busy) { let filterText = this.state.filterText; let targets = this.state.targets.map((t) => t); // cheap clone for mutation @@ -1080,22 +853,6 @@ export default class InviteDialog extends React.PureComponent { - const _email = (email as Member)?.name ?? (email as string); - - const targets = this.state.targetEmails.map((t) => t); // cheap clone for mutation - const idx = targets.indexOf(_email); - if (idx >= 0) { - targets.splice(idx, 1); - this.setState({ targetEmails: targets }); - } - - if (this.editorRef && this.editorRef.current) { - this.editorRef.current.focus(); - } - }; - /* VERJI END */ private removeMember = (member: Member): void => { const targets = this.state.targets.map((t) => t); // cheap clone for mutation const idx = targets.indexOf(member); @@ -1117,11 +874,6 @@ export default class InviteDialog extends React.PureComponent => { - // VERJI START - if (this.allowOnboardingFlag) { - return; - } - // VERJI END if (this.state.filterText) { // if the user has already typed something, just let them // paste normally. @@ -1129,26 +881,6 @@ export default class InviteDialog extends React.PureComponent { - this.setState({ busy: false }); - - if (r.results.find((e) => e.user_id == this.state.filterText.trim())) { - directoryUsers = r.results.map((u) => { - return { - userId: u.user_id, - user: null, - }; - }); - } - }); - - // ROSBERG END const potentialAddresses = this.parseFilter(text); // one search term which is not a mxid or email address if (potentialAddresses.length === 1 && !potentialAddresses[0].includes("@")) { @@ -1165,7 +897,6 @@ export default class InviteDialog extends React.PureComponent m.userId === address); if (member) { - // ROSBERG start - if (member.userId.trim() == MatrixClientPeg.getCredentials()?.userId.trim()) { - failed.push(text); // ROSBERG - continue; - } - //ROSBERG END if (this.canInviteMore([...this.state.targets, ...toAdd])) { toAdd.push(member.user); } else { @@ -1200,7 +919,7 @@ export default class InviteDialog extends React.PureComponent ( - // - // )); - /* ROSBERG START */ - let targets; - if (this.allowOnboardingFlag) { - if (this.state.targetEmails?.length > 0) { - targets = this.state.targetEmails.map((t) => ( - // ROSBERG - )); - } else { - targets = this.state.targets.map((t) => - t?.userId && t?.name ? ( - - ) : null, - ); - } - } else { - targets = this.state.targets.map((t) => - t?.userId && t?.name ? ( - - ) : null, - ); - } - /* ROSBERG END */ + const targets = this.state.targets.map((t) => ( + + )); const input = ( 0 || (this.state.filterText && this.state.filterText.includes("@")); + const hasSelection = + this.state.targets.length > 0 || (this.state.filterText && this.state.filterText.includes("@")); - // VERJI HACK (&& !Email.looksValid(this.state.filterText)) - let hasSelection = false; - //let emailInvite = false; - if (this.allowOnboardingFlag) { - hasSelection = this.state.targets.length > 0 || this.state.targetEmails?.length > 0; - // emailInvite = (this.state.filterText && this.state.filterText.includes('@') && Email.looksValid(this.state.filterText)); - } else { - hasSelection = this.state.targets.length > 0; - } - // VERJI END const cli = MatrixClientPeg.safeGet(); const userId = cli.getUserId()!; if (this.props.kind === InviteKind.Dm) { @@ -1640,15 +1320,9 @@ export default class InviteDialog extends React.PureComponent 0) { - buttonText = _t("action|go"); - } else { - buttonText = _t("action|go"); - } - /* VERJI END */ + buttonText = _t("action|go"); - goButtonFn = this.startDm; //this.checkProfileAndStartDm; + goButtonFn = this.checkProfileAndStartDm; extraSection = (
{_t("invite|suggestions_disclaimer")} @@ -1759,7 +1433,7 @@ export default class InviteDialog extends React.PureComponent ); } - /* VERJI start */ - if (this.allowOnboardingFlag) { - goButton = - this.props.kind == InviteKind.CallTransfer ? null : ( - 0 || Email.looksValid(this.state.filterText)) - ? this.startInviteByEmail - : goButtonFn - } - className="mx_InviteDialog_goButton" - disabled={ - (this.state.busy || !hasSelection) && - this.state.targetEmails?.length <= 0 && - !Email.looksValid(this.state.filterText) - } - > - {buttonText} - - ); - } else { - goButton = - this.props.kind == InviteKind.CallTransfer ? null : ( - - {buttonText} - - ); - } - /* VERJI END */ const usersSection = ( diff --git a/src/components/views/dialogs/LogoutDialog.tsx b/src/components/views/dialogs/LogoutDialog.tsx index 5f6eaf2f2c4..253a43b0f05 100644 --- a/src/components/views/dialogs/LogoutDialog.tsx +++ b/src/components/views/dialogs/LogoutDialog.tsx @@ -71,7 +71,7 @@ export default class LogoutDialog extends React.Component { }; // we can't call setState() immediately, so wait a beat - window.setTimeout(() => this.startLoadBackupStatus(), 0); //Verji + window.setTimeout(() => this.startLoadBackupStatus(), 0); } /** kick off the asynchronous calls to populate `state.backupStatus` in the background */ diff --git a/src/components/views/dialogs/RoomSettingsDialog.tsx b/src/components/views/dialogs/RoomSettingsDialog.tsx index d74fbc37291..213ee94aca6 100644 --- a/src/components/views/dialogs/RoomSettingsDialog.tsx +++ b/src/components/views/dialogs/RoomSettingsDialog.tsx @@ -19,10 +19,6 @@ limitations under the License. import React from "react"; import { RoomEvent, Room, RoomStateEvent, MatrixEvent, EventType } from "matrix-js-sdk/src/matrix"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; import TabbedView, { Tab } from "../../structures/TabbedView"; import { _t, _td } from "../../../languageHandler"; @@ -44,7 +40,6 @@ import { NonEmptyArray } from "../../../@types/common"; import { PollHistoryTab } from "../settings/tabs/room/PollHistoryTab"; import ErrorBoundary from "../elements/ErrorBoundary"; import { PeopleRoomSettingsTab } from "../settings/tabs/room/PeopleRoomSettingsTab"; -import { ModuleRunner } from "../../../modules/ModuleRunner"; export const enum RoomSettingsTab { General = "ROOM_GENERAL_TAB", @@ -140,11 +135,7 @@ class RoomSettingsDialog extends React.Component { private getTabs(): NonEmptyArray> { const tabs: Tab[] = []; - const customRolesRoomSettingsTabOpts = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke( - CustomComponentLifecycle.RolesRoomSettingsTab, - customRolesRoomSettingsTabOpts as CustomComponentOpts, - ); + tabs.push( new Tab( RoomSettingsTab.General, @@ -174,32 +165,21 @@ class RoomSettingsDialog extends React.Component { ), ); } - if (SettingsStore.getValue(UIFeature.RoomSettingsSecurity)) { - tabs.push( - new Tab( - RoomSettingsTab.Security, - _td("room_settings|security|title"), - "mx_RoomSettingsDialog_securityIcon", - ( - this.props.onFinished(true)} - /> - ), - "RoomSettingsSecurityPrivacy", - ), - ); - } + tabs.push( + new Tab( + RoomSettingsTab.Security, + _td("room_settings|security|title"), + "mx_RoomSettingsDialog_securityIcon", + this.props.onFinished(true)} />, + "RoomSettingsSecurityPrivacy", + ), + ); tabs.push( new Tab( RoomSettingsTab.Roles, _td("room_settings|permissions|title"), "mx_RoomSettingsDialog_rolesIcon", - ( - - - - ), + , "RoomSettingsRolesPermissions", ), ); diff --git a/src/components/views/dialogs/SpaceSettingsDialog.tsx b/src/components/views/dialogs/SpaceSettingsDialog.tsx index e6b243f3f24..016307d8994 100644 --- a/src/components/views/dialogs/SpaceSettingsDialog.tsx +++ b/src/components/views/dialogs/SpaceSettingsDialog.tsx @@ -16,10 +16,6 @@ limitations under the License. import React, { useMemo } from "react"; import { Room, MatrixClient } from "matrix-js-sdk/src/matrix"; -import { - CustomComponentOpts, - CustomComponentLifecycle, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; import { _t, _td } from "../../../languageHandler"; import BaseDialog from "./BaseDialog"; @@ -34,7 +30,6 @@ import AdvancedRoomSettingsTab from "../settings/tabs/room/AdvancedRoomSettingsT import RolesRoomSettingsTab from "../settings/tabs/room/RolesRoomSettingsTab"; import { Action } from "../../../dispatcher/actions"; import { NonEmptyArray } from "../../../@types/common"; -import { ModuleRunner } from "../../../modules/ModuleRunner"; export enum SpaceSettingsTab { General = "SPACE_GENERAL_TAB", @@ -57,11 +52,6 @@ const SpaceSettingsDialog: React.FC = ({ matrixClient: cli, space, onFin }); const tabs = useMemo(() => { - const customRolesRoomSettingsTabOpts = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke( - CustomComponentLifecycle.RolesRoomSettingsTab, - customRolesRoomSettingsTabOpts as CustomComponentOpts, - ); return [ new Tab( SpaceSettingsTab.General, @@ -79,11 +69,7 @@ const SpaceSettingsDialog: React.FC = ({ matrixClient: cli, space, onFin SpaceSettingsTab.Roles, _td("room_settings|permissions|title"), "mx_RoomSettingsDialog_rolesIcon", - ( - - - - ), + , ), SettingsStore.getValue(UIFeature.AdvancedSettings) ? new Tab( diff --git a/src/components/views/dialogs/UserSettingsDialog.tsx b/src/components/views/dialogs/UserSettingsDialog.tsx index 0a82994080d..bb97b36fc96 100644 --- a/src/components/views/dialogs/UserSettingsDialog.tsx +++ b/src/components/views/dialogs/UserSettingsDialog.tsx @@ -16,10 +16,6 @@ limitations under the License. */ import React from "react"; -import { - CustomComponentOpts, - CustomComponentLifecycle, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; import TabbedView, { Tab, useActiveTabWithDefault } from "../../structures/TabbedView"; import { _t, _td } from "../../../languageHandler"; @@ -42,7 +38,7 @@ import { UserTab } from "./UserTab"; import { NonEmptyArray } from "../../../@types/common"; import { SDKContext, SdkContextClass } from "../../../contexts/SDKContext"; import { useSettingValue } from "../../../hooks/useSettings"; -import { ModuleRunner } from "../../../modules/ModuleRunner"; + interface IProps { initialTabId?: UserTab; sdkContext: SdkContextClass; @@ -87,11 +83,7 @@ export default function UserSettingsDialog(props: IProps): JSX.Element { const getTabs = (): NonEmptyArray> => { const tabs: Tab[] = []; - const customSessionManagerTabOpts = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke( - CustomComponentLifecycle.SessionManagerTab, - customSessionManagerTabOpts as CustomComponentOpts, - ); + tabs.push( new Tab( UserTab.General, @@ -106,11 +98,7 @@ export default function UserSettingsDialog(props: IProps): JSX.Element { UserTab.SessionManager, _td("settings|sessions|title"), "mx_UserSettingsDialog_sessionsIcon", - ( - - - - ), + , undefined, ), ); @@ -150,17 +138,15 @@ export default function UserSettingsDialog(props: IProps): JSX.Element { "UserSettingsKeyboard", ), ); - if (SettingsStore.getValue(UIFeature.SpacesEnabled)) { - tabs.push( - new Tab( - UserTab.Sidebar, - _td("settings|sidebar|title"), - "mx_UserSettingsDialog_sidebarIcon", - , - "UserSettingsSidebar", - ), - ); - } + tabs.push( + new Tab( + UserTab.Sidebar, + _td("settings|sidebar|title"), + "mx_UserSettingsDialog_sidebarIcon", + , + "UserSettingsSidebar", + ), + ); if (voipEnabled) { tabs.push( @@ -174,17 +160,15 @@ export default function UserSettingsDialog(props: IProps): JSX.Element { ); } - if (SettingsStore.getValue(UIFeature.SpacesEnabled)) { - tabs.push( - new Tab( - UserTab.Security, - _td("room_settings|security|title"), - "mx_UserSettingsDialog_securityIcon", - , - "UserSettingsSecurityPrivacy", - ), - ); - } + tabs.push( + new Tab( + UserTab.Security, + _td("room_settings|security|title"), + "mx_UserSettingsDialog_securityIcon", + , + "UserSettingsSecurityPrivacy", + ), + ); if (showLabsFlags() || SettingsStore.getFeatureSettingNames().some((k) => SettingsStore.getBetaInfo(k))) { tabs.push( diff --git a/src/components/views/dialogs/devtools/AccountData.tsx b/src/components/views/dialogs/devtools/AccountData.tsx index d4a31f0297c..635becac3fb 100644 --- a/src/components/views/dialogs/devtools/AccountData.tsx +++ b/src/components/views/dialogs/devtools/AccountData.tsx @@ -23,8 +23,6 @@ import MatrixClientContext from "../../../../contexts/MatrixClientContext"; import { EventEditor, EventViewer, eventTypeField, IEditorProps, stringify } from "./Event"; import FilteredList from "./FilteredList"; import { _td, TranslationKey } from "../../../../languageHandler"; -import SettingsStore from "../../../../settings/SettingsStore"; -import { UIFeature } from "../../../../settings/UIFeature"; export const AccountDataEventEditor: React.FC = ({ mxEvent, onBack }) => { const cli = useContext(MatrixClientContext); @@ -100,12 +98,9 @@ export const AccountDataExplorer: React.FC = ({ onBack, setTool ); }; @@ -117,12 +112,9 @@ export const RoomAccountDataExplorer: React.FC = ({ onBack, setT ); }; diff --git a/src/components/views/dialogs/devtools/BaseTool.tsx b/src/components/views/dialogs/devtools/BaseTool.tsx index ec2ceba9f91..e5f93ead3f9 100644 --- a/src/components/views/dialogs/devtools/BaseTool.tsx +++ b/src/components/views/dialogs/devtools/BaseTool.tsx @@ -22,8 +22,6 @@ import classNames from "classnames"; import { _t, TranslationKey } from "../../../../languageHandler"; import { XOR } from "../../../../@types/common"; import { Tool } from "../DevtoolsDialog"; -import SettingsStore from "../../../../settings/SettingsStore"; -import { UIFeature } from "../../../../settings/UIFeature"; export interface IDevtoolsProps { onBack(): void; @@ -80,7 +78,7 @@ const BaseTool: React.FC> = ({
{extraButton} - {SettingsStore.getValue(UIFeature.BaseToolActionButton) && actionButton} + {actionButton}
); diff --git a/src/components/views/dialogs/spotlight/SpotlightDialog.tsx b/src/components/views/dialogs/spotlight/SpotlightDialog.tsx index d232136b4f3..2ac7681afae 100644 --- a/src/components/views/dialogs/spotlight/SpotlightDialog.tsx +++ b/src/components/views/dialogs/spotlight/SpotlightDialog.tsx @@ -87,7 +87,6 @@ import { useFeatureEnabled } from "../../../../hooks/useSettings"; import { filterBoolean } from "../../../../utils/arrays"; import { transformSearchTerm } from "../../../../utils/SearchInput"; import { Filter } from "./Filter"; -import { UIFeature } from "../../../../settings/UIFeature"; const MAX_RECENT_SEARCHES = 10; const SECTION_LIMIT = 50; // only show 50 results per section for performance reasons @@ -568,10 +567,7 @@ const SpotlightDialog: React.FC = ({ initialText = "", initialFilter = n }; let otherSearchesSection: JSX.Element | undefined; - if ( - (SettingsStore.getValue(UIFeature.SpacesEnabled) && trimmedQuery) || - (filter !== Filter.PublicRooms && filter !== Filter.PublicSpaces) - ) { + if (trimmedQuery || (filter !== Filter.PublicRooms && filter !== Filter.PublicSpaces)) { otherSearchesSection = (
= ({ protocols, config, setConfig })); const addNewServer = useCallback( - ({ closeMenu }) => - SettingsStore.getValue(UIFeature.NetworkOptions) && ( - <> - - => { - closeMenu(); - const { finished } = Modal.createDialog( - TextInputDialog, - { - title: _t("spotlight|public_rooms|network_dropdown_add_dialog_title"), - description: _t("spotlight|public_rooms|network_dropdown_add_dialog_description"), - button: _t("action|add"), - hasCancel: false, - placeholder: _t("spotlight|public_rooms|network_dropdown_add_dialog_placeholder"), - validator: validServer, - fixedWidth: false, - }, - "mx_NetworkDropdown_dialog", - ); - - const [ok, newServer] = await finished; - if (!ok) return; - - if (!allServers.includes(newServer)) { - setUserDefinedServers([...userDefinedServers, newServer]); - setConfig({ - roomServer: newServer, - }); - } - }} - > -
- - {_t("spotlight|public_rooms|network_dropdown_add_server_option")} - -
-
- - ), + ({ closeMenu }) => ( + <> + + => { + closeMenu(); + const { finished } = Modal.createDialog( + TextInputDialog, + { + title: _t("spotlight|public_rooms|network_dropdown_add_dialog_title"), + description: _t("spotlight|public_rooms|network_dropdown_add_dialog_description"), + button: _t("action|add"), + hasCancel: false, + placeholder: _t("spotlight|public_rooms|network_dropdown_add_dialog_placeholder"), + validator: validServer, + fixedWidth: false, + }, + "mx_NetworkDropdown_dialog", + ); + + const [ok, newServer] = await finished; + if (!ok) return; + + if (!allServers.includes(newServer)) { + setUserDefinedServers([...userDefinedServers, newServer]); + setConfig({ + roomServer: newServer, + }); + } + }} + > +
+ + {_t("spotlight|public_rooms|network_dropdown_add_server_option")} + +
+
+ + ), [allServers, setConfig, setUserDefinedServers, userDefinedServers], ); @@ -234,7 +232,7 @@ export const NetworkDropdown: React.FC = ({ protocols, config, setConfig toKey={(config: IPublicRoomDirectoryConfig | null) => config ? `${config.roomServer}-${config.instanceId}` : "null" } - options={SettingsStore.getValue(UIFeature.NetworkOptions) ? options : []} + options={options} onChange={(option) => setConfig(option)} selectedLabel={(option) => option?.key diff --git a/src/components/views/elements/ErrorBoundary.tsx b/src/components/views/elements/ErrorBoundary.tsx index 7f1cb9d3939..b5bc13f610e 100644 --- a/src/components/views/elements/ErrorBoundary.tsx +++ b/src/components/views/elements/ErrorBoundary.tsx @@ -16,10 +16,6 @@ limitations under the License. import React, { ErrorInfo, ReactNode } from "react"; import { logger } from "matrix-js-sdk/src/logger"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; import { _t } from "../../../languageHandler"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; @@ -28,7 +24,6 @@ import Modal from "../../../Modal"; import SdkConfig from "../../../SdkConfig"; import BugReportDialog from "../dialogs/BugReportDialog"; import AccessibleButton from "./AccessibleButton"; -import { ModuleRunner } from "../../../modules/ModuleRunner"; interface Props { children: ReactNode; @@ -81,12 +76,6 @@ export default class ErrorBoundary extends React.PureComponent { }; public render(): ReactNode { - const CustomErrorBoundary = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke( - CustomComponentLifecycle.ErrorBoundary, - CustomErrorBoundary as CustomComponentOpts, - ); - if (this.state.error) { const newIssueUrl = SdkConfig.get().feedback.new_issue_url; @@ -132,18 +121,16 @@ export default class ErrorBoundary extends React.PureComponent { } return ( - -
-
-

{_t("error|something_went_wrong")}

- {bugReportSection} - {clearCacheButton} -
+
+
+

{_t("error|something_went_wrong")}

+ {bugReportSection} + {clearCacheButton}
- +
); } - return {this.props.children}; + return this.props.children; } } diff --git a/src/components/views/elements/PowerSelector.tsx b/src/components/views/elements/PowerSelector.tsx index 38d69fc7333..7dcf3d78ecc 100644 --- a/src/components/views/elements/PowerSelector.tsx +++ b/src/components/views/elements/PowerSelector.tsx @@ -22,8 +22,6 @@ import Field from "./Field"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import { objectHasDiff } from "../../../utils/objects"; -import SettingsStore from "../../../settings/SettingsStore"; -import { UIFeature } from "../../../settings/UIFeature"; const CUSTOM_VALUE = "SELECT_VALUE_CUSTOM"; @@ -192,8 +190,7 @@ export default class PowerSelector extends React.C text: Roles.textualPowerLevel(level, this.props.usersDefault), }; }); - SettingsStore.getValue(UIFeature.PowerSelectorCustomValue) && - options.push({ value: CUSTOM_VALUE, text: _t("power_level|custom_level") }); + options.push({ value: CUSTOM_VALUE, text: _t("power_level|custom_level") }); const optionsElements = options.map((op) => { return (
); } @@ -275,12 +269,10 @@ export default class PhoneNumbers extends React.Component { ); }); - let addVerifySection = SettingsStore.getValue(UIFeature.PhoneNumerShowAddButton) && ( - <> - - {_t("action|add")} - - + let addVerifySection = ( + + {_t("action|add")} + ); if (this.state.verifying) { const msisdn = this.state.verifyMsisdn; diff --git a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx index ed813183964..7b260e3a7e6 100644 --- a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx @@ -90,19 +90,14 @@ export default class GeneralRoomSettingsTab extends React.Component - {SettingsStore.getValue(UIFeature.RoomSettingsAlias) && ( - <> - {" "} - - - - - )} + + + {urlPreviewSettings} diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx index 0d47bab815b..ebc6da28c08 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx @@ -412,15 +412,12 @@ export default class GeneralUserSettingsTab extends React.Component - {SettingsStore.getValue(UIFeature.UserSettingsExternalAccount) && externalAccountManagement} - {SettingsStore.getValue(UIFeature.UserSettingsChangePassword) && passwordChangeSection} + {externalAccountManagement} + {passwordChangeSection} {threepidSection} @@ -498,12 +495,7 @@ export default class GeneralUserSettingsTab extends React.Component {threepidSection} {/* has its own heading as it includes the current identity server */} - {SettingsStore.getValue(UIFeature.UserSettingsSetIdServer) && ( - <> - {" "} - {" "} - - )} + ); } @@ -574,9 +566,8 @@ export default class GeneralUserSettingsTab extends React.Component - {SettingsStore.getValue(UIFeature.UserSettingsDiscovery) && <> {discoverySection} } - {SettingsStore.getValue(UIFeature.UserSettingsIntegrationManager) && - this.renderIntegrationManagerSection()} + {discoverySection} + {this.renderIntegrationManagerSection()} {accountManagementSection} ); diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx index a4f9aff30c9..2bf2c0f6042 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx @@ -16,10 +16,6 @@ limitations under the License. import React, { ReactNode } from "react"; import { logger } from "matrix-js-sdk/src/logger"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; import AccessibleButton from "../../../elements/AccessibleButton"; import { _t } from "../../../../../languageHandler"; @@ -34,7 +30,6 @@ import { SettingsSection } from "../../shared/SettingsSection"; import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection"; import ExternalLink from "../../../elements/ExternalLink"; import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; -import { ModuleRunner } from "../../../../../modules/ModuleRunner"; interface IProps {} @@ -267,74 +262,66 @@ export default class HelpUserSettingsTab extends React.Component const { appVersion, cryptoVersion } = this.getVersionInfo(); - const CustomHelpUserSettingsTab = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke( - CustomComponentLifecycle.HelpUserSettingsTab, - CustomHelpUserSettingsTab as CustomComponentOpts, - ); - return ( - - - - {bugReportingSection} - - - - - {appVersion} -
- {cryptoVersion} -
-
- {updateButton} -
-
- {this.renderLegal()} - {this.renderCredits()} - + + + {bugReportingSection} + + + + + {appVersion} +
+ {cryptoVersion} +
+
+ {updateButton} +
+
+ {this.renderLegal()} + {this.renderCredits()} + + + {_t( + "setting|help_about|homeserver", + { + homeserverUrl: this.context.getHomeserverUrl(), + }, + { + code: (sub) => {sub}, + }, + )} + + {this.context.getIdentityServerUrl() && ( {_t( - "setting|help_about|homeserver", + "setting|help_about|identity_server", { - homeserverUrl: this.context.getHomeserverUrl(), + identityServerUrl: this.context.getIdentityServerUrl(), }, { code: (sub) => {sub}, }, )} - {this.context.getIdentityServerUrl() && ( - - {_t( - "setting|help_about|identity_server", - { - identityServerUrl: this.context.getIdentityServerUrl(), - }, - { - code: (sub) => {sub}, - }, - )} - - )} - -
- - {_t("common|access_token")} - - {_t("setting|help_about|access_token_detail")} - this.context.getAccessToken()}> - {this.context.getAccessToken()} - -
-
- - {_t("setting|help_about|clear_cache_reload")} - -
-
-
-
+ )} + +
+ + {_t("common|access_token")} + + {_t("setting|help_about|access_token_detail")} + this.context.getAccessToken()}> + {this.context.getAccessToken()} + +
+
+ + {_t("setting|help_about|clear_cache_reload")} + + +
+ ); } } diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx index 932edb0aa72..6df2a1a03c5 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx @@ -33,7 +33,6 @@ import { showUserOnboardingPage } from "../../../user-onboarding/UserOnboardingP import SettingsSubsection from "../../shared/SettingsSubsection"; import SettingsTab from "../SettingsTab"; import { SettingsSection } from "../../shared/SettingsSection"; -import { UIFeature } from "../../../../../settings/UIFeature"; interface IProps { closeSettingsFn(success: boolean): void; @@ -60,8 +59,8 @@ export default class PreferencesUserSettingsTab extends React.Component("FTUE.useCaseSelection"); const roomListSettings = PreferencesUserSettingsTab.ROOM_LIST_SETTINGS // Only show the user onboarding setting if the user should see the user onboarding page @@ -203,8 +170,7 @@ export default class PreferencesUserSettingsTab extends React.Component - {SettingsStore.getValue(UIFeature.SearchShortcutPreferences) && - this.renderGroup(PreferencesUserSettingsTab.KEYBINDINGS_SETTINGS)} + {this.renderGroup(PreferencesUserSettingsTab.KEYBINDINGS_SETTINGS)} diff --git a/src/components/views/settings/tabs/user/SidebarUserSettingsTab.tsx b/src/components/views/settings/tabs/user/SidebarUserSettingsTab.tsx index 215622226a5..6f966948f5e 100644 --- a/src/components/views/settings/tabs/user/SidebarUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/SidebarUserSettingsTab.tsx @@ -32,7 +32,6 @@ import SettingsTab from "../SettingsTab"; import { SettingsSection } from "../../shared/SettingsSection"; import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection"; import SdkConfig from "../../../../../SdkConfig"; -import { UIFeature } from "../../../../../settings/UIFeature"; type InteractionName = "WebSettingsSidebarTabSpacesCheckbox" | "WebQuickSettingsPinToSidebarCheckbox"; @@ -79,8 +78,6 @@ const SidebarUserSettingsTab: React.FC = () => { PosthogTrackers.trackInteraction("WebSettingsSidebarTabSpacesCheckbox", event, 1); }; - if (!SettingsStore.getValue(UIFeature.SpacesEnabled)) return <>; - return ( diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx index d9d836d537d..758a48e1c57 100644 --- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx @@ -31,8 +31,6 @@ import SettingsTab from "../SettingsTab"; import { SettingsSection } from "../../shared/SettingsSection"; import SettingsSubsection from "../../shared/SettingsSubsection"; import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; -import SettingsStore from "../../../../../../src/settings/SettingsStore"; -import { UIFeature } from "../../../../../../src/settings/UIFeature"; interface IState { mediaDevices: IMediaDevices | null; @@ -199,11 +197,7 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> { {webcamDropdown} - {SettingsStore.getValue(UIFeature.VideoMirrorLocalVideo) && ( - <> - {" "} - - )} + @@ -228,25 +222,21 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> { data-testid="voice-echo-cancellation" /> - {SettingsStore.getValue(UIFeature.VideoConnectionSettings) && ( - <> - - - - - - )} + + + + ); diff --git a/src/components/views/spaces/SpacePanel.tsx b/src/components/views/spaces/SpacePanel.tsx index da9214d86e7..7c909c0024b 100644 --- a/src/components/views/spaces/SpacePanel.tsx +++ b/src/components/views/spaces/SpacePanel.tsx @@ -29,10 +29,6 @@ import React, { import { DragDropContext, Draggable, Droppable, DroppableProvidedProps } from "react-beautiful-dnd"; import classNames from "classnames"; import { Room } from "matrix-js-sdk/src/matrix"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; import { _t } from "../../../languageHandler"; import { useContextMenu } from "../../structures/ContextMenu"; @@ -76,7 +72,6 @@ import { UIComponent, UIFeature } from "../../../settings/UIFeature"; import { ThreadsActivityCentre } from "./threads-activity-centre/"; import AccessibleButton from "../elements/AccessibleButton"; import { KeyboardShortcut } from "../settings/KeyboardShortcut"; -import { ModuleRunner } from "../../../modules/ModuleRunner"; const useSpaces = (): [Room[], MetaSpace[], Room[], SpaceKey] => { const invites = useEventEmitterState(SpaceStore.instance, UPDATE_INVITED_SPACES, () => { @@ -252,31 +247,27 @@ const CreateSpaceButton: React.FC -
  • - - - {contextMenu} -
  • - - ) +
  • + + + {contextMenu} +
  • ); }; @@ -382,8 +373,7 @@ const SpacePanel: React.FC = () => { setPanelCollapsed(!isPanelCollapsed); } }); - const customUserMenuOpts = { CustomComponent: React.Fragment }; - ModuleRunner.instance.invoke(CustomComponentLifecycle.UserMenu, customUserMenuOpts as CustomComponentOpts); + return ( {({ onKeyDownHandler, onDragEndHandler }) => ( @@ -404,23 +394,19 @@ const SpacePanel: React.FC = () => { ref={ref} aria-label={_t("common|spaces")} > - - - setPanelCollapsed(!isPanelCollapsed)} - title={isPanelCollapsed ? _t("action|expand") : _t("action|collapse")} - caption={ - - } - /> - - + + setPanelCollapsed(!isPanelCollapsed)} + title={isPanelCollapsed ? _t("action|expand") : _t("action|collapse")} + caption={ + + } + /> + {(provided, snapshot) => ( ({ id: p[0], name: p[1] })) // convert pairs to objects for code readability .filter((p) => !isHighContrastTheme(p.id)); const builtInThemes = themes.filter((p) => !p.id.startsWith("custom-")); - const customThemes = themes.filter((p) => !builtInThemes.includes(p)).sort((a, b) => compare(a.name, b.name)); // Verji - //verji start - if (!customThemes) { - return [...builtInThemes]; - } - return [...customThemes]; - //verji end + const customThemes = themes.filter((p) => !builtInThemes.includes(p)).sort((a, b) => compare(a.name, b.name)); + return [...builtInThemes, ...customThemes]; } function clearCustomTheme(): void { diff --git a/src/toasts/BulkUnverifiedSessionsToast.ts b/src/toasts/BulkUnverifiedSessionsToast.ts index 532621803cb..1019d717e9f 100644 --- a/src/toasts/BulkUnverifiedSessionsToast.ts +++ b/src/toasts/BulkUnverifiedSessionsToast.ts @@ -21,8 +21,6 @@ import GenericToast from "../components/views/toasts/GenericToast"; import ToastStore from "../stores/ToastStore"; import { Action } from "../dispatcher/actions"; import { snoozeBulkUnverifiedDeviceReminder } from "../utils/device/snoozeBulkUnverifiedDeviceReminder"; -import SettingsStore from "../settings/SettingsStore"; -import { UIFeature } from "../settings/UIFeature"; const TOAST_KEY = "reviewsessions"; @@ -40,22 +38,20 @@ export const showToast = (deviceIds: Set): void => { snoozeBulkUnverifiedDeviceReminder(); }; - if (SettingsStore.getValue(UIFeature.UnverifiedSessionsToast)) { - ToastStore.sharedInstance().addOrReplaceToast({ - key: TOAST_KEY, - title: _t("encryption|verification|unverified_sessions_toast_title"), - icon: "verification_warning", - props: { - description: _t("encryption|verification|unverified_sessions_toast_description"), - acceptLabel: _t("action|review"), - onAccept, - rejectLabel: _t("encryption|verification|unverified_sessions_toast_reject"), - onReject, - }, - component: GenericToast, - priority: 50, - }); - } + ToastStore.sharedInstance().addOrReplaceToast({ + key: TOAST_KEY, + title: _t("encryption|verification|unverified_sessions_toast_title"), + icon: "verification_warning", + props: { + description: _t("encryption|verification|unverified_sessions_toast_description"), + acceptLabel: _t("action|review"), + onAccept, + rejectLabel: _t("encryption|verification|unverified_sessions_toast_reject"), + onReject, + }, + component: GenericToast, + priority: 50, + }); }; export const hideToast = (): void => { diff --git a/src/toasts/SetupEncryptionToast.ts b/src/toasts/SetupEncryptionToast.ts index 06363e387e3..3f78ad0c925 100644 --- a/src/toasts/SetupEncryptionToast.ts +++ b/src/toasts/SetupEncryptionToast.ts @@ -80,12 +80,8 @@ const onReject = (): void => { }; export const showToast = (kind: Kind): void => { - // if (SecurityCustomisations.setupEncryptionNeeded?.(kind)) { - // return; - // } - if ( - ModuleRunner.instance.extensions.cryptoSetup?.setupEncryptionNeeded({ + ModuleRunner.instance.extensions.cryptoSetup.setupEncryptionNeeded({ kind: kind as any, storeProvider: { getInstance: () => SetupEncryptionStore.sharedInstance() }, }) diff --git a/src/utils/FormattingUtils.ts b/src/utils/FormattingUtils.ts index b04057958d8..90e983ad1ad 100644 --- a/src/utils/FormattingUtils.ts +++ b/src/utils/FormattingUtils.ts @@ -131,46 +131,3 @@ export function formatList(items: ReactNode[], itemLimit = items.length, include }), ); } -/** - * Constructs a written English string representing `items`, with an optional - * limit on the number of items included in the result. If specified and if the - * length of `items` is greater than the limit, the string "and n others" will - * be appended onto the result. If `items` is empty, returns the empty string. - * If there is only one item, return it. - * @param {string[]} items the items to construct a string from. - * @param {number?} itemLimit the number by which to limit the list. - * @returns {string} a string constructed by joining `items` with a comma - * between each item, but with the last item appended as " and [lastItem]". - */ -// Verji additions -export function formatCommaSeparatedList(items: string[], itemLimit?: number): string; -export function formatCommaSeparatedList(items: ReactElement[], itemLimit?: number): ReactElement; -export function formatCommaSeparatedList(items: ReactNode[], itemLimit?: number): ReactNode; -export function formatCommaSeparatedList(items: ReactNode[], itemLimit?: number): ReactNode { - const remaining = itemLimit === undefined ? 0 : Math.max(items.length - itemLimit, 0); - if (items.length === 0) { - return ""; - } else if (items.length === 1) { - return items[0]; - } else { - let lastItem; - if (remaining > 0) { - items = items.slice(0, itemLimit); - } else { - lastItem = items.pop(); - } - - let joinedItems; - if (items.every((e) => typeof e === "string")) { - joinedItems = items.join(", "); - } else { - joinedItems = jsxJoin(items, ", "); - } - - if (remaining > 0) { - return _t("common|formattingresult", { items: joinedItems, count: remaining }); - } else { - return _t("common|formattingresult2", { items: joinedItems, lastItem }); - } - } -} diff --git a/src/utils/direct-messages.ts b/src/utils/direct-messages.ts index 0f4c4f9134e..13c028652e8 100644 --- a/src/utils/direct-messages.ts +++ b/src/utils/direct-messages.ts @@ -179,9 +179,8 @@ export class ThreepidMember extends Member { } export interface IDMUserTileProps { - member: Member; // VERJI - email: string; // VERJI - onRemove?(member: Member | string): void; // VERJI + member: Member; + onRemove?(member: Member): void; } /** diff --git a/test/DeviceListener-test.ts b/test/DeviceListener-test.ts index 78202593710..aa6b14af7bc 100644 --- a/test/DeviceListener-test.ts +++ b/test/DeviceListener-test.ts @@ -410,44 +410,11 @@ describe("DeviceListener", () => { // all devices verified by default mockCrypto!.getDeviceVerificationStatus.mockResolvedValue(deviceTrustVerified); mockClient!.deviceId = currentDevice.deviceId; - jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) => { - if ( - settingName === UIFeature.BulkUnverifiedSessionsReminder || - settingName === UIFeature.UnverifiedSessionsToast - ) { - return true; - } - return false; - }); + jest.spyOn(SettingsStore, "getValue").mockImplementation( + (settingName) => settingName === UIFeature.BulkUnverifiedSessionsReminder, + ); }); - describe("bulk unverified sessions toasts", () => { - it("shows toast with unverified devices at app start with UIFeature.UnverifiedSessionsToast returning true", async () => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); - // currentDevice, device2 are verified, device3 is unverified - mockCrypto!.getDeviceVerificationStatus.mockImplementation(async (_userId, deviceId) => { - switch (deviceId) { - case currentDevice.deviceId: - case device2.deviceId: - return deviceTrustVerified; - default: - return deviceTrustUnverified; - } - }); - await createAndStart(); - expect(BulkUnverifiedSessionsToast.showToast).toHaveBeenCalledWith( - new Set([device3.deviceId]), - ); - expect(BulkUnverifiedSessionsToast.hideToast).not.toHaveBeenCalled(); - }); - - it("hide toast with UIFeature.UnverifiedSessionsToast returning false", async () => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); - await createAndStart(); - expect(BulkUnverifiedSessionsToast.showToast).not.toHaveBeenCalled(); - expect(BulkUnverifiedSessionsToast.hideToast).toHaveBeenCalled(); - }); - it("hides toast when cross signing is not ready", async () => { mockCrypto!.isCrossSigningReady.mockResolvedValue(false); await createAndStart(); diff --git a/test/VerjiLocalSearch-test.ts b/test/VerjiLocalSearch-test.ts deleted file mode 100644 index 7d9d979eed9..00000000000 --- a/test/VerjiLocalSearch-test.ts +++ /dev/null @@ -1,258 +0,0 @@ -/* - Copyright 2024 Verji Tech AS. All rights reserved. - Unauthorized copying or distribution of this file, via any medium, is strictly prohibited. -*/ - -import { EventContext } from "matrix-js-sdk/src/models/event-context"; // eslint-disable-line -import { MatrixEvent } from "matrix-js-sdk/src/matrix"; - -import { - findAllMatches, - eventMatchesSearchTerms, - makeSearchTermObject, - isMemberMatch, - SearchTerm, - reverseEventContext, -} from "../src/VerjiLocalSearch"; - -describe("LocalSearch", () => { - it("should return true for matches", async () => { - const testEvent = {} as MatrixEvent; - testEvent.getType = () => "m.room.message"; - testEvent.isRedacted = () => false; - testEvent.getContent = () => ({ body: "bodytext" }) as any; - testEvent.getSender = () => ({ userId: "testtestsson" }) as any; - testEvent.getDate = () => new Date(); - - const termObj: SearchTerm = { - searchTypeAdvanced: false, - searchTypeNormal: true, - fullText: "bodytext", - words: [{ word: "bodytext", highlight: false }], - regExpHighlights: [], - }; - - const isMatch = eventMatchesSearchTerms(termObj, testEvent as MatrixEvent, [] as any); - expect(isMatch).toBe(true); - }); - - it("finds only one match among several", async () => { - const testEvent = {} as MatrixEvent; - testEvent.getType = () => "m.room.message"; - testEvent.isRedacted = () => false; - testEvent.getContent = () => ({ body: "bodytext" }) as any; - testEvent.getSender = () => ({ userId: "testtestsson" }) as any; - testEvent.getDate = () => new Date(); - - const testEvent2 = {} as MatrixEvent; - testEvent2.getType = () => "m.room.message"; - testEvent2.isRedacted = () => false; - testEvent2.getContent = () => ({ body: "not that text at all" }) as any; - testEvent2.getSender = () => ({ userId: "testtestsson" }) as any; - testEvent2.getDate = () => new Date(); - - const testEvent3 = {} as MatrixEvent; - testEvent3.getType = () => "m.room.message"; - testEvent3.isRedacted = () => false; - testEvent3.getContent = () => ({ body: "some different text that doesn't match" }) as any; - testEvent3.getSender = () => ({ userId: "testtestsson" }) as any; - testEvent3.getDate = () => new Date(); - - const room = { - getLiveTimeline: () => { - const timeline = {} as any; - timeline.getEvents = () => [testEvent, testEvent2, testEvent3]; - timeline.getNeighbouringTimeline = () => null; - return timeline; - }, - currentState: { - getMembers: () => [{ name: "Name Namesson", userId: "testtestsson" }], - }, - }; - - const termObj = { - searchTypeAdvanced: false, - searchTypeNormal: true, - fullText: "bodytext", - words: [{ word: "bodytext", highlight: false }], - regExpHighlights: [], - }; - - const matches = await findAllMatches(termObj, room as any, [] as any); - expect(matches.length).toBe(1); - }); - - it("finds several different with advanced search", async () => { - const testEvent = {} as MatrixEvent; - testEvent.getType = () => "m.room.message"; - testEvent.isRedacted = () => false; - testEvent.getContent = () => ({ body: "body text" }) as any; - testEvent.getSender = () => ({ userId: "testtestsson" }) as any; - testEvent.getDate = () => new Date(); - - const testEvent2 = {} as MatrixEvent; - testEvent2.getType = () => "m.room.message"; - testEvent2.isRedacted = () => false; - testEvent2.getContent = () => ({ body: "not that text at all" }) as any; - testEvent2.getSender = () => ({ userId: "testtestsson" }) as any; - testEvent2.getDate = () => new Date(); - - const testEvent3 = {} as MatrixEvent; - testEvent3.getType = () => "m.room.message"; - testEvent3.isRedacted = () => false; - testEvent3.getContent = () => ({ body: "some different text that doesn't match" }) as any; - testEvent3.getSender = () => ({ userId: "testtestsson" }) as any; - testEvent3.getDate = () => new Date(); - - const testEvent4 = {} as MatrixEvent; - testEvent4.getType = () => "m.room.message"; - testEvent4.isRedacted = () => false; - testEvent4.getContent = () => ({ body: "a text that isn't found" }) as any; - testEvent4.getSender = () => ({ userId: "testtestsson" }) as any; - testEvent4.getDate = () => new Date(); - - const room = { - getLiveTimeline: () => { - const timeline = {} as any; - timeline.getEvents = () => [testEvent, testEvent2, testEvent3, testEvent4]; - timeline.getNeighbouringTimeline = () => null; - return timeline; - }, - }; - - const termObj = makeSearchTermObject("rx:(body|all|some)"); - expect(termObj.searchTypeAdvanced).toBe(true); - - const matches = await findAllMatches(termObj, room as any, [] as any); - expect(matches.length).toBe(3); - }); - - it("should be able to find messages sent by specific members", async () => { - const testEvent = {} as MatrixEvent; - testEvent.getType = () => "m.room.message"; - testEvent.isRedacted = () => false; - testEvent.getContent = () => ({ body: "body text Santa Clause" }) as any; - testEvent.getSender = () => "testtestssen" as any; - testEvent.getDate = () => new Date(); - - const testEvent2 = {} as MatrixEvent; - testEvent2.getType = () => "m.room.message"; - testEvent2.isRedacted = () => false; - testEvent2.getContent = () => ({ body: "not that text at all" }) as any; - testEvent2.getSender = () => "namerssen" as any; - testEvent2.getDate = () => new Date(); - - const testEvent3 = {} as MatrixEvent; - testEvent3.getType = () => "m.room.message"; - testEvent3.isRedacted = () => false; - testEvent3.getContent = () => ({ body: "some different text, but not the one Testsson" }) as any; - testEvent3.getSender = () => "namersson" as any; - testEvent3.getDate = () => new Date(); - - const testEvent4 = {} as MatrixEvent; - testEvent4.getType = () => "m.room.message"; - testEvent4.isRedacted = () => false; - testEvent4.getContent = () => ({ body: "a text" }) as any; - testEvent4.getSender = () => "testtestsson" as any; - testEvent4.getDate = () => new Date(); - - const room = { - getLiveTimeline: () => { - const timeline = {} as any; - timeline.getEvents = () => [testEvent, testEvent2, testEvent3, testEvent4]; - timeline.getNeighbouringTimeline = () => null; - return timeline; - }, - }; - - const foundUsers = { - ["testtestsson"]: { name: "Test Testsson", userId: "testtestsson" }, - }; - - const termObj = makeSearchTermObject("Testsson"); - const matches = await findAllMatches(termObj, room as any, foundUsers); - - expect(matches.length).toBe(2); - expect(matches[0].result.getSender()).toBe("testtestsson"); - expect(matches[1].result.getSender()).toBe("namersson"); - }); - - it("can find by ISO date", async () => { - const testEvent = {} as MatrixEvent; - testEvent.getType = () => "m.room.message"; - testEvent.isRedacted = () => false; - testEvent.getContent = () => ({ body: "body text" }) as any; - testEvent.getSender = () => "testtestsson" as any; - testEvent.getDate = () => new Date(2020, 10, 2, 13, 30, 0); - - const testEvent2 = {} as MatrixEvent; - testEvent2.getType = () => "m.room.message"; - testEvent2.isRedacted = () => false; - testEvent2.getContent = () => ({ body: "not that text at all" }) as any; - testEvent2.getSender = () => "namersson" as any; - testEvent2.getDate = () => new Date(2020, 9, 28, 14, 0, 0); - - const room = { - getLiveTimeline: () => { - const timeline = { - getEvents: () => [testEvent, testEvent2], - getNeighbouringTimeline: () => null, - }; - return timeline; - }, - }; - - const foundUsers = {}; - const termObj = makeSearchTermObject("2020-10-28"); - const matches = await findAllMatches(termObj, room as any, foundUsers); - expect(matches.length).toBe(1); - expect(matches[0].result.getSender()).toBe("namersson"); - }); - - it("matches users", async () => { - const termObj = makeSearchTermObject("Namesson"); - const isMatch = isMemberMatch({ name: "Name Namesson", userId: "namenamesson" } as any, termObj); - expect(isMatch).toBe(true); - }); - - it("should reverse the timeline", () => { - const testEvent1 = {} as MatrixEvent; - testEvent1.getType = () => "m.room.message"; - testEvent1.isRedacted = () => false; - testEvent1.getContent = () => ({ body: "body text Santa Clause" }) as any; - testEvent1.getSender = () => "testtestssen" as any; - testEvent1.getDate = () => new Date(); - testEvent1.getId = () => "1"; - - const testEvent2 = {} as MatrixEvent; - testEvent2.getType = () => "m.room.message"; - testEvent2.isRedacted = () => false; - testEvent2.getContent = () => ({ body: "not that text at all" }) as any; - testEvent2.getSender = () => "namerssen" as any; - testEvent2.getDate = () => new Date(); - testEvent2.getId = () => "2"; - - const testEvent3 = {} as MatrixEvent; - testEvent3.getType = () => "m.room.message"; - testEvent3.isRedacted = () => false; - testEvent3.getContent = () => ({ body: "some different text, but not the one Testsson" }) as any; - testEvent3.getSender = () => "namersson" as any; - testEvent3.getDate = () => new Date(); - testEvent3.getId = () => "3"; - - const mockEventContext = { - getTimeline: () => [testEvent1, testEvent2, testEvent3], - getOurEventIndex: () => 1, - getEvent: () => testEvent2, - addEvents: jest.fn(), - }; - - const eventContext = mockEventContext as unknown as EventContext; - - const reversedContext = reverseEventContext(eventContext); - - expect(reversedContext.getTimeline()[0].getId()).toEqual("3"); - expect(reversedContext.getTimeline()[1].getId()).toEqual("2"); - expect(reversedContext.getTimeline()[2].getId()).toEqual("1"); - }); -}); diff --git a/test/components/structures/AppsDrawer-test.tsx b/test/components/structures/AppsDrawer-test.tsx deleted file mode 100644 index 2f004c9a2d5..00000000000 --- a/test/components/structures/AppsDrawer-test.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - Copyright 2024 Verji Tech AS. All rights reserved. - Unauthorized copying or distribution of this file, via any medium, is strictly prohibited. -*/ - -import React from "react"; -import { render, screen } from "@testing-library/react"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; - -import EntityTile from "../../../src/components/views/rooms/EntityTile"; -import { ModuleRunner } from "../../../src/modules/ModuleRunner"; - -describe("EntityTile", () => { - const renderComp = () => { - render(); - }; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it("should render", () => { - renderComp(); - expect(screen.getByTestId("avatar-img")).toBeDefined(); - }); - - describe("wrap the EntityTile with a React.Fragment", () => { - it("should wrap the EntityTile with a React.Fragment", () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.EntityTile) { - (opts as CustomComponentOpts).CustomComponent = ({ children }) => { - return ( - <> -
    Header
    -
    {children}
    -
    Footer
    - - ); - }; - } - }); - - renderComp(); - expect(screen.getByTestId("wrapper-header")).toBeDefined(); - expect(screen.getByTestId("wrapper-EntityTile")).toBeDefined(); - expect(screen.getByTestId("wrapper-footer")).toBeDefined(); - expect(screen.getByTestId("wrapper-header").nextSibling).toBe(screen.getByTestId("wrapper-EntityTile")); - expect(screen.getByTestId("wrapper-EntityTile").nextSibling).toBe(screen.getByTestId("wrapper-footer")); - }); - }); -}); diff --git a/test/components/structures/EntityTile-test.tsx b/test/components/structures/EntityTile-test.tsx deleted file mode 100644 index 2f004c9a2d5..00000000000 --- a/test/components/structures/EntityTile-test.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - Copyright 2024 Verji Tech AS. All rights reserved. - Unauthorized copying or distribution of this file, via any medium, is strictly prohibited. -*/ - -import React from "react"; -import { render, screen } from "@testing-library/react"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; - -import EntityTile from "../../../src/components/views/rooms/EntityTile"; -import { ModuleRunner } from "../../../src/modules/ModuleRunner"; - -describe("EntityTile", () => { - const renderComp = () => { - render(); - }; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it("should render", () => { - renderComp(); - expect(screen.getByTestId("avatar-img")).toBeDefined(); - }); - - describe("wrap the EntityTile with a React.Fragment", () => { - it("should wrap the EntityTile with a React.Fragment", () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.EntityTile) { - (opts as CustomComponentOpts).CustomComponent = ({ children }) => { - return ( - <> -
    Header
    -
    {children}
    -
    Footer
    - - ); - }; - } - }); - - renderComp(); - expect(screen.getByTestId("wrapper-header")).toBeDefined(); - expect(screen.getByTestId("wrapper-EntityTile")).toBeDefined(); - expect(screen.getByTestId("wrapper-footer")).toBeDefined(); - expect(screen.getByTestId("wrapper-header").nextSibling).toBe(screen.getByTestId("wrapper-EntityTile")); - expect(screen.getByTestId("wrapper-EntityTile").nextSibling).toBe(screen.getByTestId("wrapper-footer")); - }); - }); -}); diff --git a/test/components/structures/ErrorBoundary-test.tsx b/test/components/structures/ErrorBoundary-test.tsx deleted file mode 100644 index fc88c008397..00000000000 --- a/test/components/structures/ErrorBoundary-test.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright 2024 Verji Tech AS. All rights reserved. - Unauthorized copying or distribution of this file, via any medium, is strictly prohibited. -*/ - -import React from "react"; -import { render, screen } from "@testing-library/react"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; - -import ErrorBoundary from "../../../src/components/views/elements/ErrorBoundary"; -import { ModuleRunner } from "../../../src/modules/ModuleRunner"; - -describe("ErrorBoundary", () => { - const renderComp = () => { - render( - -
    🤘
    -
    , - ); - }; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it("should render", () => { - renderComp(); - expect(screen.getByText("🤘")).toBeDefined(); - }); - - describe("wrap the ErrorBoundary with a React.Fragment", () => { - it("should wrap the ErrorBoundary with a React.Fragment", () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.ErrorBoundary) { - (opts as CustomComponentOpts).CustomComponent = ({ children }) => { - return ( - <> -
    Header
    -
    {children}
    -
    Footer
    - - ); - }; - } - }); - - renderComp(); - expect(screen.getByTestId("wrapper-header")).toBeDefined(); - expect(screen.getByTestId("wrapper-ErrorBoundary")).toBeDefined(); - expect(screen.getByTestId("wrapper-footer")).toBeDefined(); - expect(screen.getByTestId("wrapper-header").nextSibling).toBe(screen.getByTestId("wrapper-ErrorBoundary")); - expect(screen.getByTestId("wrapper-ErrorBoundary").nextSibling).toBe(screen.getByTestId("wrapper-footer")); - }); - }); -}); diff --git a/test/components/structures/HomePage-test.tsx b/test/components/structures/HomePage-test.tsx deleted file mode 100644 index 9c3be6df60d..00000000000 --- a/test/components/structures/HomePage-test.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright 2023 Mikhail Aheichyk -Copyright 2023 Nordeck IT + Consulting GmbH. - -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 { render, screen } from "@testing-library/react"; - -import HomePage from "../../../src/components/structures/HomePage"; -import SettingsStore from "../../../src/settings/SettingsStore"; -import { getMockClientWithEventEmitter, mockClientMethodsEvents, mockClientMethodsUser } from "../../test-utils"; -import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; - -jest.mock("../../../src/customisations/helpers/UIComponents", () => ({ - shouldShowComponent: jest.fn(), -})); - -describe("HomePage", () => { - const userId = "@me:here"; - const client = getMockClientWithEventEmitter({ - ...mockClientMethodsUser(userId), - ...mockClientMethodsEvents(), - getAccountData: jest.fn(), - isUserIgnored: jest.fn().mockReturnValue(false), - isRoomEncrypted: jest.fn().mockReturnValue(false), - getRoom: jest.fn(), - getClientWellKnown: jest.fn().mockReturnValue({}), - supportsThreads: jest.fn().mockReturnValue(true), - getUserId: jest.fn(), - }); - - jest.spyOn(MatrixClientPeg, "safeGet").mockReturnValue(client); - - client.getUserId.mockReturnValue("123"); - - it("shows the Welcome screen buttons when feature is true", () => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); - - client.getUserId.mockReturnValue("123"); - render(); - - expect(screen.findAllByText("onboarding")).toBeTruthy(); - expect(screen.queryAllByRole("button", { name: /onboarding/i })).toBeTruthy(); - }); - it("does not show the Welcome screen buttons when feature is false", () => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); - - client.getUserId.mockReturnValue("123"); - - render(); - - expect(screen.queryByText("onboarding")).not.toBeInTheDocument(); - expect(screen.queryByRole("button", { name: /onboarding/i })).not.toBeInTheDocument(); - }); -}); diff --git a/test/components/structures/LeftPanel-test.tsx b/test/components/structures/LeftPanel-test.tsx index 4b4e8acb081..1c990aa2310 100644 --- a/test/components/structures/LeftPanel-test.tsx +++ b/test/components/structures/LeftPanel-test.tsx @@ -23,8 +23,7 @@ import LeftPanel from "../../../src/components/structures/LeftPanel"; import PageType from "../../../src/PageTypes"; import ResizeNotifier from "../../../src/utils/ResizeNotifier"; import { shouldShowComponent } from "../../../src/customisations/helpers/UIComponents"; -import { UIComponent, UIFeature } from "../../../src/settings/UIFeature"; -import SettingsStore from "../../../src/settings/SettingsStore"; +import { UIComponent } from "../../../src/settings/UIFeature"; jest.mock("../../../src/customisations/helpers/UIComponents", () => ({ shouldShowComponent: jest.fn(), @@ -52,22 +51,4 @@ describe("LeftPanel", () => { expect(screen.getByRole("button", { name: /search/i })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Explore rooms" })).toBeInTheDocument(); }); - - describe("UIFeature.showExploreRoomsButton", () => { - it("shows the explore rooms button when enabled", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((val) => - val === UIFeature.ShowExploreRoomsButton ? true : "default", - ); - renderComponent(); - expect(screen.getByRole("button", { name: "Explore rooms" })).toBeInTheDocument(); - }); - - it("does not show the explore rooms button when disabled", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((val) => - val === UIFeature.ShowExploreRoomsButton ? false : "default", - ); - renderComponent(); - expect(screen.queryByRole("button", { name: "Explore rooms" })).not.toBeInTheDocument(); - }); - }); }); diff --git a/test/components/structures/LoggedInView-test.tsx b/test/components/structures/LoggedInView-test.tsx index ae77bfbb2b2..04c8b43811a 100644 --- a/test/components/structures/LoggedInView-test.tsx +++ b/test/components/structures/LoggedInView-test.tsx @@ -15,14 +15,10 @@ limitations under the License. */ import React from "react"; -import { render, RenderResult, screen } from "@testing-library/react"; +import { render, RenderResult } from "@testing-library/react"; import { ConditionKind, EventType, IPushRule, MatrixEvent, ClientEvent, PushRuleKind } from "matrix-js-sdk/src/matrix"; import { MediaHandler } from "matrix-js-sdk/src/webrtc/mediaHandler"; import { logger } from "matrix-js-sdk/src/logger"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; import LoggedInView from "../../../src/components/structures/LoggedInView"; import { SDKContext } from "../../../src/contexts/SDKContext"; @@ -30,7 +26,6 @@ import { StandardActions } from "../../../src/notifications/StandardActions"; import ResizeNotifier from "../../../src/utils/ResizeNotifier"; import { flushPromises, getMockClientWithEventEmitter, mockClientMethodsUser } from "../../test-utils"; import { TestSdkContext } from "../../TestSdkContext"; -import { ModuleRunner } from "../../../src/modules/ModuleRunner"; describe("", () => { const userId = "@alice:domain.org"; @@ -58,7 +53,7 @@ describe("", () => { brand: "Test", element_call: {}, }, - currentRoomId: "!someRoom:server", + currentRoomId: "", currentUserId: "@bob:server", }; @@ -73,30 +68,6 @@ describe("", () => { mockClient.setPushRuleActions.mockReset().mockResolvedValue({}); }); - describe("wrap the LoggedInView with a React.Fragment", () => { - it("should wrap the LoggedInView with a React.Fragment", () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.LoggedInView) { - (opts as CustomComponentOpts).CustomComponent = ({ children }) => { - return ( - <> -
    Header
    -
    {children}
    -
    Footer
    - - ); - }; - } - }); - - const { container } = getComponent(); - - const header = container.querySelector("[data-testid=wrapper-header]"); - expect(header?.nextSibling).toBe(container.querySelector("[data-testid=wrapper-LoggedInView]")); - expect(container.children[0].tagName).toEqual("DIV"); - }); - }); - describe("synced push rules", () => { const pushRulesEvent = new MatrixEvent({ type: EventType.PushRules }); @@ -413,77 +384,4 @@ describe("", () => { }); }); }); - describe("CustomComponentLifecycles", () => { - describe("on CustomComponentLifecycle.LeftPanel", () => { - it("should invoke CustomComponentLifecycle.LeftPanel on rendering the LeftPanel", async () => { - jest.spyOn(ModuleRunner.instance, "invoke"); - getComponent(); - await flushPromises(); - expect(ModuleRunner.instance.invoke).toHaveBeenCalledWith(CustomComponentLifecycle.LeftPanel, { - CustomComponent: expect.any(Symbol), - }); - }); - - it("should render standard LeftPanel if if there are no module-implementations using the lifecycle", async () => { - const { container } = getComponent(); - await flushPromises(); - expect(container.querySelector(".mx_LeftPanel")).toBeVisible(); - }); - it("should replace the default LeftPanel and return
    instead", async () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.LeftPanel) { - (opts as CustomComponentOpts).CustomComponent = () => { - return ( - <> -
    - - ); - }; - } - }); - const container = getComponent().container as HTMLElement; - await flushPromises(); - - const customSpacePanel = screen.queryByTestId("custom-left-panel"); - expect(customSpacePanel).toBeVisible(); - expect(container.querySelector(".mx_LeftPanel")).toBeNull(); - }); - }); - describe("on CustomComponentLifecycle.SpacePanel", () => { - it("should invoke CustomComponentLifecycle.SpacePanel on rendering the SpacePanel", async () => { - jest.spyOn(ModuleRunner.instance, "invoke"); - getComponent(); - await flushPromises(); - expect(ModuleRunner.instance.invoke).toHaveBeenCalledWith(CustomComponentLifecycle.SpacePanel, { - CustomComponent: expect.any(Symbol), - }); - }); - - it("should render standard SpacePanel if if there are no module-implementations using the lifecycle", async () => { - const { container } = getComponent(); - await flushPromises(); - expect(container.querySelector(".mx_SpacePanel")).toBeVisible(); - }); - - it("should replace the default SpacePanel and return
    instead", async () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.SpacePanel) { - (opts as CustomComponentOpts).CustomComponent = () => { - return ( - <> -
    - - ); - }; - } - }); - const container = getComponent().container as HTMLElement; - await flushPromises(); - - const customSpacePanel = screen.queryByTestId("custom-space-panel"); - expect(customSpacePanel).toBeVisible(); - expect(container.querySelector(".mx_SpacePanel")).toBeNull(); - }); - }); - }); }); diff --git a/test/components/structures/MessagePanel-test.tsx b/test/components/structures/MessagePanel-test.tsx index ba12728dba3..23f094d4abd 100644 --- a/test/components/structures/MessagePanel-test.tsx +++ b/test/components/structures/MessagePanel-test.tsx @@ -37,7 +37,6 @@ import { import ResizeNotifier from "../../../src/utils/ResizeNotifier"; import { IRoomState } from "../../../src/components/structures/RoomView"; import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; -import { UIFeature } from "../../../src/settings/UIFeature"; jest.mock("../../../src/utils/beacon", () => ({ useBeacon: jest.fn(), @@ -108,7 +107,6 @@ describe("MessagePanel", function () { jest.clearAllMocks(); // HACK: We assume all settings want to be disabled jest.spyOn(SettingsStore, "getValue").mockImplementation((arg) => { - if (arg == UIFeature.EnableNewRoomIntro) return true; return arg === "showDisplaynameChanges"; }); @@ -516,59 +514,7 @@ describe("MessagePanel", function () { // read marker should be hidden given props and at the last event expect(isReadMarkerVisible(rm)).toBeFalsy(); }); - it("should show NewRoomIntro if featrue is on", function () { - const events = mkCreationEvents(); - const createEvent = events.find((event) => event.getType() === "m.room.create"); - client.getRoom.mockImplementation((id) => (id === createEvent!.getRoomId() ? room : null)); - TestUtilsMatrix.upsertRoomStateEvents(room, events); - - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.EnableNewRoomIntro) return true; - return true; - }); - - const { container } = render( - getComponent({ - events, - readMarkerEventId: events[5].getId(), - readMarkerVisible: true, - }), - ); - - // find the
  • which wraps the read marker - const [rm] = container.getElementsByClassName("mx_MessagePanel_myReadMarker"); - - const [messageList] = container.getElementsByClassName("mx_RoomView_MessageList"); - const rows = messageList.children; - expect(rows.length).toEqual(7); // 6 events + the NewRoomIntro - expect(rm.previousSibling).toEqual(rows[5]); - // read marker should be hidden given props and at the last event - expect(isReadMarkerVisible(rm)).toBeFalsy(); - }); - it("should not show NewRoomIntro if featrue is off", function () { - const events = mkCreationEvents(); - const createEvent = events.find((event) => event.getType() === "m.room.create"); - client.getRoom.mockImplementation((id) => (id === createEvent!.getRoomId() ? room : null)); - TestUtilsMatrix.upsertRoomStateEvents(room, events); - - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.EnableNewRoomIntro) return false; - return true; - }); - - const { container } = render( - getComponent({ - events, - readMarkerEventId: events[5].getId(), - readMarkerVisible: true, - }), - ); - - const [messageList] = container.getElementsByClassName("mx_RoomView_MessageList"); - const rows = messageList.children; - expect(rows.length).toEqual(6); // 6 events without the NewRoomIntro - }); it("should render Date separators for the events", function () { const events = mkOneDayEvents(); const { queryAllByRole } = render(getComponent({ events })); diff --git a/test/components/structures/ReactionsRowButtonTooltip-test.tsx b/test/components/structures/ReactionsRowButtonTooltip-test.tsx deleted file mode 100644 index fcb0486b509..00000000000 --- a/test/components/structures/ReactionsRowButtonTooltip-test.tsx +++ /dev/null @@ -1,94 +0,0 @@ -/* - Copyright 2024 Verji Tech AS. All rights reserved. - Unauthorized copying or distribution of this file, via any medium, is strictly prohibited. -*/ - -import React from "react"; -import { render, screen } from "@testing-library/react"; -import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; - -import ReactionsRowButtonTooltip from "../../../src/components/views/messages/ReactionsRowButtonTooltip"; -import { getMockClientWithEventEmitter } from "../../test-utils"; -import MatrixClientContext from "../../../src/contexts/MatrixClientContext"; -import { ModuleRunner } from "../../../src/modules/ModuleRunner"; - -describe("ReactionsRowButtonTooltip", () => { - const content = "Hello world!"; - const reactionEvents = [] as any; - const visible = true; - const roomId = "myRoomId"; - const mockClient = getMockClientWithEventEmitter({ - mxcUrlToHttp: jest.fn().mockReturnValue("https://not.a.real.url"), - getRoom: jest.fn(), - }); - const userId = "@alice:server"; - const room = new Room(roomId, mockClient, userId); - - const customReactionImagesEnabled = true; - - const mxEvent = { - getRoomId: jest.fn().mockReturnValue(roomId), - pushDetails: {}, - _replacingEvent: null, - _localRedactionEvent: null, - _isCancelled: false, - } as unknown as MatrixEvent; - - const getComp = () => - render( - - - , - ); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it("should render", () => { - const { asFragment } = getComp(); - screen.debug(); - expect(asFragment()).toMatchSnapshot(); - }); - - describe("wrap the ReactionsRowButtonTooltip with a React.Fragment", () => { - it("should wrap the ReactionsRowButtonTooltip with a React.Fragment", () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.ReactionsRowButtonTooltip) { - (opts as CustomComponentOpts).CustomComponent = ({ children }) => { - return ( - <> -
    Header
    -
    {children}
    -
    Footer
    - - ); - }; - } - }); - - getComp(); - expect(screen.getByTestId("wrapper-header")).toBeDefined(); - expect(screen.getByTestId("wrapper-ReactionsRowButtonTooltip")).toBeDefined(); - expect(screen.getByTestId("wrapper-footer")).toBeDefined(); - expect(screen.getByTestId("wrapper-header").nextSibling).toBe( - screen.getByTestId("wrapper-ReactionsRowButtonTooltip"), - ); - expect(screen.getByTestId("wrapper-ReactionsRowButtonTooltip").nextSibling).toBe( - screen.getByTestId("wrapper-footer"), - ); - }); - }); -}); diff --git a/test/components/structures/RoomView-test.tsx b/test/components/structures/RoomView-test.tsx index d96ca69b605..31f5c896aec 100644 --- a/test/components/structures/RoomView-test.tsx +++ b/test/components/structures/RoomView-test.tsx @@ -33,12 +33,7 @@ import { KnownMembership } from "matrix-js-sdk/src/types"; import { MEGOLM_ALGORITHM } from "matrix-js-sdk/src/crypto/olmlib"; import { fireEvent, render, screen, RenderResult, waitForElementToBeRemoved, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; -import { ModuleRunner } from "../../../src/modules/ModuleRunner"; import { stubClient, mockPlatformPeg, @@ -720,69 +715,4 @@ describe("RoomView", () => { await mountRoomView(); expect(dis.dispatch).toHaveBeenCalledWith({ action: Action.RoomLoaded }); }); - - describe("CustomComponentLifecycle.RoomHeader", () => { - it("should invoke CustomComponentLifecycle.RoomHeader when you are joined (not previewing)", async () => { - jest.spyOn(ModuleRunner.instance, "invoke"); - room.getMyMembership = jest.fn().mockReturnValue(KnownMembership.Join); - await renderRoomView(); - expect(ModuleRunner.instance.invoke).toHaveBeenCalledWith(CustomComponentLifecycle.RoomHeader, { - CustomComponent: expect.any(Symbol), - }); - }); - - it("should render LegacyRoomHeader if if there are no module-implementations using the lifecycle", async () => { - room.getMyMembership = jest.fn().mockReturnValue(KnownMembership.Join); - const { container } = await renderRoomView(); - expect(container.querySelector(".mx_LegacyRoomHeader")).toBeVisible(); - }); - - it("should replace the default RoomHeader and return
    instead", async () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.RoomHeader) { - (opts as CustomComponentOpts).CustomComponent = () => { - return ( - <> -
    - - ); - }; - } - }); - - room.getMyMembership = jest.fn().mockReturnValue(KnownMembership.Join); - const { container } = await renderRoomView(); - const customRoomHeader = screen.queryByTestId("custom-room-header"); - expect(customRoomHeader).toBeVisible(); - expect(container.querySelector(".mx_LegacyRoomHeader")).toBeNull(); - }); - }); - - describe("CustomComponentLifecycle.RoomView", () => { - it("should wrap RoomView with a custom RoomHeader", async () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.RoomView) { - (opts as CustomComponentOpts).CustomComponent = ({ children }) => { - return ( - <> -
    Header
    -
    {children}
    -
    Footer
    - - ); - }; - } - }); - - room.getMyMembership = jest.fn().mockReturnValue(KnownMembership.Join); - - await renderRoomView(); - - expect(screen.getByTestId("wrapper-header")).toBeDefined(); - expect(screen.getByTestId("wrapper-RoomView")).toBeDefined(); - expect(screen.getByTestId("wrapper-footer")).toBeDefined(); - expect(screen.getByTestId("wrapper-header").nextSibling).toBe(screen.getByTestId("wrapper-RoomView")); - expect(screen.getByTestId("wrapper-RoomView").nextSibling).toBe(screen.getByTestId("wrapper-footer")); - }); - }); }); diff --git a/test/components/structures/SpaceRoomView-test.tsx b/test/components/structures/SpaceRoomView-test.tsx deleted file mode 100644 index 13d3689751e..00000000000 --- a/test/components/structures/SpaceRoomView-test.tsx +++ /dev/null @@ -1,64 +0,0 @@ -/* - Copyright 2024 Verji Tech AS. All rights reserved. - Unauthorized copying or distribution of this file, via any medium, is strictly prohibited. -*/ - -/** - * @todo This test is incomplete and needs to be finished. - */ - -import React from "react"; -import { render, screen } from "@testing-library/react"; -import { MatrixClient, Room } from "matrix-js-sdk/src/matrix"; -import { MockedObject, mocked } from "jest-mock"; - -import SpaceRoomView from "../../../src/components/structures/SpaceRoomView"; -import { mkSpace, stubClient } from "../../test-utils"; -import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; -import ResizeNotifier from "../../../src/utils/ResizeNotifier"; -import { RoomPermalinkCreator } from "../../../src/utils/permalinks/Permalinks"; -import MatrixClientContext from "../../../src/contexts/MatrixClientContext"; - -describe("SpaceRoomView", () => { - stubClient(); - const client: MockedObject = mocked(MatrixClientPeg.safeGet()); - const sourceRoom = "!111111111111111111:example.org"; - - const setupSpace = (client: MatrixClient): Room => { - const testSpace: Room = mkSpace(client, "!space:server"); - testSpace.name = "Test Space"; - client.getRoom = () => testSpace; - return testSpace; - }; - - const space = setupSpace(client); - - const context = { - getSafeUserId: jest.fn().mockReturnValue("@guest:localhost"), - }; - - jest.spyOn(MatrixClientPeg, "get").mockReturnValue(client); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - const renderComp = () => - render( - - console.log("Function not implemented.")} - onRejectButtonClicked={(): void => console.log("Function not implemented.")} - /> - , - ); - - it("should render a SpaceRoomView", () => { - renderComp(); - screen.debug(); - expect(screen.getByText("Something went wrong!")).toBeInTheDocument(); - }); -}); diff --git a/test/components/structures/__snapshots__/ReactionsRowButtonTooltip-test.tsx.snap b/test/components/structures/__snapshots__/ReactionsRowButtonTooltip-test.tsx.snap deleted file mode 100644 index 354ed64663d..00000000000 --- a/test/components/structures/__snapshots__/ReactionsRowButtonTooltip-test.tsx.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ReactionsRowButtonTooltip should render 1`] = ` - -
    - -`; diff --git a/test/components/structures/auth/Login-test.tsx b/test/components/structures/auth/Login-test.tsx index e3511e6d59d..93a02f31db0 100644 --- a/test/components/structures/auth/Login-test.tsx +++ b/test/components/structures/auth/Login-test.tsx @@ -31,7 +31,6 @@ import SettingsStore from "../../../../src/settings/SettingsStore"; import { Features } from "../../../../src/settings/Settings"; import * as registerClientUtils from "../../../../src/utils/oidc/registerClient"; import { makeDelegatedAuthConfig } from "../../../test-utils/oidc"; -import { UIFeature } from "../../../../src/settings/UIFeature"; jest.useRealTimers(); @@ -381,10 +380,9 @@ describe("Login", function () { const delegatedAuth = makeDelegatedAuthConfig(issuer); beforeEach(() => { jest.spyOn(logger, "error"); - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.EnableLoginPage) return true; - return name === Features.OidcNativeFlow; - }); + jest.spyOn(SettingsStore, "getValue").mockImplementation( + (settingName) => settingName === Features.OidcNativeFlow, + ); }); afterEach(() => { @@ -392,10 +390,7 @@ describe("Login", function () { }); it("should not attempt registration when oidc native flow setting is disabled", async () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.EnableLoginPage) return true; - return false; - }); + jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); getComponent(hsUrl, isUrl, delegatedAuth); @@ -455,11 +450,7 @@ describe("Login", function () { * Oidc-aware flows still work while the oidc-native feature flag is disabled */ it("should show oidc-aware flow for oidc-enabled homeserver when oidc native flow setting is disabled", async () => { - // jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.UserSettingsResetBackup) return false; - return true; - }); + jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); mockClient.loginFlows.mockResolvedValue({ flows: [ { diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index 070a2e72bb1..8fd2f9f4163 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -31,10 +31,6 @@ import { } from "matrix-js-sdk/src/matrix"; import { PollStartEvent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent"; import { mocked } from "jest-mock"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import RoomContext, { TimelineRenderingType } from "../../../../src/contexts/RoomContext"; @@ -50,7 +46,6 @@ import { Action } from "../../../../src/dispatcher/actions"; import { mkVoiceBroadcastInfoStateEvent } from "../../../voice-broadcast/utils/test-utils"; import { VoiceBroadcastInfoState } from "../../../../src/voice-broadcast"; import { createMessageEventContent } from "../../../test-utils/events"; -import { ModuleRunner } from "../../../../src/modules/ModuleRunner"; jest.mock("../../../../src/utils/strings", () => ({ copyPlaintext: jest.fn(), @@ -528,39 +523,6 @@ describe("MessageContextMenu", () => { }); }); }); - - describe("wrapping MessageContextMenu with a custom component", () => { - it("should wrap the MessageContextMenu with a custom component", () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.MessageContextMenu) { - (opts as CustomComponentOpts).CustomComponent = ({ children }) => { - return ( - <> -
    Header
    -
    {children}
    -
    Footer
    - - ); - }; - } - }); - - const eventContent = createMessageEventContent("hello"); - const mxEvent = new MatrixEvent({ type: EventType.RoomMessage, content: eventContent }); - - createMenu(mxEvent); - - expect(document.querySelector('[data-testid="wrapper-header"]')).toBeDefined(); - expect(document.querySelector('[data-testid="wrapper-MessageContextMenu"]')).toBeDefined(); - expect(document.querySelector('[data-testid="wrapper-footer"]')).toBeDefined(); - expect(document.querySelector('[data-testid="wrapper-header"]')?.nextSibling).toBe( - document.querySelector('[data-testid="wrapper-MessageContextMenu"]'), - ); - expect(document.querySelector('[data-testid="wrapper-MessageContextMenu"]')?.nextSibling).toBe( - document.querySelector('[data-testid="wrapper-footer"]'), - ); - }); - }); }); function createRightClickMenuWithContent(eventContent: object, context?: Partial): RenderResult { diff --git a/test/components/views/context_menus/RoomContextMenu-test.tsx b/test/components/views/context_menus/RoomContextMenu-test.tsx index 4458c26af8f..535e03f5179 100644 --- a/test/components/views/context_menus/RoomContextMenu-test.tsx +++ b/test/components/views/context_menus/RoomContextMenu-test.tsx @@ -31,7 +31,6 @@ import DMRoomMap from "../../../../src/utils/DMRoomMap"; import SettingsStore from "../../../../src/settings/SettingsStore"; import { EchoChamber } from "../../../../src/stores/local-echo/EchoChamber"; import { RoomNotifState } from "../../../../src/RoomNotifs"; -import { UIFeature } from "../../../../src/settings/UIFeature"; jest.mock("../../../../src/customisations/helpers/UIComponents", () => ({ shouldShowComponent: jest.fn(), @@ -93,31 +92,10 @@ describe("RoomContextMenu", () => { renderComponent(); expect(screen.queryByText("Developer tools")).not.toBeInTheDocument(); }); - //eik - it("renders files menuitem when feature is on", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.RoomSummaryFilesOption) return true; - return true; - }); - renderComponent(); - expect(screen.queryByText("Files")).toBeInTheDocument(); - }); - it("does not render files menuitem when feature is off", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.RoomSummaryFilesOption) return false; - return true; - }); - - renderComponent(); - expect(screen.queryByText("Files")).not.toBeInTheDocument(); - }); - //eik end describe("when developer mode is enabled", () => { beforeEach(() => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - if (setting == "developerMode") return true; - }); + jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => setting === "developerMode"); }); it("should render the developer tools option", () => { diff --git a/test/components/views/context_menus/SpaceContextMenu-test.tsx b/test/components/views/context_menus/SpaceContextMenu-test.tsx index b43ffce24cf..03324378ee7 100644 --- a/test/components/views/context_menus/SpaceContextMenu-test.tsx +++ b/test/components/views/context_menus/SpaceContextMenu-test.tsx @@ -246,41 +246,4 @@ describe("", () => { expect(screen.queryByTestId("leave-option")).not.toBeInTheDocument(); }); }); - - describe("UIFeature.AddSubSpace feature flag", () => { - const space = makeMockSpace(); - - beforeEach(() => { - // set space to allow adding children to space - mocked(space.currentState.maySendStateEvent).mockReturnValue(true); - mocked(shouldShowComponent).mockReturnValue(true); - jest.clearAllMocks(); - }); - - it("UIFeature.AddSubSpace = true: renders create space button when UIFeature is true", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => { - if (name === UIFeature.AddSubSpace) return true; - else return "default"; - }); - renderComponent({ space }); - - screen.debug(); - - expect(screen.getByTestId("add-to-space-header")).toBeInTheDocument(); - expect(screen.getByTestId("new-room-option")).toBeInTheDocument(); - expect(screen.queryByTestId("new-subspace-option")).toBeInTheDocument(); - }); - - it("UIFeature.AddSubSpace = false: does not render create space button when UIFeature is false", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => { - if (name === UIFeature.AddSubSpace) return false; - else return "default"; - }); - renderComponent({ space }); - - expect(screen.getByTestId("add-to-space-header")).toBeInTheDocument(); - expect(screen.getByTestId("new-room-option")).toBeInTheDocument(); - expect(screen.queryByTestId("new-subspace-option")).not.toBeInTheDocument(); - }); - }); }); diff --git a/test/components/views/dialogs/CreateRoomDialog-test.tsx b/test/components/views/dialogs/CreateRoomDialog-test.tsx index acf0d7eb6d9..68bcef48c8f 100644 --- a/test/components/views/dialogs/CreateRoomDialog-test.tsx +++ b/test/components/views/dialogs/CreateRoomDialog-test.tsx @@ -21,7 +21,6 @@ import { JoinRule, MatrixError, Preset, Visibility } from "matrix-js-sdk/src/mat import CreateRoomDialog from "../../../../src/components/views/dialogs/CreateRoomDialog"; import { flushPromises, getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../test-utils"; import SettingsStore from "../../../../src/settings/SettingsStore"; -import { UIFeature } from "../../../../src/settings/UIFeature"; describe("", () => { const userId = "@alice:server.org"; @@ -208,60 +207,12 @@ describe("", () => { roomType: undefined, }); }); - //Eik - it("should not show rule dropdown, when UIFeature.CreateRoomShowJoinRuleDropdown is set to false", async () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - if (setting === UIFeature.CreateRoomShowJoinRuleDropdown) return false; - return true; - }); - getComponent(); - await flushPromises(); - - expect( - screen.queryByRole("LabelledCheckbox", { - name: "Make this room visible in the public room directory.", - }), - ).not.toBeInTheDocument(); - expect(screen.queryByRole("option", { name: "Ask to join" })).not.toBeInTheDocument(); - }); - it("should not show end-to-end encryption option, when UIFeature.CreateRoomE2eeSection is set to false", async () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - if (setting === UIFeature.CreateRoomE2eeSection) return false; - return true; - }); - getComponent(); - await flushPromises(); - - expect( - screen.queryByRole("LabelledToggleSwitch", { name: "Enable end-to-end encryption" }), - ).not.toBeInTheDocument(); - }); - it("should not display 'Show Advanced', when UIFeature.CreateRoomShowAdvancedSettings is set to false", async () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - if (setting === UIFeature.CreateRoomShowAdvancedSettings) return false; - return true; - }); - getComponent(); - await flushPromises(); - - expect( - screen.queryByRole("LabelledToggleSwitch", { - name: "Block anyone not part of %(serverName)s from ever joining this room.", - }), - ).not.toBeInTheDocument(); - }); - //eik end }); describe("for a knock room", () => { describe("when feature is disabled", () => { it("should not have the option to create a knock room", async () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - if (setting === UIFeature.CreateRoomShowJoinRuleDropdown) return true; - if (setting === UIFeature.CreateRoomE2eeSection) return true; - if (setting === UIFeature.CreateRoomShowAdvancedSettings) return true; - return false; - }); + jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); getComponent(); fireEvent.click(screen.getByLabelText("Room visibility")); expect(screen.queryByRole("option", { name: "Ask to join" })).not.toBeInTheDocument(); @@ -274,14 +225,9 @@ describe("", () => { beforeEach(async () => { onFinished.mockReset(); - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - if (setting === "feature_ask_to_join") return true; - if (setting === UIFeature.CreateRoomShowJoinRuleDropdown) return true; - if (setting === UIFeature.CreateRoomE2eeSection) return true; - if (setting === UIFeature.CreateRoomShowAdvancedSettings) return true; - - return false; - }); + jest.spyOn(SettingsStore, "getValue").mockImplementation( + (setting) => setting === "feature_ask_to_join", + ); getComponent({ onFinished }); fireEvent.change(screen.getByLabelText("Name"), { target: { value: roomName } }); fireEvent.click(screen.getByLabelText("Room visibility")); diff --git a/test/components/views/dialogs/ExportDialog-test.tsx b/test/components/views/dialogs/ExportDialog-test.tsx index 2f54f3a0835..7ac59d24280 100644 --- a/test/components/views/dialogs/ExportDialog-test.tsx +++ b/test/components/views/dialogs/ExportDialog-test.tsx @@ -26,8 +26,6 @@ import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import HTMLExporter from "../../../../src/utils/exportUtils/HtmlExport"; import ChatExport from "../../../../src/customisations/ChatExport"; import PlainTextExporter from "../../../../src/utils/exportUtils/PlainTextExport"; -import SettingsStore from "../../../../src/settings/SettingsStore"; -import { UIFeature } from "../../../../src/settings/UIFeature"; jest.useFakeTimers(); @@ -89,8 +87,6 @@ describe("", () => { // default setting value mocked(ChatExportMock.getForceChatExportParameters!).mockClear().mockReturnValue({}); - - jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); }); it("renders export dialog", () => { @@ -160,10 +156,6 @@ describe("", () => { }); describe("export format", () => { - beforeEach(() => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); - }); - it("renders export format with html selected by default", () => { const component = getComponent(); expect(getExportFormatInput(component, ExportFormat.Html)).toBeChecked(); @@ -191,10 +183,6 @@ describe("", () => { }); describe("export type", () => { - beforeEach(() => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); - }); - it("renders export type with timeline selected by default", () => { const component = getComponent(); expect(getExportTypeInput(component)).toHaveValue(ExportType.Timeline); @@ -261,33 +249,9 @@ describe("", () => { expect(htmlExporterInstance.export).toHaveBeenCalled(); }); }); - - //eik - it("renders export type when feature is on", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.AllExportTypes) return true; - return true; - }); - const component = getComponent(); - expect(getExportTypeInput(component)).not.toBeNull(); - }); - it("does not render export type when feature is off", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.AllExportTypes) return false; - return true; - }); - const component = getComponent(); - expect(getExportTypeInput(component)).toBeFalsy(); - }); - - //eik end }); describe("size limit", () => { - beforeEach(() => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); - }); - it("renders size limit input with default value", () => { const component = getComponent(); expect(getSizeInput(component)).toHaveValue(8); @@ -345,34 +309,9 @@ describe("", () => { expect(htmlExporterInstance.export).toHaveBeenCalled(); }); - //Eik - it("renders size limit input when feature is on", () => { - console.log("Eik : feature is on"); - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.ExportDefaultSizeLimit) return true; - return true; - }); - const component = getComponent(); - expect(getSizeInput(component)).toHaveValue(8); - }); - it("does not render size limit input when feature is off", () => { - console.log("Eik : feature is off"); - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.ExportDefaultSizeLimit) return false; - return true; - }); - const component = getComponent(); - expect(getSizeInput(component)).toBeFalsy(); - }); - - //Eik end }); describe("include attachments", () => { - beforeEach(() => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); - }); - it("renders input with default value of false", () => { const component = getComponent(); expect(getAttachmentsCheckbox(component)).not.toBeChecked(); @@ -391,24 +330,5 @@ describe("", () => { const component = getComponent(); expect(getAttachmentsCheckbox(component)).toBeFalsy(); }); - //Eik - it("renders checkbox empty if feature is on", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.ExportAttatchmentsDefaultOff) return true; - return true; - }); - const component = getComponent(); - expect(getAttachmentsCheckbox(component)).not.toBeChecked(); - }); - it("renders the checkbox checked when off", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.ExportAttatchmentsDefaultOff) return false; - return true; - }); - const component = getComponent(); - expect(getAttachmentsCheckbox(component)).toBeChecked(); - }); - - //Eik end }); }); diff --git a/test/components/views/dialogs/InviteDialog-test.tsx b/test/components/views/dialogs/InviteDialog-test.tsx index a28b742b516..16f756cb01b 100644 --- a/test/components/views/dialogs/InviteDialog-test.tsx +++ b/test/components/views/dialogs/InviteDialog-test.tsx @@ -41,7 +41,6 @@ import { IProfileInfo } from "../../../../src/hooks/useProfileInfo"; import { DirectoryMember, startDmOnFirstMessage } from "../../../../src/utils/direct-messages"; import SettingsStore from "../../../../src/settings/SettingsStore"; import Modal from "../../../../src/Modal"; -import HomePage from "../../../../src/components/structures/HomePage"; const mockGetAccessToken = jest.fn().mockResolvedValue("getAccessToken"); jest.mock("../../../../src/IdentityAuthClient", () => @@ -494,10 +493,4 @@ describe("InviteDialog", () => { await flushPromises(); expect(screen.queryByText("@localpart:server.tld")).not.toBeInTheDocument(); }); - it("does not show buttons on HomePage when UIFeature is false", () => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); - - render(); - expect(screen.queryByText("Explore")).not.toBeInTheDocument(); - }); }); diff --git a/test/components/views/dialogs/RoomSettingsDialog-test.tsx b/test/components/views/dialogs/RoomSettingsDialog-test.tsx index 907fe304c13..9a5f9b6745f 100644 --- a/test/components/views/dialogs/RoomSettingsDialog-test.tsx +++ b/test/components/views/dialogs/RoomSettingsDialog-test.tsx @@ -25,17 +25,12 @@ import { RoomStateEvent, Visibility, } from "matrix-js-sdk/src/matrix"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; import { getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../test-utils"; import RoomSettingsDialog from "../../../../src/components/views/dialogs/RoomSettingsDialog"; import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; import SettingsStore from "../../../../src/settings/SettingsStore"; import { UIFeature } from "../../../../src/settings/UIFeature"; -import { ModuleRunner } from "../../../../src/modules/ModuleRunner"; describe("", () => { const userId = "@alice:server.org"; @@ -96,24 +91,7 @@ describe("", () => { const { container } = getComponent(); expect(container.querySelectorAll(".mx_TabbedView_tabLabel")).toMatchSnapshot(); }); - it("renders security & privacy if UIFeature is on", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.RoomSettingsSecurity) return true; - return true; - }); - getComponent(); - // expect(container.querySelectorAll(".mx_TabbedView_tabLabel")).toMatchSnapshot(); - expect(screen.queryByText("Security & Privacy")).not.toBeNull(); - }); - it("does not renders security & privacy if UIFeature is off", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.RoomSettingsSecurity) return false; - return true; - }); - getComponent(); - // expect(container.querySelectorAll(".mx_TabbedView_tabLabel")).toMatchSnapshot(); - expect(screen.queryByText("Security & Privacy")).toBeNull(); - }); + describe("people settings tab", () => { it("does not render when disabled and room join rule is not knock", () => { jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Invite); @@ -204,43 +182,4 @@ describe("", () => { expect(container.querySelector(".mx_SettingsTab")).toMatchSnapshot(); }); }); - describe("on CustomComponentLifecycle.RolesRoomSettingsTab", () => { - it("should invoke CustomComponentLifecycle.RolesRoomSettingsTab on rendering the RolesRoomSettingsDialog component", () => { - jest.spyOn(ModuleRunner.instance, "invoke"); - getComponent(); - expect(ModuleRunner.instance.invoke).toHaveBeenCalledWith(CustomComponentLifecycle.RolesRoomSettingsTab, { - CustomComponent: expect.any(Symbol), - }); - }); - - it("should render standard RolesRoomSettingsTab if if there are no module-implementations using the lifecycle", () => { - const container = getComponent().container as HTMLElement; - fireEvent.click(screen.getByText("Roles & Permissions")); - - expect(container.querySelector("#mx_tabpanel_ROOM_ROLES_TAB")).toBeVisible(); - // Expect that element unique to Roles-tab is rendered. - expect(screen.getByTestId("add-privileged-users-submit-button")).toBeVisible(); - }); - - it("should replace the default RolesRoomSettingsTab and return
    instead", () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.RolesRoomSettingsTab) { - (opts as CustomComponentOpts).CustomComponent = () => { - return ( - <> -
    - - ); - }; - } - }); - getComponent(); - fireEvent.click(screen.getByText("Roles & Permissions")); - const customRolesTab = screen.queryByTestId("custom-roles-room-settings-tab"); - expect(customRolesTab).toBeVisible(); - - // Expect that element unique to RolesRoomSettingsTab is NOT-rendered, as proof of default RolesRoomSettingsTab not being in the document. - expect(screen.queryByTestId("add-privileged-users-submit-button")).toBeFalsy(); - }); - }); }); diff --git a/test/components/views/dialogs/UserSettingsDialog-test.tsx b/test/components/views/dialogs/UserSettingsDialog-test.tsx index a6978ae7772..72232d5e1b5 100644 --- a/test/components/views/dialogs/UserSettingsDialog-test.tsx +++ b/test/components/views/dialogs/UserSettingsDialog-test.tsx @@ -15,13 +15,9 @@ limitations under the License. */ import React, { ReactElement } from "react"; -import { fireEvent, render, screen } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import { mocked, MockedObject } from "jest-mock"; import { MatrixClient } from "matrix-js-sdk/src/matrix"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; import SettingsStore, { CallbackFn } from "../../../../src/settings/SettingsStore"; import SdkConfig from "../../../../src/SdkConfig"; @@ -39,7 +35,6 @@ import { import { UIFeature } from "../../../../src/settings/UIFeature"; import { SettingLevel } from "../../../../src/settings/SettingLevel"; import { SdkContextClass } from "../../../../src/contexts/SDKContext"; -import { ModuleRunner } from "../../../../src/modules/ModuleRunner"; mockPlatformPeg({ supportsSpellCheckSettings: jest.fn().mockReturnValue(false), @@ -119,10 +114,6 @@ describe("", () => { }); it("renders tabs correctly", () => { - // jest.spyOn(SettingsStore, "getValue").mockImplementation((name:string) => { - // if (name == UIFeature.SpacesEnabled) return true; - // return true; - // }); const { container } = render(getComponent()); expect(container.querySelectorAll(".mx_TabbedView_tabLabel")).toMatchSnapshot(); }); @@ -174,7 +165,6 @@ describe("", () => { }); it("renders with sidebar tab selected", () => { - mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === UIFeature.SpacesEnabled); const { container } = render(getComponent({ initialTabId: UserTab.Sidebar })); expect(getActiveTabLabel(container)).toEqual("Sidebar"); @@ -191,7 +181,6 @@ describe("", () => { }); it("renders with secutity tab selected", () => { - mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === UIFeature.SpacesEnabled); const { container } = render(getComponent({ initialTabId: UserTab.Security })); expect(getActiveTabLabel(container)).toEqual("Security & Privacy"); @@ -273,59 +262,5 @@ describe("", () => { // unwatches settings on unmount expect(mockSettingsStore.unwatchSetting).toHaveBeenCalledWith("mock-watcher-id-feature_mjolnir"); - describe("on CustomComponentLifecycle.SessionManageTab", () => { - it("should invoke CustomComponentLifecycle.SessionsManagerTab on rendering when Sessions-tab component renders", () => { - jest.spyOn(ModuleRunner.instance, "invoke"); - render(getComponent()); - fireEvent.click(screen.getByText("Sessions")); - screen.debug(undefined, 300000); - expect(ModuleRunner.instance.invoke).toHaveBeenCalledWith(CustomComponentLifecycle.SessionManagerTab, { - CustomComponent: expect.any(Symbol), - }); - }); - - it("should render standard SessionManagerTab if if there are no module-implementations using the lifecycle", () => { - const { container } = render(getComponent()); - fireEvent.click(screen.getByText("Sessions")); - - expect(container.querySelector("#mx_tabpanel_USER_SESSION_MANAGER_TAB")).toBeVisible(); - // Expect that element unique to SessionsManagerTab is rendered. - expect(screen.getByTestId("current-session-section")).toBeVisible(); - }); - - it("should replace the default SessionManagerTab and return
    instead", () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.SessionManagerTab) { - (opts as CustomComponentOpts).CustomComponent = () => { - return ( - <> -
    - - ); - }; - } - }); - render(getComponent()); - fireEvent.click(screen.getByText("Sessions")); - const customRolesTab = screen.queryByTestId("custom-user-sessions-manager-tab"); - expect(customRolesTab).toBeVisible(); - - // Expect that element unique to RolesRoomSettingsTab is NOT-rendered, as proof of default RolesRoomSettingsTab not being in the document. - expect(screen.queryByTestId("current-session-section")).toBeFalsy(); - }); - }); - }); - it("renders sidebar and access tab when feature is on", () => { - mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === UIFeature.SpacesEnabled); - - const { getByTestId } = render(getComponent()); - expect(getByTestId(`settings-tab-${UserTab.Sidebar}`)).toBeTruthy(); - expect(getByTestId(`settings-tab-${UserTab.Security}`)).toBeTruthy(); - }); - it("does not render sidebar and security/access tab when feature is off", () => { - render(getComponent()); - - expect(screen.queryByText("Sidebar")).toBeNull(); - expect(screen.queryByText("Access")).toBeNull(); }); }); diff --git a/test/components/views/dialogs/__snapshots__/RoomSettingsDialog-test.tsx.snap b/test/components/views/dialogs/__snapshots__/RoomSettingsDialog-test.tsx.snap index c08bcffae45..6c148400d88 100644 --- a/test/components/views/dialogs/__snapshots__/RoomSettingsDialog-test.tsx.snap +++ b/test/components/views/dialogs/__snapshots__/RoomSettingsDialog-test.tsx.snap @@ -20,6 +20,24 @@ NodeList [ General
  • , + ,
  • , + , + ,
  • ", () => { it("should reset back to custom value when custom input is blurred blank", async () => { @@ -98,20 +97,4 @@ describe("", () => { deferred.reject("Some error"); await screen.findByDisplayValue(25); }); - it("should render custom value choice when feature is on", async () => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); - - const fn = jest.fn(); - render(); - - expect(await screen.queryByText("Custom level")).not.toBeNull(); - }); - it("should not render custom value choice when feature is off", async () => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); - - const fn = jest.fn(); - render(); - - expect(await screen.queryByText("Custom level")).toBeNull(); - }); }); diff --git a/test/components/views/messages/ReactionsRow-test.tsx b/test/components/views/messages/ReactionsRow-test.tsx deleted file mode 100644 index 3fde40c8a76..00000000000 --- a/test/components/views/messages/ReactionsRow-test.tsx +++ /dev/null @@ -1,99 +0,0 @@ -/* - Copyright 2024 Verji Tech AS. All rights reserved. - Unauthorized copying or distribution of this file, via any medium, is strictly prohibited. -*/ - -import React from "react"; -import { render, screen } from "@testing-library/react"; -import { - CustomComponentLifecycle, - CustomComponentOpts, -} from "@matrix-org/react-sdk-module-api/lib/lifecycles/CustomComponentLifecycle"; -import { - MatrixEvent, - Relations, - RelationsEvent, - EventType, - Room, - RelationType, - M_BEACON, - MatrixClient, -} from "matrix-js-sdk/src/matrix"; - -import ReactionsRow from "../../../../src/components/views/messages/ReactionsRow"; -import { createMessageEventContent } from "../../../test-utils/events"; -import { getMockClientWithEventEmitter } from "../../../test-utils"; -import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; -import { ModuleRunner } from "../../../../src/modules/ModuleRunner"; - -describe("ReactionsRow", () => { - const eventContent = createMessageEventContent("hello"); - - const roomId = "myRoomId"; - const mockClient = getMockClientWithEventEmitter({ - mxcUrlToHttp: jest.fn().mockReturnValue("https://not.a.real.url"), - getRoom: jest.fn(), - }); - const userId = "@alice:server"; - const room = new Room(roomId, mockClient, userId); - - const mxEvent = new MatrixEvent({ type: EventType.RoomMessage, content: eventContent }); - const reactions = new Relations(RelationType.Reference, M_BEACON.name, room); - - const mockGetSortedAnnotationsByKey = jest.spyOn(reactions, "getSortedAnnotationsByKey"); - const mockContent = "mockContent"; - const mockEvents = new Set([ - { - getSender: () => "mockSender1", - isRedacted: () => false, - getRelation: () => ({ key: mockContent }), - }, - ]) as never as RelationsEvent[]; - - mockGetSortedAnnotationsByKey.mockReturnValue([[mockContent, mockEvents as never]]); - - const renderComp = () => { - render( - - - ); - , - ); - }; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it("should render", () => { - renderComp(); - expect(screen.getByText(mockContent)).toBeDefined(); - }); - - describe("wrap the ReactionsRow with a React.Fragment", () => { - it("should wrap the ReactionsRow with a React.Fragment", () => { - jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts) => { - if (lifecycleEvent === CustomComponentLifecycle.ReactionsRow) { - (opts as CustomComponentOpts).CustomComponent = ({ children }) => { - return ( - <> -
    Header
    -
    {children}
    -
    Footer
    - - ); - }; - } - }); - - renderComp(); - expect(screen.getByTestId("wrapper-header")).toBeDefined(); - expect(screen.getByTestId("wrapper-ReactionsRow")).toBeDefined(); - expect(screen.getByTestId("wrapper-footer")).toBeDefined(); - expect(screen.getByTestId("wrapper-header").nextSibling).toBe(screen.getByTestId("wrapper-ReactionsRow")); - expect(screen.getByTestId("wrapper-ReactionsRow").nextSibling).toBe(screen.getByTestId("wrapper-footer")); - }); - }); -}); diff --git a/test/components/views/right_panel/RoomSummaryCard-test.tsx b/test/components/views/right_panel/RoomSummaryCard-test.tsx index c6c6c794a6d..b4288dc3577 100644 --- a/test/components/views/right_panel/RoomSummaryCard-test.tsx +++ b/test/components/views/right_panel/RoomSummaryCard-test.tsx @@ -37,13 +37,8 @@ import { _t } from "../../../../src/languageHandler"; import SettingsStore from "../../../../src/settings/SettingsStore"; import { tagRoom } from "../../../../src/utils/room/tagRoom"; import { DefaultTagID } from "../../../../src/stores/room-list/models"; -import { UIFeature } from "../../../../src/settings/UIFeature"; -import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents"; jest.mock("../../../../src/utils/room/tagRoom"); -jest.mock("../../../../src/customisations/helpers/UIComponents", () => ({ - shouldShowComponent: jest.fn(), -})); describe("", () => { const userId = "@alice:domain.org"; @@ -101,12 +96,6 @@ describe("", () => { mockClient.getRoom.mockReturnValue(room); jest.spyOn(room, "isElementVideoRoom").mockRestore(); jest.spyOn(room, "isCallRoom").mockRestore(); - - mocked(shouldShowComponent).mockReturnValue(true); - - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - return true; - }); }); afterEach(() => { @@ -223,67 +212,6 @@ describe("", () => { ); }); - it("renders 'add widgets, bridges..' option when UIFeature is enabled", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - if (setting === UIFeature.Widgets) return true; - return true; - }); - const { getByText } = getComponent(); - - expect(getByText("Add widgets, bridges & bots")).toBeInTheDocument(); - expect(screen.queryAllByText("Add widgets, bridges & bots")).toBeTruthy(); - }); - it("do not render 'add widgets, bridges..' option when UIFeature is false", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - if (setting === UIFeature.Widgets) return false; - return true; - }); - - getComponent(); - - expect(screen.queryByText("Add widgets, bridges & bots")).toBeFalsy(); - }); - it("do render 'Files' option when UIFeature is true", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - if (setting === UIFeature.RoomSummaryFilesOption) return true; - return true; - }); - const { getByText } = getComponent(); - - expect(getByText("Files")).toBeInTheDocument(); - expect(screen.queryByText(_t("right_panel|files_button"))).toBeTruthy(); - }); - it("does not render 'Files' option when UIFeature is false", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - if (setting === UIFeature.RoomSummaryFilesOption) return false; - return true; - }); - getComponent(); - - expect(screen.queryByText("Files")).toBeFalsy(); - expect(screen.queryByText(_t("right_panel|files_button"))).toBeFalsy(); - }); - it("does not render 'Copy link' option when UIFeature is false", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - if (setting === UIFeature.RoomSummaryCopyLink) return false; - return true; - }); - getComponent(); - - expect(screen.queryByText("Copy link")).toBeFalsy(); - expect(screen.queryByText(_t("action|copy_link"))).toBeFalsy(); - }); - it("does not render 'Copy link' option when UIFeature is true", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => { - if (setting === UIFeature.RoomSummaryCopyLink) return true; - return true; - }); - const { getByText } = getComponent(); - - expect(getByText("Copy link")).toBeInTheDocument(); - expect(screen.queryByText(_t("action|copy_link"))).toBeTruthy(); - }); - describe("pinning", () => { it("renders pins options when pinning feature is enabled", () => { mocked(settingsHooks.useFeatureEnabled).mockImplementation((feature) => feature === "feature_pinning"); @@ -389,22 +317,4 @@ describe("", () => { expect(screen.queryByText("Public room")).toBeInTheDocument(); }); }); - - describe("UIFeature.showAddWidgetsInRoomInfo", () => { - it("shows the add widgets button when enabled", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((val) => - val === UIFeature.ShowAddWidgetsInRoomInfo ? true : "default", - ); - const { baseElement } = getComponent(); - expect(baseElement.innerHTML).toContain("Add widgets"); - }); - - it("does not show the add widgets button when disabled", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((val) => - val === UIFeature.ShowAddWidgetsInRoomInfo ? false : "default", - ); - const { baseElement } = getComponent(); - expect(baseElement.innerHTML).not.toContain("Add widgets"); - }); - }); }); diff --git a/test/components/views/right_panel/UserInfo-test.tsx b/test/components/views/right_panel/UserInfo-test.tsx index 1169506a012..1c9e375e04b 100644 --- a/test/components/views/right_panel/UserInfo-test.tsx +++ b/test/components/views/right_panel/UserInfo-test.tsx @@ -63,8 +63,7 @@ import { DirectoryMember, startDmOnFirstMessage } from "../../../../src/utils/di import { clearAllModals, flushPromises } from "../../../test-utils"; import ErrorDialog from "../../../../src/components/views/dialogs/ErrorDialog"; import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents"; -import { UIComponent, UIFeature } from "../../../../src/settings/UIFeature"; -import SettingsStore from "../../../../src/settings/SettingsStore"; +import { UIComponent } from "../../../../src/settings/UIFeature"; jest.mock("../../../../src/utils/direct-messages", () => ({ ...jest.requireActual("../../../../src/utils/direct-messages"), @@ -177,7 +176,6 @@ beforeEach(() => { jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient); jest.spyOn(MatrixClientPeg, "safeGet").mockReturnValue(mockClient); - jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); }); describe("", () => { @@ -343,18 +341,6 @@ describe("", () => { screen.getByRole("button", { name: "Message" }); }); - it("does not renders the message button when feature is false", () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { - if (name == UIFeature.ShowSendMessageToUserLink) return false; - }); - render( - - - , - ); - - expect(screen.queryByText("button")).toBeNull(); - }); it("hides the message button if the visibility customisation hides all create room features", () => { mocked(shouldShowComponent).withImplementation( @@ -845,15 +831,7 @@ describe("", () => { inviteSpy.mockRestore(); }); - it("does not show share user button when UIFeature is false", () => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); - - renderComponent(); - expect(screen.queryByText("share link to user")).not.toBeInTheDocument(); - }); - it("shows share user button when UIFeature is true", () => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); - + it("always shows share user button", () => { renderComponent(); expect(screen.getByRole("button", { name: /share link to user/i })).toBeInTheDocument(); }); @@ -1412,16 +1390,7 @@ describe("", () => { `); }); - it("does not show redact button when UIFeature.UserInfoRedactButton is false", () => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); - - renderComponent(); - expect(screen.queryByText("remove recent messages")).not.toBeInTheDocument(); - }); - it("returns kick, redact messages, ban buttons if conditions met", () => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); - const mockMeMember = new RoomMember(mockRoom.roomId, "arbitraryId"); mockMeMember.powerLevel = 51; // defaults to 50 mockRoom.getMember.mockReturnValueOnce(mockMeMember); diff --git a/test/components/views/right_panel/__snapshots__/RoomSummaryCard-test.tsx.snap b/test/components/views/right_panel/__snapshots__/RoomSummaryCard-test.tsx.snap index 69113facf92..784be90168e 100644 --- a/test/components/views/right_panel/__snapshots__/RoomSummaryCard-test.tsx.snap +++ b/test/components/views/right_panel/__snapshots__/RoomSummaryCard-test.tsx.snap @@ -1,402 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` UIFeature.showAddWidgetsInRoomInfo shows the add widgets button when enabled 1`] = ` - -
    -
    -
    - -
    -
    -
    - - ! - -

    - !room:domain.org -

    -
    -
    - -
    - Not encrypted - -
    -
    - -
    -
    -
  • {_t("widget|shared_data_name")}
  • +
  • {_t("widget|shared_data_avatar")}
  • +
  • {_t("widget|shared_data_mxid")}
  • +
  • {_t("widget|shared_data_device_id")}
  • +
  • {_t("widget|shared_data_theme")}
  • +
  • {_t("widget|shared_data_lang")}
  • +
  • {_t("widget|shared_data_url", { brand })}
  • +
  • {_t("widget|shared_data_room_id")}
  • +
  • {_t("widget|shared_data_widget_id")}
  • + + } > - - +
    + +
    + ); // Due to i18n limitations, we can't dedupe the code for variables in these two messages. diff --git a/src/components/views/elements/Field.tsx b/src/components/views/elements/Field.tsx index f76b945712b..d60af8025d9 100644 --- a/src/components/views/elements/Field.tsx +++ b/src/components/views/elements/Field.tsx @@ -14,12 +14,20 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes, RefObject, createRef } from "react"; +import React, { + InputHTMLAttributes, + SelectHTMLAttributes, + TextareaHTMLAttributes, + RefObject, + createRef, + KeyboardEvent, +} from "react"; import classNames from "classnames"; import { debounce } from "lodash"; import { IFieldState, IValidationResult } from "./Validation"; import Tooltip from "./Tooltip"; +import { Key } from "../../../Keyboard"; // Invoke validation from user input (when typing, etc.) at most once every N ms. const VALIDATION_THROTTLE_MS = 200; @@ -232,6 +240,18 @@ export default class Field extends React.PureComponent { return this.props.inputRef ?? this._inputRef; } + private onKeyDown = (evt: KeyboardEvent): void => { + // If the tooltip is displayed to show a feedback and Escape is pressed + // The tooltip is hided + if (this.state.feedbackVisible && evt.key === Key.ESCAPE) { + evt.preventDefault(); + evt.stopPropagation(); + this.setState({ + feedbackVisible: false, + }); + } + }; + public render(): React.ReactNode { /* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */ const { @@ -318,7 +338,7 @@ export default class Field extends React.PureComponent { }); return ( -
    +
    {prefixContainer} {fieldInput} diff --git a/src/components/views/elements/RoomTopic.tsx b/src/components/views/elements/RoomTopic.tsx index f926ef5cf46..9647188304c 100644 --- a/src/components/views/elements/RoomTopic.tsx +++ b/src/components/views/elements/RoomTopic.tsx @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useCallback, useContext, useRef } from "react"; +import React, { useCallback, useContext, useState } from "react"; import { Room, EventType } from "matrix-js-sdk/src/matrix"; import classNames from "classnames"; +import { Tooltip } from "@vector-im/compound-web"; import { useTopic } from "../../../hooks/room/useTopic"; -import { Alignment } from "./Tooltip"; import { _t } from "../../../languageHandler"; import dis from "../../../dispatcher/dispatcher"; import { Action } from "../../../dispatcher/actions"; @@ -28,7 +28,6 @@ import InfoDialog from "../dialogs/InfoDialog"; import { useDispatcher } from "../../../hooks/useDispatcher"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import AccessibleButton from "./AccessibleButton"; -import TooltipTarget from "./TooltipTarget"; import { Linkify, topicToHtml } from "../../../HtmlUtils"; import { tryTransformPermalinkToLocalHref } from "../../../utils/permalinks/Permalinks"; @@ -49,10 +48,10 @@ export function onRoomTopicLinkClick(e: React.MouseEvent): void { export default function RoomTopic({ room, className, ...props }: IProps): JSX.Element { const client = useContext(MatrixClientContext); - const ref = useRef(null); + const [disableTooltip, setDisableTooltip] = useState(false); const topic = useTopic(room); - const body = topicToHtml(topic?.text, topic?.html, ref); + const body = topicToHtml(topic?.text, topic?.html); const onClick = useCallback( (e: React.MouseEvent) => { @@ -70,14 +69,14 @@ export default function RoomTopic({ room, className, ...props }: IProps): JSX.El [props], ); - const ignoreHover = (ev: React.MouseEvent): boolean => { - return (ev.target as HTMLElement).tagName.toUpperCase() === "A"; + const onHover = (ev: React.MouseEvent | React.FocusEvent): void => { + setDisableTooltip((ev.target as HTMLElement).tagName.toUpperCase() === "A"); }; useDispatcher(dis, (payload) => { if (payload.action === Action.ShowRoomTopic) { const canSetTopic = room.currentState.maySendStateEvent(EventType.RoomTopic, client.getSafeUserId()); - const body = topicToHtml(topic?.text, topic?.html, ref, true); + const body = topicToHtml(topic?.text, topic?.html, undefined, true); const modal = Modal.createDialog(InfoDialog, { title: room.name, @@ -115,18 +114,24 @@ export default function RoomTopic({ room, className, ...props }: IProps): JSX.El } }); + // Do not render the tooltip if the topic is empty + // We still need to have a div for the header buttons to be displayed correctly + if (!body) return
    ; + return ( - - {body} - + +
    + {body} +
    +
    ); } diff --git a/src/components/views/elements/Tooltip.tsx b/src/components/views/elements/Tooltip.tsx index aafa28b59a7..fdba5f6f5cb 100644 --- a/src/components/views/elements/Tooltip.tsx +++ b/src/components/views/elements/Tooltip.tsx @@ -57,6 +57,9 @@ export interface ITooltipProps { type State = Partial>; +/** + * @deprecated Use [compound tooltip](https://element-hq.github.io/compound-web/?path=/docs/tooltip--docs) instead + */ export default class Tooltip extends React.PureComponent { private static container: HTMLElement; private parent: Element | null = null; diff --git a/src/components/views/elements/TooltipTarget.tsx b/src/components/views/elements/TooltipTarget.tsx deleted file mode 100644 index 89de915b456..00000000000 --- a/src/components/views/elements/TooltipTarget.tsx +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2021 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React, { forwardRef, HTMLAttributes, useRef } from "react"; -import { randomString } from "matrix-js-sdk/src/randomstring"; - -import useFocus from "../../../hooks/useFocus"; -import useHover from "../../../hooks/useHover"; -import Tooltip, { ITooltipProps } from "./Tooltip"; - -interface IProps - extends HTMLAttributes, - Omit { - tooltipTargetClassName?: string; - ignoreHover?: (ev: React.MouseEvent) => boolean; -} - -/** - * Generic tooltip target element that handles tooltip visibility state - * and displays children - */ -const TooltipTarget = forwardRef( - ( - { - children, - tooltipTargetClassName, - // tooltip pass through props - className, - id, - label, - alignment, - tooltipClassName, - maxParentWidth, - ignoreHover, - ...rest - }, - ref, - ) => { - const idRef = useRef("mx_TooltipTarget_" + randomString(8)); - // Use generated ID if one is not passed - if (id === undefined) { - id = idRef.current; - } - - const [isFocused, focusProps] = useFocus(); - const [isHovering, hoverProps] = useHover(ignoreHover || (() => false)); - - // No need to fill up the DOM with hidden tooltip elements. Only add the - // tooltip when we're hovering over the item (performance) - const tooltip = (isFocused || isHovering) && ( - - ); - - return ( -
    - {children} - {tooltip} -
    - ); - }, -); - -export default TooltipTarget; diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 29c1c97e1a5..eedf5a60465 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -17,6 +17,7 @@ limitations under the License. import React from "react"; import { MatrixEvent, ClientEvent, ClientEventHandlerMap } from "matrix-js-sdk/src/matrix"; import { randomString } from "matrix-js-sdk/src/randomstring"; +import { Tooltip } from "@vector-im/compound-web"; import { _t } from "../../../languageHandler"; import Modal from "../../../Modal"; @@ -27,8 +28,6 @@ import { isSelfLocation, } from "../../../utils/location"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import TooltipTarget from "../elements/TooltipTarget"; -import { Alignment } from "../elements/Tooltip"; import { SmartMarker, Map, LocationViewDialog } from "../location"; import { IBodyProps } from "./IBodyProps"; import { createReconnectedListener } from "../../../utils/connection"; @@ -126,7 +125,7 @@ export const LocationBodyFallbackContent: React.FC<{ event: MatrixEvent; error: interface LocationBodyContentProps { mxEvent: MatrixEvent; mapId: string; - tooltip?: string; + tooltip: string; onError: (error: Error) => void; onClick?: () => void; } @@ -156,13 +155,9 @@ export const LocationBodyContent: React.FC = ({ return (
    - {tooltip ? ( - - {mapElement} - - ) : ( - mapElement - )} + +
    {mapElement}
    +
    ); }; diff --git a/src/components/views/messages/ReactionsRowButton.tsx b/src/components/views/messages/ReactionsRowButton.tsx index 2737212d33b..1dbd1bd7bf1 100644 --- a/src/components/views/messages/ReactionsRowButton.tsx +++ b/src/components/views/messages/ReactionsRowButton.tsx @@ -44,20 +44,10 @@ export interface IProps { customReactionImagesEnabled?: boolean; } -interface IState { - tooltipRendered: boolean; - tooltipVisible: boolean; -} - -export default class ReactionsRowButton extends React.PureComponent { +export default class ReactionsRowButton extends React.PureComponent { public static contextType = MatrixClientContext; public context!: React.ContextType; - public state = { - tooltipRendered: false, - tooltipVisible: false, - }; - public onClick = (): void => { const { mxEvent, myReactionEvent, content } = this.props; if (myReactionEvent) { @@ -74,21 +64,6 @@ export default class ReactionsRowButton extends React.PureComponent { - this.setState({ - // To avoid littering the DOM with a tooltip for every reaction, - // only render it on first use. - tooltipRendered: true, - tooltipVisible: true, - }); - }; - - public onMouseLeave = (): void => { - this.setState({ - tooltipVisible: false, - }); - }; - public render(): React.ReactNode { const { mxEvent, content, count, reactionEvents, myReactionEvent } = this.props; @@ -97,19 +72,6 @@ export default class ReactionsRowButton extends React.PureComponent - ); - } - const room = this.context.getRoom(mxEvent.getRoomId()); let label: string | undefined; let customReactionName: string | undefined; @@ -156,20 +118,24 @@ export default class ReactionsRowButton extends React.PureComponent - {reactionContent} - - {tooltip} - + + {reactionContent} + + + ); } } diff --git a/src/components/views/messages/ReactionsRowButtonTooltip.tsx b/src/components/views/messages/ReactionsRowButtonTooltip.tsx index f2a3d26109e..5b4db10ed6b 100644 --- a/src/components/views/messages/ReactionsRowButtonTooltip.tsx +++ b/src/components/views/messages/ReactionsRowButtonTooltip.tsx @@ -14,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; +import React, { PropsWithChildren } from "react"; import { MatrixEvent } from "matrix-js-sdk/src/matrix"; +import { Tooltip } from "@vector-im/compound-web"; import { unicodeToShortcode } from "../../../HtmlUtils"; import { _t } from "../../../languageHandler"; import { formatList } from "../../../utils/FormattingUtils"; -import Tooltip from "../elements/Tooltip"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import { REACTION_SHORTCODE_KEY } from "./ReactionsRow"; interface IProps { @@ -30,20 +30,18 @@ interface IProps { content: string; // A list of Matrix reaction events for this key reactionEvents: MatrixEvent[]; - visible: boolean; // Whether to render custom image reactions customReactionImagesEnabled?: boolean; } -export default class ReactionsRowButtonTooltip extends React.PureComponent { +export default class ReactionsRowButtonTooltip extends React.PureComponent> { public static contextType = MatrixClientContext; public context!: React.ContextType; public render(): React.ReactNode { - const { content, reactionEvents, mxEvent, visible } = this.props; + const { content, reactionEvents, mxEvent, children } = this.props; const room = this.context.getRoom(mxEvent.getRoomId()); - let tooltipLabel: JSX.Element | undefined; if (room) { const senders: string[] = []; let customReactionName: string | undefined; @@ -57,34 +55,16 @@ export default class ReactionsRowButtonTooltip extends React.PureComponent - {_t( - "timeline|reactions|tooltip", - { - shortName, - }, - { - reactors: () => { - return
    {formatList(senders, 6)}
    ; - }, - reactedWith: (sub) => { - if (!shortName) { - return null; - } - return
    {sub}
    ; - }, - }, - )} -
    - ); - } + const formattedSenders = formatList(senders, 6); + const caption = shortName ? _t("timeline|reactions|tooltip_caption", { shortName }) : undefined; - let tooltip: JSX.Element | undefined; - if (tooltipLabel) { - tooltip = ; + return ( + + {children} + + ); } - return tooltip; + return children; } } diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index dbc6acb29be..d9839252f90 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -43,7 +43,6 @@ import DMRoomMap from "../../../utils/DMRoomMap"; import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; import SdkConfig from "../../../SdkConfig"; import MultiInviter from "../../../utils/MultiInviter"; -import { MatrixClientPeg } from "../../../MatrixClientPeg"; import E2EIcon from "../rooms/E2EIcon"; import { useTypedEventEmitter } from "../../../hooks/useEventEmitter"; import { textualPowerLevel } from "../../../Roles"; @@ -1413,8 +1412,7 @@ const BasicUserInfo: React.FC<{ // We don't need a perfect check here, just something to pass as "probably not our homeserver". If // someone does figure out how to bypass this check the worst that happens is an error. - // FIXME this should be using cli instead of MatrixClientPeg.matrixClient - if (isSynapseAdmin && member.userId.endsWith(`:${MatrixClientPeg.getHomeserverName()}`)) { + if (isSynapseAdmin && member.userId.endsWith(`:${cli.getDomain()}`)) { synapseDeactivateButton = ( { - private tooltipId = `mx_MessageComposer_${Math.random()}`; private dispatcherRef?: string; private messageComposerInput = createRef(); private voiceRecordingButton = createRef(); @@ -568,12 +567,9 @@ export class MessageComposer extends React.Component { } let recordingTooltip: JSX.Element | undefined; - if (this.state.recordingTimeLeftSeconds) { - const secondsLeft = Math.round(this.state.recordingTimeLeftSeconds); - recordingTooltip = ( - - ); - } + + const isTooltipOpen = Boolean(this.state.recordingTimeLeftSeconds); + const secondsLeft = this.state.recordingTimeLeftSeconds ? Math.round(this.state.recordingTimeLeftSeconds) : 0; const threadId = this.props.relation?.rel_type === THREAD_RELATION_TYPE.name ? this.props.relation.event_id : null; @@ -599,68 +595,66 @@ export class MessageComposer extends React.Component { }); return ( -
    - {recordingTooltip} -
    - -
    - {e2eIcon} - {composer} -
    - {controls} - {canSendMessages && ( - { - setUpVoiceBroadcastPreRecording( - this.props.room, - MatrixClientPeg.safeGet(), - SdkContextClass.instance.voiceBroadcastPlaybacksStore, - SdkContextClass.instance.voiceBroadcastRecordingsStore, - SdkContextClass.instance.voiceBroadcastPreRecordingStore, - ); - this.toggleButtonMenu(); - }} - /> - )} - {showSendButton && ( - - )} + +
    + {recordingTooltip} +
    + +
    + {e2eIcon} + {composer} +
    + {controls} + {canSendMessages && ( + { + setUpVoiceBroadcastPreRecording( + this.props.room, + MatrixClientPeg.safeGet(), + SdkContextClass.instance.voiceBroadcastPlaybacksStore, + SdkContextClass.instance.voiceBroadcastRecordingsStore, + SdkContextClass.instance.voiceBroadcastPreRecordingStore, + ); + this.toggleButtonMenu(); + }} + /> + )} + {showSendButton && ( + + )} +
    -
    + ); } } diff --git a/src/components/views/rooms/ReadReceiptGroup.tsx b/src/components/views/rooms/ReadReceiptGroup.tsx index 3629af58148..c9d00a4e699 100644 --- a/src/components/views/rooms/ReadReceiptGroup.tsx +++ b/src/components/views/rooms/ReadReceiptGroup.tsx @@ -16,18 +16,17 @@ limitations under the License. import React, { PropsWithChildren } from "react"; import { User } from "matrix-js-sdk/src/matrix"; +import { Tooltip } from "@vector-im/compound-web"; import ReadReceiptMarker, { IReadReceiptInfo } from "./ReadReceiptMarker"; import { IReadReceiptProps } from "./EventTile"; import AccessibleButton from "../elements/AccessibleButton"; import MemberAvatar from "../avatars/MemberAvatar"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; -import { Alignment } from "../elements/Tooltip"; import { formatDate } from "../../../DateUtils"; import { Action } from "../../../dispatcher/actions"; import dis from "../../../dispatcher/dispatcher"; import ContextMenu, { aboveLeftOf, MenuItem, useContextMenu } from "../../structures/ContextMenu"; -import { useTooltip } from "../../../utils/useTooltip"; import { _t } from "../../../languageHandler"; import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex"; import { formatList } from "../../../utils/FormattingUtils"; @@ -87,18 +86,6 @@ export function ReadReceiptGroup({ const tooltipMembers: string[] = readReceipts.map((it) => it.roomMember?.name ?? it.userId); const tooltipText = readReceiptTooltip(tooltipMembers, maxAvatars); - const [{ showTooltip, hideTooltip }, tooltip] = useTooltip({ - label: ( - <> -
    - {_t("timeline|read_receipt_title", { count: readReceipts.length })} -
    -
    {tooltipText}
    - - ), - alignment: Alignment.TopRight, - }); - // return early if there are no read receipts if (readReceipts.length === 0) { // We currently must include `mx_ReadReceiptGroup_container` in @@ -185,34 +172,35 @@ export function ReadReceiptGroup({ return (
    -
    - - {remText} - +
    + - {avatars} - - - {tooltip} - {contextMenu} -
    + {remText} + + {avatars} + +
    + {contextMenu} +
    +
    ); } @@ -222,60 +210,48 @@ interface ReadReceiptPersonProps extends IReadReceiptProps { onAfterClick?: () => void; } -function ReadReceiptPerson({ +// Export for testing +export function ReadReceiptPerson({ userId, roomMember, ts, isTwelveHour, onAfterClick, }: ReadReceiptPersonProps): JSX.Element { - const [{ showTooltip, hideTooltip }, tooltip] = useTooltip({ - alignment: Alignment.Top, - tooltipClassName: "mx_ReadReceiptGroup_person--tooltip", - label: ( - <> -
    {roomMember?.rawDisplayName ?? userId}
    -
    {userId}
    - - ), - }); - return ( - { - dis.dispatch({ - action: Action.ViewUser, - // XXX: We should be using a real member object and not assuming what the receiver wants. - // The ViewUser action leads to the RightPanelStore, and RightPanelStoreIPanelState defines the - // member property of IRightPanelCardState as `RoomMember | User`, so we’re fine for now, but we - // should definitely clean this up later - member: roomMember ?? ({ userId } as User), - push: false, - }); - onAfterClick?.(); - }} - onMouseOver={showTooltip} - onMouseLeave={hideTooltip} - onFocus={showTooltip} - onBlur={hideTooltip} - onWheel={hideTooltip} - > -
    @@ -121,10 +118,7 @@ exports[`RoomView for a local room in state ERROR should match the snapshot 1`]
    @@ -284,10 +278,7 @@ exports[`RoomView for a local room in state NEW should match the snapshot 1`] =
    @@ -531,10 +522,7 @@ exports[`RoomView for a local room in state NEW that is encrypted should match t
    diff --git a/test/components/views/dialogs/SpotlightDialog-test.tsx b/test/components/views/dialogs/SpotlightDialog-test.tsx index 5bf1029bc9e..f8fe3c00a7d 100644 --- a/test/components/views/dialogs/SpotlightDialog-test.tsx +++ b/test/components/views/dialogs/SpotlightDialog-test.tsx @@ -82,8 +82,8 @@ function mockClient({ }: MockClientOptions = {}): MatrixClient { stubClient(); const cli = MatrixClientPeg.safeGet(); - MatrixClientPeg.getHomeserverName = jest.fn(() => homeserver); cli.getUserId = jest.fn(() => userId); + cli.getDomain = jest.fn(() => homeserver); cli.getHomeserverUrl = jest.fn(() => homeserver); cli.getThirdpartyProtocols = jest.fn(() => Promise.resolve(thirdPartyProtocols)); cli.publicRooms = jest.fn((options) => { diff --git a/test/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx b/test/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx index 1412074ed9d..06b13f1df7a 100644 --- a/test/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx +++ b/test/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx @@ -18,7 +18,7 @@ import { render, RenderResult, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import React from "react"; import { mocked, MockedObject } from "jest-mock"; -import { CryptoApi, MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix"; +import { Crypto, MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix"; import { defer, IDeferred, sleep } from "matrix-js-sdk/src/utils"; import { BackupTrustInfo, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api"; @@ -35,7 +35,7 @@ import RestoreKeyBackupDialog from "../../../../../src/components/views/dialogs/ describe("CreateSecretStorageDialog", () => { let mockClient: MockedObject; - let mockCrypto: MockedObject; + let mockCrypto: MockedObject; beforeEach(() => { mockClient = getMockClientWithEventEmitter({ diff --git a/test/components/views/dialogs/security/ExportE2eKeysDialog-test.tsx b/test/components/views/dialogs/security/ExportE2eKeysDialog-test.tsx index 0436fb2bf25..c4a5ef1ee1b 100644 --- a/test/components/views/dialogs/security/ExportE2eKeysDialog-test.tsx +++ b/test/components/views/dialogs/security/ExportE2eKeysDialog-test.tsx @@ -17,7 +17,7 @@ limitations under the License. import React from "react"; import { screen, fireEvent, render, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { CryptoApi, IMegolmSessionData } from "matrix-js-sdk/src/matrix"; +import { Crypto, IMegolmSessionData } from "matrix-js-sdk/src/matrix"; import * as MegolmExportEncryption from "../../../../../src/utils/MegolmExportEncryption"; import ExportE2eKeysDialog from "../../../../../src/async-components/views/dialogs/security/ExportE2eKeysDialog"; @@ -70,7 +70,7 @@ describe("ExportE2eKeysDialog", () => { cli.getCrypto = () => { return { exportRoomKeysAsJson, - } as unknown as CryptoApi; + } as unknown as Crypto.CryptoApi; }; // Mock the result of encrypting the sessions. If we don't do this, the diff --git a/test/components/views/dialogs/security/ImportE2eKeysDialog-test.tsx b/test/components/views/dialogs/security/ImportE2eKeysDialog-test.tsx index af7b85b0c2d..f1199660301 100644 --- a/test/components/views/dialogs/security/ImportE2eKeysDialog-test.tsx +++ b/test/components/views/dialogs/security/ImportE2eKeysDialog-test.tsx @@ -17,7 +17,7 @@ limitations under the License. import React from "react"; import { fireEvent, render, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { CryptoApi } from "matrix-js-sdk/src/matrix"; +import { Crypto } from "matrix-js-sdk/src/matrix"; import ImportE2eKeysDialog from "../../../../../src/async-components/views/dialogs/security/ImportE2eKeysDialog"; import * as MegolmExportEncryption from "../../../../../src/utils/MegolmExportEncryption"; @@ -75,7 +75,7 @@ describe("ImportE2eKeysDialog", () => { cli.getCrypto = () => { return { importRoomKeysAsJson, - } as unknown as CryptoApi; + } as unknown as Crypto.CryptoApi; }; // Mock the result of decrypting the sessions, to avoid needing to diff --git a/test/components/views/elements/Field-test.tsx b/test/components/views/elements/Field-test.tsx index ce826282aca..7cb3074927a 100644 --- a/test/components/views/elements/Field-test.tsx +++ b/test/components/views/elements/Field-test.tsx @@ -69,6 +69,10 @@ describe("Field", () => { // Expect 'alert' role expect(screen.queryByRole("alert")).toBeInTheDocument(); + + // Close the feedback is Escape is pressed + fireEvent.keyDown(screen.getByRole("textbox"), { key: "Escape" }); + expect(screen.queryByRole("alert")).toBeNull(); }); it("Should mark the feedback as status if valid", async () => { @@ -87,6 +91,10 @@ describe("Field", () => { // Expect 'status' role expect(screen.queryByRole("status")).toBeInTheDocument(); + + // Close the feedback is Escape is pressed + fireEvent.keyDown(screen.getByRole("textbox"), { key: "Escape" }); + expect(screen.queryByRole("status")).toBeNull(); }); it("Should mark the feedback as tooltip if custom tooltip set", async () => { @@ -106,6 +114,10 @@ describe("Field", () => { // Expect 'tooltip' role expect(screen.queryByRole("tooltip")).toBeInTheDocument(); + + // Close the feedback is Escape is pressed + fireEvent.keyDown(screen.getByRole("textbox"), { key: "Escape" }); + expect(screen.queryByRole("tooltip")).toBeNull(); }); }); }); diff --git a/test/components/views/elements/RoomTopic-test.tsx b/test/components/views/elements/RoomTopic-test.tsx index dc05779794e..8e62bd641f4 100644 --- a/test/components/views/elements/RoomTopic-test.tsx +++ b/test/components/views/elements/RoomTopic-test.tsx @@ -16,7 +16,8 @@ limitations under the License. import React from "react"; import { Room } from "matrix-js-sdk/src/matrix"; -import { fireEvent, render, screen } from "@testing-library/react"; +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; import { mkEvent, stubClient } from "../../../test-utils"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; @@ -33,9 +34,12 @@ describe("", () => { window.location.href = originalHref; }); - function runClickTest(topic: string, clickText: string) { + /** + * Create a room with the given topic + * @param topic + */ + function createRoom(topic: string) { stubClient(); - const room = new Room("!pMBteVpcoJRdCJxDmn:matrix.org", MatrixClientPeg.safeGet(), "@alice:example.org"); const topicEvent = mkEvent({ type: "m.room.topic", @@ -45,11 +49,27 @@ describe("", () => { ts: 123, event: true, }); - room.addLiveEvents([topicEvent]); + return room; + } + + /** + * Create a room and render it + * @param topic + */ + const renderRoom = (topic: string) => { + const room = createRoom(topic); render(); + }; + /** + * Create a room and click on the given text + * @param topic + * @param clickText + */ + function runClickTest(topic: string, clickText: string) { + renderRoom(topic); fireEvent.click(screen.getByText(clickText)); } @@ -78,4 +98,18 @@ describe("", () => { expect(window.location.href).toEqual(expectedHref); expect(dis.fire).toHaveBeenCalledWith(Action.ShowRoomTopic); }); + + it("should open the tooltip when hovering a text", async () => { + const topic = "room topic"; + renderRoom(topic); + await userEvent.hover(screen.getByText(topic)); + await waitFor(() => expect(screen.getByRole("tooltip", { name: "Click to read topic" })).toBeInTheDocument()); + }); + + it("should not open the tooltip when hovering a link", async () => { + const topic = "https://matrix.org"; + renderRoom(topic); + await userEvent.hover(screen.getByText(topic)); + await waitFor(() => expect(screen.queryByRole("tooltip", { name: "Click to read topic" })).toBeNull()); + }); }); diff --git a/test/components/views/elements/TooltipTarget-test.tsx b/test/components/views/elements/TooltipTarget-test.tsx deleted file mode 100644 index 0823229a904..00000000000 --- a/test/components/views/elements/TooltipTarget-test.tsx +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright 2022 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React from "react"; -import { fireEvent, render } from "@testing-library/react"; - -import { Alignment } from "../../../../src/components/views/elements/Tooltip"; -import TooltipTarget from "../../../../src/components/views/elements/TooltipTarget"; - -describe("", () => { - const defaultProps = { - "tooltipTargetClassName": "test tooltipTargetClassName", - "className": "test className", - "tooltipClassName": "test tooltipClassName", - "label": "test label", - "alignment": Alignment.Left, - "id": "test id", - "data-testid": "test", - }; - - const getComponent = (props = {}) => { - const wrapper = render( - // wrap in element so renderIntoDocument can render functional component - - - child - - , - ); - return wrapper.getByTestId("test"); - }; - - const getVisibleTooltip = () => document.querySelector(".mx_Tooltip.mx_Tooltip_visible"); - - it("renders container", () => { - const component = getComponent(); - expect(component).toMatchSnapshot(); - expect(getVisibleTooltip()).toBeFalsy(); - }); - - const alignmentKeys = Object.keys(Alignment).filter((o: any) => isNaN(o)); - it.each(alignmentKeys)("displays %s aligned tooltip on mouseover", async (alignment: any) => { - const wrapper = getComponent({ alignment: Alignment[alignment] })!; - fireEvent.mouseOver(wrapper); - expect(getVisibleTooltip()).toMatchSnapshot(); - }); - - it("hides tooltip on mouseleave", () => { - const wrapper = getComponent()!; - fireEvent.mouseOver(wrapper); - expect(getVisibleTooltip()).toBeTruthy(); - fireEvent.mouseLeave(wrapper); - expect(getVisibleTooltip()).toBeFalsy(); - }); - - it("displays tooltip on focus", () => { - const wrapper = getComponent()!; - fireEvent.focus(wrapper); - expect(getVisibleTooltip()).toBeTruthy(); - }); - - it("hides tooltip on blur", async () => { - const wrapper = getComponent()!; - fireEvent.focus(wrapper); - expect(getVisibleTooltip()).toBeTruthy(); - fireEvent.blur(wrapper); - expect(getVisibleTooltip()).toBeFalsy(); - }); -}); diff --git a/test/components/views/elements/__snapshots__/AppTile-test.tsx.snap b/test/components/views/elements/__snapshots__/AppTile-test.tsx.snap index 8f362565472..b344e3cd58d 100644 --- a/test/components/views/elements/__snapshots__/AppTile-test.tsx.snap +++ b/test/components/views/elements/__snapshots__/AppTile-test.tsx.snap @@ -288,9 +288,7 @@ exports[`AppTile for a pinned widget should render permission request 1`] = ` Using this widget may share data
    displays Bottom aligned tooltip on mouseover 1`] = ` -