From d0383e3cd52882ed6c363f5e2800f2d61253616a Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Fri, 10 Nov 2023 11:26:30 +0000 Subject: [PATCH 01/13] Disable 'A room with an edit ... restart' because flaking on Rust --- cypress/e2e/read-receipts/editing-messages.spec.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cypress/e2e/read-receipts/editing-messages.spec.ts b/cypress/e2e/read-receipts/editing-messages.spec.ts index c5ccb77750..6ab2da349e 100644 --- a/cypress/e2e/read-receipts/editing-messages.spec.ts +++ b/cypress/e2e/read-receipts/editing-messages.spec.ts @@ -19,6 +19,7 @@ limitations under the License. /// import { HomeserverInstance } from "../../plugins/utils/homeserver"; +import { skipIfRustCrypto } from "../../support/util"; import { assertRead, assertReadThread, @@ -179,6 +180,10 @@ describe("Read receipts", () => { assertStillRead(room2); }); it("A room with an edit is still read after restart", () => { + // Flaky with rust crypto + // See https://github.com/vector-im/element-web/issues/26341 + skipIfRustCrypto(); + // Given a message is marked as read goTo(room2); receiveMessages(room2, ["Msg1"]); From c1a060bac6728a0d16ad21f32b53d357a482d4ae Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Fri, 10 Nov 2023 11:40:08 +0000 Subject: [PATCH 02/13] Disable everywhere since we saw another flake --- cypress/e2e/read-receipts/editing-messages.spec.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cypress/e2e/read-receipts/editing-messages.spec.ts b/cypress/e2e/read-receipts/editing-messages.spec.ts index 6ab2da349e..bbaa15d659 100644 --- a/cypress/e2e/read-receipts/editing-messages.spec.ts +++ b/cypress/e2e/read-receipts/editing-messages.spec.ts @@ -19,7 +19,6 @@ limitations under the License. /// import { HomeserverInstance } from "../../plugins/utils/homeserver"; -import { skipIfRustCrypto } from "../../support/util"; import { assertRead, assertReadThread, @@ -179,11 +178,8 @@ describe("Read receipts", () => { // Then the room remains read assertStillRead(room2); }); - it("A room with an edit is still read after restart", () => { - // Flaky with rust crypto - // See https://github.com/vector-im/element-web/issues/26341 - skipIfRustCrypto(); - + // XXX: fails because flaky: https://github.com/vector-im/element-web/issues/26341 + it.skip("A room with an edit is still read after restart", () => { // Given a message is marked as read goTo(room2); receiveMessages(room2, ["Msg1"]); From 8c759a965563629defd137f4b87b83e2275a2461 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Fri, 10 Nov 2023 15:31:54 +0000 Subject: [PATCH 03/13] Disable 'Looking in thread view to find old threads...' because of flakes --- cypress/e2e/read-receipts/high-level.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cypress/e2e/read-receipts/high-level.spec.ts b/cypress/e2e/read-receipts/high-level.spec.ts index 36f358f00d..2c49e1cfc9 100644 --- a/cypress/e2e/read-receipts/high-level.spec.ts +++ b/cypress/e2e/read-receipts/high-level.spec.ts @@ -303,7 +303,8 @@ describe("Read receipts", () => { assertUnreadThread("Root2"); assertUnreadThread("Root3"); }); - it("Looking in thread view to find old threads that were never read makes the room unread", () => { + // XXX: fails because flaky: https://github.com/vector-im/element-web/issues/26331 + it.skip("Looking in thread view to find old threads that were never read makes the room unread", () => { // Given lots of messages in threads that are unread goTo(room1); receiveMessages(room2, [ From 62f41f0961ce55f5b1785435a79cd085a403e25e Mon Sep 17 00:00:00 2001 From: Timo <16718859+toger5@users.noreply.github.com> Date: Fri, 10 Nov 2023 17:46:02 +0100 Subject: [PATCH 04/13] Add feature flag for disabling encryption in Element Call (#11837) * add feature flag for disabling encryption Signed-off-by: Timo K * prettier Signed-off-by: Timo K * Update src/i18n/strings/en_EN.json Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * add tests and make url flags explicit Signed-off-by: Timo K * remove unnecessary braces Signed-off-by: Timo K --------- Signed-off-by: Timo K Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- src/i18n/strings/en_EN.json | 1 + src/models/Call.ts | 8 +++++--- src/settings/Settings.tsx | 7 +++++++ test/models/Call-test.ts | 24 ++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 7ae2f7a70f..d5b76383b4 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1398,6 +1398,7 @@ "element_call_video_rooms": "Element Call video rooms", "experimental_description": "Feeling experimental? Try out our latest ideas in development. These features are not finalised; they may be unstable, may change, or may be dropped altogether. Learn more.", "experimental_section": "Early previews", + "feature_disable_call_per_sender_encryption": "Disable per-sender encryption for Element Call", "feature_wysiwyg_composer_description": "Use rich text instead of Markdown in the message composer.", "group_calls": "New group call experience", "group_developer": "Developer", diff --git a/src/models/Call.ts b/src/models/Call.ts index ecf1cbab66..9a841eb9d7 100644 --- a/src/models/Call.ts +++ b/src/models/Call.ts @@ -661,9 +661,11 @@ export class ElementCall extends Call { analyticsID, }); - if (client.isRoomEncrypted(roomId)) params.append("perParticipantE2EE", ""); - if (SettingsStore.getValue("fallbackICEServerAllowed")) params.append("allowIceFallback", ""); - if (SettingsStore.getValue("feature_allow_screen_share_only_mode")) params.append("allowVoipWithNoMedia", ""); + if (client.isRoomEncrypted(roomId) && !SettingsStore.getValue("feature_disable_call_per_sender_encryption")) + params.append("perParticipantE2EE", "true"); + if (SettingsStore.getValue("fallbackICEServerAllowed")) params.append("allowIceFallback", "true"); + if (SettingsStore.getValue("feature_allow_screen_share_only_mode")) + params.append("allowVoipWithNoMedia", "true"); // Set custom fonts if (SettingsStore.getValue("useSystemFont")) { diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 7f92f0413f..4f000f300c 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -404,6 +404,13 @@ export const SETTINGS: { [setting: string]: ISetting } = { controller: new ReloadOnChangeController(), default: false, }, + "feature_disable_call_per_sender_encryption": { + isFeature: true, + supportedLevels: LEVELS_FEATURE, + labsGroup: LabGroup.VoiceAndVideo, + displayName: _td("labs|feature_disable_call_per_sender_encryption"), + default: false, + }, "feature_allow_screen_share_only_mode": { isFeature: true, supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, diff --git a/test/models/Call-test.ts b/test/models/Call-test.ts index bd394e628b..cbf1df0ffa 100644 --- a/test/models/Call-test.ts +++ b/test/models/Call-test.ts @@ -925,6 +925,30 @@ describe("ElementCall", () => { call.destroy(); expect(destroyPersistentWidgetSpy).toHaveBeenCalled(); }); + + it("the perParticipantE2EE url flag is used in encrypted rooms while respecting the feature_disable_call_per_sender_encryption flag", async () => { + // We destroy the call created in beforeEach because we test the call creation process. + call.destroy(); + const addWidgetSpy = jest.spyOn(WidgetStore.instance, "addVirtualWidget"); + // If a room is not encrypted we will never add the perParticipantE2EE flag. + client.isRoomEncrypted.mockReturnValue(true); + + // should create call with perParticipantE2EE flag + ElementCall.create(room); + + expect(addWidgetSpy.mock.calls[0][0].url).toContain("perParticipantE2EE=true"); + ElementCall.get(room)?.destroy(); + + // should create call without perParticipantE2EE flag + enabledSettings.add("feature_disable_call_per_sender_encryption"); + await ElementCall.create(room); + enabledSettings.delete("feature_disable_call_per_sender_encryption"); + + expect(addWidgetSpy.mock.calls[1][0].url).not.toContain("perParticipantE2EE=true"); + + client.isRoomEncrypted.mockClear(); + addWidgetSpy.mockRestore(); + }); }); describe("instance in a video room", () => { From bef8aec483558292132a99041cc41828f8bdf5cc Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 10 Nov 2023 17:30:16 +0000 Subject: [PATCH 05/13] New release automations (#11825) * Add release-drafter Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Initial release automation Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Simplify dependency management Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add release-gitflow.yml Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .github/release-drafter.yml | 1 + .github/workflows/release-drafter.yml | 14 ++++++++++ .github/workflows/release-gitflow.yml | 13 ++++++++++ .github/workflows/release.yml | 37 +++++++++++++++++++++------ 4 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 .github/release-drafter.yml create mode 100644 .github/workflows/release-drafter.yml create mode 100644 .github/workflows/release-gitflow.yml diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000000..e9d334f61b --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1 @@ +_extends: matrix-org/matrix-js-sdk diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 0000000000..3ce2b5a2af --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,14 @@ +name: Release Drafter +on: + push: + branches: [staging] +concurrency: ${{ github.workflow }} +jobs: + draft: + runs-on: ubuntu-latest + steps: + - uses: release-drafter/release-drafter@dabcf3767562210392d862070ed2ef6434b9bc6f # v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + disable-autolabeler: true diff --git a/.github/workflows/release-gitflow.yml b/.github/workflows/release-gitflow.yml new file mode 100644 index 0000000000..b515bb4cc1 --- /dev/null +++ b/.github/workflows/release-gitflow.yml @@ -0,0 +1,13 @@ +# Gitflow merge-back master->develop +name: Merge master -> develop +on: + push: + branches: [master] +concurrency: ${{ github.repository }}-${{ github.workflow }} +jobs: + merge: + uses: matrix-org/matrix-js-sdk/.github/workflows/release-gitflow.yml@develop + secrets: inherit + with: + dependencies: | + matrix-js-sdk diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c8b44ef47d..1b08aa0734 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,11 +1,32 @@ name: Release Process on: - release: - types: [published] -concurrency: ${{ github.workflow }}-${{ github.ref }} + workflow_dispatch: + inputs: + mode: + description: What type of release + required: true + default: rc + type: choice + options: + - rc + - final + matrix-js-sdk: + description: JS SDK version to use (current|X.Y.Z) + required: false + default: current + type: string + npm: + description: Publish to npm + required: true + type: boolean + default: true +concurrency: ${{ github.workflow }} jobs: - npm: - name: Publish - uses: matrix-org/matrix-js-sdk/.github/workflows/release-npm.yml@develop - secrets: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + release: + uses: matrix-org/matrix-js-sdk/.github/workflows/release-action.yml@develop + secrets: inherit + with: + final: ${{ inputs.mode == 'final' }} + npm: ${{ inputs.npm }} + dependencies: | + matrix-js-sdk=${{ inputs.matrix-js-sdk }} From 7a56d61a9e42b7f17f768fddc7479a1a29a8dc69 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Fri, 10 Nov 2023 22:25:18 +0100 Subject: [PATCH 06/13] Disable Percy (#11852) * Disable Percy While visual regression testing is without doubt an essential part of quality assurance, the way we're currently using Percy brings little to no value while causing mainenance overhead. Therefore, we're disabling it until we have figure out https://github.com/vector-im/wat-internal/issues/36 and https://github.com/vector-im/wat-internal/issues/56. * Also disable nightly build * Comment out Percy step instead of fiddling with the output value * Appease the frigging linter --- .github/workflows/cypress.yaml | 23 +++++++++++++---------- .github/workflows/element-web.yaml | 8 ++++++-- README.md | 7 +++++++ docs/cypress.md | 4 ++++ 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/.github/workflows/cypress.yaml b/.github/workflows/cypress.yaml index 2892b62ae0..424d3699b6 100644 --- a/.github/workflows/cypress.yaml +++ b/.github/workflows/cypress.yaml @@ -78,16 +78,19 @@ jobs: core.setOutput("author", response.data.author.name); core.setOutput("email", response.data.author.email); - # Only run Percy when it is demanded or we are running the daily build - - name: Enable Percy - id: percy - if: | - github.event.workflow_run.event == 'schedule' || - ( - github.event.workflow_run.event == 'merge_group' && - contains(fromJSON(steps.prdetails.outputs.data).labels.*.name, 'X-Needs-Percy') - ) - run: echo "value=1" >> $GITHUB_OUTPUT + # Percy is disabled while we're figuring out https://github.com/vector-im/wat-internal/issues/36 + # and https://github.com/vector-im/wat-internal/issues/56. We're hoping to turn it back on or switch + # to an alternative in the future. + # # Only run Percy when it is demanded or we are running the daily build + # - name: Enable Percy + # id: percy + # if: | + # github.event.workflow_run.event == 'schedule' || + # ( + # github.event.workflow_run.event == 'merge_group' && + # contains(fromJSON(steps.prdetails.outputs.data).labels.*.name, 'X-Needs-Percy') + # ) + # run: echo "value=1" >> $GITHUB_OUTPUT - name: Generate unique ID 💎 id: uuid diff --git a/.github/workflows/element-web.yaml b/.github/workflows/element-web.yaml index 74a570d78b..7b085d892d 100644 --- a/.github/workflows/element-web.yaml +++ b/.github/workflows/element-web.yaml @@ -3,8 +3,12 @@ # as an artifact and run integration tests. name: Element Web - Build on: - schedule: - - cron: "17 4 * * 1-5" # every weekday at 04:17 UTC + # We only need the nightly run for Percy which is disabled while we're + # figuring out https://github.com/vector-im/wat-internal/issues/36 and + # https://github.com/vector-im/wat-internal/issues/56. We're hoping to + # turn it back on or switch to an alternative in the future. + # schedule: + # - cron: "17 4 * * 1-5" # every weekday at 04:17 UTC pull_request: {} merge_group: types: [checks_requested] diff --git a/README.md b/README.md index f17350a43d..39d1f600e2 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,14 @@ ![Tests](https://github.com/matrix-org/matrix-react-sdk/actions/workflows/tests.yml/badge.svg) ![Static Analysis](https://github.com/matrix-org/matrix-react-sdk/actions/workflows/static_analysis.yaml/badge.svg) [![matrix-react-sdk](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/ppvnzg/develop&style=flat&logo=cypress)](https://dashboard.cypress.io/projects/ppvnzg/runs) + + + [![Localazy](https://img.shields.io/endpoint?url=https%3A%2F%2Fconnect.localazy.com%2Fstatus%2Felement-web%2Fdata%3Fcontent%3Dall%26title%3Dlocalazy%26logo%3Dtrue)](https://localazy.com/p/element-web) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=matrix-react-sdk&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=matrix-react-sdk) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=matrix-react-sdk&metric=coverage)](https://sonarcloud.io/summary/new_code?id=matrix-react-sdk) diff --git a/docs/cypress.md b/docs/cypress.md index 91ec314bac..d786e1b5c0 100644 --- a/docs/cypress.md +++ b/docs/cypress.md @@ -238,6 +238,10 @@ should generally try to adhere to them. ## Screenshot testing with Percy +**⚠️ Percy is disabled while we're figuring out https://github.com/vector-im/wat-internal/issues/36** +**and https://github.com/vector-im/wat-internal/issues/56. We're hoping to turn it back on or switch** +**to an alternative in the future.** + We also support visual testing via [Percy](https://percy.io). Within many of our Cypress tests you can see lines calling `cy.percySnapshot()`. This creates a screenshot and uses Percy to check whether it has changed from the last time From 722c5ad493d2220bac7d2133735509b48886d4dc Mon Sep 17 00:00:00 2001 From: Germain Date: Sat, 11 Nov 2023 07:24:48 +0000 Subject: [PATCH 07/13] Update room summary card header (#11823) * Update room summary card header * test coverage for public room label * test coverage for public room label (#11841) * fix encrypted badge selector in cypress/crypto.spec --------- Co-authored-by: Kerry --- cypress/e2e/crypto/crypto.spec.ts | 2 +- .../views/right_panel/_RoomSummaryCard.pcss | 60 +------ .../views/right_panel/RoomSummaryCard.tsx | 86 +++++++--- .../right_panel/RoomSummaryCard-test.tsx | 149 ++++++++++++------ .../RoomSummaryCard-test.tsx.snap | 44 +++--- 5 files changed, 201 insertions(+), 140 deletions(-) diff --git a/cypress/e2e/crypto/crypto.spec.ts b/cypress/e2e/crypto/crypto.spec.ts index 9795b9da2d..f9cd5ba316 100644 --- a/cypress/e2e/crypto/crypto.spec.ts +++ b/cypress/e2e/crypto/crypto.spec.ts @@ -269,7 +269,7 @@ describe("Cryptography", function () { // Assert that verified icon is rendered cy.findByRole("button", { name: "Room members" }).click(); cy.findByRole("button", { name: "Room information" }).click(); - cy.get(".mx_RoomSummaryCard_e2ee_verified").should("exist"); + cy.get('.mx_RoomSummaryCard_badges [data-kind="success"]').should("contain.text", "Encrypted"); // Take a snapshot of RoomSummaryCard with a verified E2EE icon cy.get(".mx_RightPanel").percySnapshotElement("RoomSummaryCard - with a verified E2EE icon", { diff --git a/res/css/views/right_panel/_RoomSummaryCard.pcss b/res/css/views/right_panel/_RoomSummaryCard.pcss index e2b71e1a15..d6da39365e 100644 --- a/res/css/views/right_panel/_RoomSummaryCard.pcss +++ b/res/css/views/right_panel/_RoomSummaryCard.pcss @@ -31,68 +31,12 @@ limitations under the License. .mx_RoomSummaryCard_roomName { margin: $spacing-12 0 $spacing-4; - font-weight: var(--cpd-font-weight-semibold); - font-size: $font-17px; } .mx_RoomSummaryCard_alias { - font: var(--cpd-font-body-md-regular); - color: $secondary-content; text-overflow: ellipsis; } - .mx_RoomSummaryCard_avatar { - display: flex; - justify-content: center; - align-items: center; - - .mx_RoomSummaryCard_e2ee { - display: inline-block; - position: relative; - width: 54px; - height: 54px; - border-radius: 50%; - background-color: #737d8c; - margin-left: -10px; /* overlap */ - border: 3px solid $dark-panel-bg-color; - - &::before { - content: ""; - position: absolute; - top: 13px; - left: 13px; - height: 28px; - width: 28px; - mask-size: cover; - mask-repeat: no-repeat; - mask-position: center; - mask-image: url("$(res)/img/e2e/disabled.svg"); - background-color: #ffffff; - } - } - - .mx_RoomSummaryCard_e2ee_normal { - background-color: #424446; - &::before { - mask-image: url("$(res)/img/e2e/normal.svg"); - } - } - - .mx_RoomSummaryCard_e2ee_verified { - background-color: $e2e-verified-color; - &::before { - mask-image: url("$(res)/img/e2e/verified.svg"); - } - } - - .mx_RoomSummaryCard_e2ee_warning { - background-color: $e2e-warning-color; - &::before { - mask-image: url("$(res)/img/e2e/warning.svg"); - } - } - } - .mx_RoomSummaryCard_aboutGroup { .mx_RoomSummaryCard_Button { padding-left: 44px; @@ -244,6 +188,10 @@ limitations under the License. } } +.mx_RoomSummaryCard_badges { + margin: var(--cpd-space-4x) 0; +} + .mx_RoomSummaryCard_header { padding: 15px 12px; diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx index 98876fce93..ef6e3ea3ab 100644 --- a/src/components/views/right_panel/RoomSummaryCard.tsx +++ b/src/components/views/right_panel/RoomSummaryCard.tsx @@ -16,9 +16,13 @@ limitations under the License. import React, { useCallback, useContext, useEffect, useMemo, useState } from "react"; import classNames from "classnames"; -import { Room } from "matrix-js-sdk/src/matrix"; -import { Tooltip } from "@vector-im/compound-web"; +import { EventType, JoinRule, Room } from "matrix-js-sdk/src/matrix"; +import { Badge, Heading, Text, Tooltip } from "@vector-im/compound-web"; import { Icon as SearchIcon } from "@vector-im/compound-design-tokens/icons/search.svg"; +import { Icon as LockIcon } from "@vector-im/compound-design-tokens/icons/lock.svg"; +import { Icon as LockOffIcon } from "@vector-im/compound-design-tokens/icons/lock-off.svg"; +import { Icon as PublicIcon } from "@vector-im/compound-design-tokens/icons/public.svg"; +import { Icon as ErrorIcon } from "@vector-im/compound-design-tokens/icons/error.svg"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import { useIsEncrypted } from "../../../hooks/useIsEncrypted"; @@ -34,7 +38,6 @@ import { useEventEmitter } from "../../../hooks/useEventEmitter"; import WidgetUtils from "../../../utils/WidgetUtils"; import { IntegrationManagers } from "../../../integrations/IntegrationManagers"; import SettingsStore from "../../../settings/SettingsStore"; -import TextWithTooltip from "../elements/TextWithTooltip"; import WidgetAvatar from "../avatars/WidgetAvatar"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import WidgetStore, { IApp } from "../../../stores/WidgetStore"; @@ -56,6 +59,8 @@ import PosthogTrackers from "../../../PosthogTrackers"; import { shouldShowComponent } from "../../../customisations/helpers/UIComponents"; import { PollHistoryDialog } from "../dialogs/PollHistoryDialog"; import { Flex } from "../../utils/Flex"; +import { useAccountData } from "../../../hooks/useAccountData"; +import { useRoomState } from "../../../hooks/useRoomState"; interface IProps { room: Room; @@ -307,31 +312,74 @@ const RoomSummaryCard: React.FC = ({ room, permalinkCreator, onClose, on const isVideoRoom = videoRoomsEnabled && (room.isElementVideoRoom() || (elementCallVideoRoomsEnabled && room.isCallRoom())); + const roomState = useRoomState(room); + const directRoomsList = useAccountData>(room.client, EventType.Direct); + const [isDirectMessage, setDirectMessage] = useState(false); + useEffect(() => { + for (const [, dmRoomList] of Object.entries(directRoomsList)) { + if (dmRoomList.includes(room?.roomId ?? "")) { + setDirectMessage(true); + break; + } + } + }, [room, directRoomsList]); + const alias = room.getCanonicalAlias() || room.getAltAliases()[0] || ""; const header = (
-
- - -
- + {(name) => ( -

+ {name} -

+ )}
-
+ {alias} -
+ + + + {!isDirectMessage && roomState.getJoinRule() === JoinRule.Public && ( + + + {_t("common|public_room")} + + )} + + {isRoomEncrypted && e2eStatus !== E2EStatus.Warning && ( + + + {_t("common|encrypted")} + + )} + + {!e2eStatus && ( + + + {_t("common|unencrypted")} + + )} + + {e2eStatus === E2EStatus.Warning && ( + + + {_t("common|not_trusted")} + + )} +
); diff --git a/test/components/views/right_panel/RoomSummaryCard-test.tsx b/test/components/views/right_panel/RoomSummaryCard-test.tsx index eef7d06ba9..7f556000f6 100644 --- a/test/components/views/right_panel/RoomSummaryCard-test.tsx +++ b/test/components/views/right_panel/RoomSummaryCard-test.tsx @@ -15,8 +15,9 @@ limitations under the License. */ import React from "react"; -import { render, fireEvent } from "@testing-library/react"; -import { MatrixEvent, Room } from "matrix-js-sdk/src/matrix"; +import { render, fireEvent, screen } from "@testing-library/react"; +import { EventType, MatrixEvent, Room, MatrixClient, JoinRule } from "matrix-js-sdk/src/matrix"; +import { mocked, MockedObject } from "jest-mock"; import DMRoomMap from "../../../../src/utils/DMRoomMap"; import RoomSummaryCard from "../../../../src/components/views/right_panel/RoomSummaryCard"; @@ -28,56 +29,67 @@ import * as settingsHooks from "../../../../src/hooks/useSettings"; import Modal from "../../../../src/Modal"; import RightPanelStore from "../../../../src/stores/right-panel/RightPanelStore"; import { RightPanelPhases } from "../../../../src/stores/right-panel/RightPanelStorePhases"; -import { getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../test-utils"; +import { flushPromises, getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../test-utils"; import { PollHistoryDialog } from "../../../../src/components/views/dialogs/PollHistoryDialog"; import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks"; import { _t } from "../../../../src/languageHandler"; describe("", () => { const userId = "@alice:domain.org"; - const mockClient = getMockClientWithEventEmitter({ - ...mockClientMethodsUser(userId), - isRoomEncrypted: jest.fn(), - getRoom: jest.fn(), - }); + const roomId = "!room:domain.org"; - const room = new Room(roomId, mockClient, userId); - const roomCreateEvent = new MatrixEvent({ - type: "m.room.create", - room_id: roomId, - sender: userId, - content: { - creator: userId, - room_version: "5", - }, - state_key: "", - }); - room.currentState.setStateEvents([roomCreateEvent]); - const defaultProps = { - room, - onClose: jest.fn(), - permalinkCreator: new RoomPermalinkCreator(room), - }; - const getComponent = (props = {}) => - render(, { + let mockClient!: MockedObject; + let room!: Room; + + const getComponent = (props = {}) => { + const defaultProps = { + room, + onClose: jest.fn(), + permalinkCreator: new RoomPermalinkCreator(room), + }; + + return render(, { wrapper: ({ children }) => ( {children} ), }); - - const modalSpy = jest.spyOn(Modal, "createDialog"); - const dispatchSpy = jest.spyOn(defaultDispatcher, "dispatch"); - const rightPanelCardSpy = jest.spyOn(RightPanelStore.instance, "pushCard"); - const featureEnabledSpy = jest.spyOn(settingsHooks, "useFeatureEnabled"); + }; beforeEach(() => { + mockClient = getMockClientWithEventEmitter({ + ...mockClientMethodsUser(userId), + getAccountData: jest.fn(), + isRoomEncrypted: jest.fn(), + getOrCreateFilter: jest.fn().mockResolvedValue({ filterId: 1 }), + getRoom: jest.fn(), + }); + room = new Room(roomId, mockClient, userId); + const roomCreateEvent = new MatrixEvent({ + type: "m.room.create", + room_id: roomId, + sender: userId, + content: { + creator: userId, + room_version: "5", + }, + state_key: "", + }); + room.currentState.setStateEvents([roomCreateEvent]); + + jest.spyOn(Modal, "createDialog"); + jest.spyOn(RightPanelStore.instance, "pushCard"); + jest.spyOn(settingsHooks, "useFeatureEnabled").mockReturnValue(false); + jest.spyOn(defaultDispatcher, "dispatch"); jest.clearAllMocks(); DMRoomMap.makeShared(mockClient); mockClient.getRoom.mockReturnValue(room); jest.spyOn(room, "isElementVideoRoom").mockRestore(); jest.spyOn(room, "isCallRoom").mockRestore(); - featureEnabledSpy.mockReset().mockReturnValue(false); + }); + + afterEach(() => { + jest.restoreAllMocks(); }); it("renders the room summary", () => { @@ -101,7 +113,10 @@ describe("", () => { fireEvent.click(getByText("People")); - expect(rightPanelCardSpy).toHaveBeenCalledWith({ phase: RightPanelPhases.RoomMemberList }, true); + expect(RightPanelStore.instance.pushCard).toHaveBeenCalledWith( + { phase: RightPanelPhases.RoomMemberList }, + true, + ); }); it("opens room file panel on button click", () => { @@ -109,7 +124,7 @@ describe("", () => { fireEvent.click(getByText("Files")); - expect(rightPanelCardSpy).toHaveBeenCalledWith({ phase: RightPanelPhases.FilePanel }, true); + expect(RightPanelStore.instance.pushCard).toHaveBeenCalledWith({ phase: RightPanelPhases.FilePanel }, true); }); it("opens room export dialog on button click", () => { @@ -117,7 +132,7 @@ describe("", () => { fireEvent.click(getByText("Export chat")); - expect(modalSpy).toHaveBeenCalledWith(ExportDialog, { room }); + expect(Modal.createDialog).toHaveBeenCalledWith(ExportDialog, { room }); }); it("opens share room dialog on button click", () => { @@ -125,7 +140,7 @@ describe("", () => { fireEvent.click(getByText("Share room")); - expect(modalSpy).toHaveBeenCalledWith(ShareDialog, { target: room }); + expect(Modal.createDialog).toHaveBeenCalledWith(ShareDialog, { target: room }); }); it("opens room settings on button click", () => { @@ -133,12 +148,12 @@ describe("", () => { fireEvent.click(getByText("Room settings")); - expect(dispatchSpy).toHaveBeenCalledWith({ action: "open_room_settings" }); + expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({ action: "open_room_settings" }); }); describe("pinning", () => { it("renders pins options when pinning feature is enabled", () => { - featureEnabledSpy.mockImplementation((feature) => feature === "feature_pinning"); + mocked(settingsHooks.useFeatureEnabled).mockImplementation((feature) => feature === "feature_pinning"); const { getByText } = getComponent(); expect(getByText("Pinned")).toBeInTheDocument(); @@ -153,14 +168,15 @@ describe("", () => { }); it("opens poll history dialog on button click", () => { - const { getByText } = getComponent(); + const permalinkCreator = new RoomPermalinkCreator(room); + const { getByText } = getComponent({ permalinkCreator }); fireEvent.click(getByText("Poll history")); - expect(modalSpy).toHaveBeenCalledWith(PollHistoryDialog, { + expect(Modal.createDialog).toHaveBeenCalledWith(PollHistoryDialog, { room, matrixClient: mockClient, - permalinkCreator: defaultProps.permalinkCreator, + permalinkCreator: permalinkCreator, }); }); }); @@ -168,7 +184,7 @@ describe("", () => { describe("video rooms", () => { it("does not render irrelevant options for element video room", () => { jest.spyOn(room, "isElementVideoRoom").mockReturnValue(true); - featureEnabledSpy.mockImplementation( + mocked(settingsHooks.useFeatureEnabled).mockImplementation( (feature) => feature === "feature_video_rooms" || feature === "feature_pinning", ); const { queryByText } = getComponent(); @@ -181,7 +197,7 @@ describe("", () => { it("does not render irrelevant options for element call room", () => { jest.spyOn(room, "isCallRoom").mockReturnValue(true); - featureEnabledSpy.mockImplementation( + mocked(settingsHooks.useFeatureEnabled).mockImplementation( (feature) => feature === "feature_element_call_video_rooms" || feature === "feature_video_rooms" || @@ -195,4 +211,49 @@ describe("", () => { expect(queryByText("Export chat")).not.toBeInTheDocument(); }); }); + + describe("public room label", () => { + beforeEach(() => { + jest.spyOn(room.currentState, "getJoinRule").mockReturnValue(JoinRule.Public); + }); + + it("does not show public room label for a DM", async () => { + mockClient.getAccountData.mockImplementation( + (eventType) => + ({ + [EventType.Direct]: new MatrixEvent({ + type: EventType.Direct, + content: { + "@bob:sesame.st": ["some-room-id"], + // this room is a DM with ernie + "@ernie:sesame.st": ["some-other-room-id", room.roomId], + }, + }), + }[eventType]), + ); + getComponent(); + + await flushPromises(); + + expect(screen.queryByText("Public room")).not.toBeInTheDocument(); + }); + + it("does not show public room label for non public room", async () => { + jest.spyOn(room.currentState, "getJoinRule").mockReturnValue(JoinRule.Invite); + getComponent(); + + await flushPromises(); + + expect(screen.queryByText("Public room")).not.toBeInTheDocument(); + }); + + it("shows a public room label for a public room", async () => { + jest.spyOn(room.currentState, "getJoinRule").mockReturnValue(JoinRule.Public); + getComponent(); + + await flushPromises(); + + expect(screen.queryByText("Public room")).toBeInTheDocument(); + }); + }); }); 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 8c5891b576..9e81528f1c 100644 --- a/test/components/views/right_panel/__snapshots__/RoomSummaryCard-test.tsx.snap +++ b/test/components/views/right_panel/__snapshots__/RoomSummaryCard-test.tsx.snap @@ -35,36 +35,40 @@ exports[` renders the room summary 1`] = `
-
Date: Sat, 11 Nov 2023 08:42:02 +0000 Subject: [PATCH 08/13] Fix a test that was expecting an edit to be considered unread (#11847) --- cypress/e2e/read-receipts/editing-messages.spec.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cypress/e2e/read-receipts/editing-messages.spec.ts b/cypress/e2e/read-receipts/editing-messages.spec.ts index bbaa15d659..04b21acd1a 100644 --- a/cypress/e2e/read-receipts/editing-messages.spec.ts +++ b/cypress/e2e/read-receipts/editing-messages.spec.ts @@ -134,8 +134,7 @@ describe("Read receipts", () => { goTo(room1); assertStillRead(room2); }); - // XXX: fails because we see a dot instead of an unread number - probably the server and client disagree - it.skip("Editing a message after marking as read makes the room unread", () => { + it("Editing a message after marking as read makes the room unread", () => { // Given the room is marked as read goTo(room1); receiveMessages(room2, ["Msg1"]); @@ -146,8 +145,8 @@ describe("Read receipts", () => { // When a message is edited receiveMessages(room2, [editOf("Msg1", "Msg1 Edit1")]); - // Then the room becomes unread - assertUnread(room2, 1); + // Then the room remains unread + assertStillRead(room2); }); it("Editing a reply after reading it makes the room unread", () => { // Given the room is all read From 0d81159f1dc616db93410754222a27c7e9a6a1f5 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 13 Nov 2023 09:21:04 +0000 Subject: [PATCH 09/13] Update CODEOWNERS --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 16574bad79..b436b4e901 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,3 +2,4 @@ /.github/workflows/** @matrix-org/element-web-app-team /package.json @matrix-org/element-web-app-team /yarn.lock @matrix-org/element-web-app-team +/src/i18n/strings From 87276c54eb08436f66ae20e9aaccadf20ace1c53 Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Mon, 13 Nov 2023 09:46:31 +0000 Subject: [PATCH 10/13] Upgrade matrix-js-sdk to 30.0.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 33713fa5c7..f3745d9dc4 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "maplibre-gl": "^2.0.0", "matrix-encrypt-attachment": "^1.0.3", "matrix-events-sdk": "0.0.1", - "matrix-js-sdk": "30.0.0", + "matrix-js-sdk": "30.0.1", "matrix-widget-api": "^1.5.0", "memoize-one": "^6.0.0", "minimist": "^1.2.5", diff --git a/yarn.lock b/yarn.lock index 03690963b9..1b77d8a2ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7691,10 +7691,10 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -matrix-js-sdk@30.0.0: - version "30.0.0" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-30.0.0.tgz#8a0ed49ea7eb1d4a036107c5789edd1eb2e7d65a" - integrity sha512-v0fDomTGCEkeq97BI4viphTrd7Bn26Op1i+ssubFjlQs302Q5xTfuEVXUaMjuXkn9iUYm8daee1WNezo7kxoaQ== +matrix-js-sdk@30.0.1: + version "30.0.1" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-30.0.1.tgz#33a1fb2d9a9a8875f51f48a1b3124c1e82457472" + integrity sha512-/yefRQ7e8xU0Aox8w6lYUDjYdK+9Wmpz59K1SJZX3E1KE1SUvIo4rkPkGojN3RkRFqXXBBP4ciJiy5vH6OodAg== dependencies: "@babel/runtime" "^7.12.5" "@matrix-org/matrix-sdk-crypto-wasm" "^2.2.0" From 69c367167f6307662db554c22133a5c887c68a35 Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Mon, 13 Nov 2023 09:49:24 +0000 Subject: [PATCH 11/13] Prepare changelog for v3.84.1 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e792b05d8..b00376bb84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Changes in [3.84.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.84.1) (2023-11-13) +===================================================================================================== + +## 🐛 Bug Fixes + * Ensure `setUserCreator` is called when a store is assigned ([\#3867](https://github.com/matrix-org/matrix-js-sdk/pull/3867)). Fixes vector-im/element-web#26520. Contributed by @MidhunSureshR. + Changes in [3.84.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.84.0) (2023-11-07) ===================================================================================================== From 36927c24375847823c94d7f1085b5619865edf26 Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Mon, 13 Nov 2023 09:49:26 +0000 Subject: [PATCH 12/13] v3.84.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f3745d9dc4..a9c7276aa3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.84.0", + "version": "3.84.1", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 6ee8349f7ce6d6f47bc00922d3577e972bd4a04a Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Mon, 13 Nov 2023 09:53:28 +0000 Subject: [PATCH 13/13] Reset matrix-js-sdk back to develop branch --- package.json | 2 +- yarn.lock | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 2abf594d92..f7120476ec 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "maplibre-gl": "^2.0.0", "matrix-encrypt-attachment": "^1.0.3", "matrix-events-sdk": "0.0.1", - "matrix-js-sdk": "30.0.1", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", "matrix-widget-api": "^1.5.0", "memoize-one": "^6.0.0", "minimist": "^1.2.5", diff --git a/yarn.lock b/yarn.lock index 8733b8d931..743c2b68de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1799,10 +1799,10 @@ emojibase "^15.0.0" emojibase-data "^15.0.0" -"@matrix-org/matrix-sdk-crypto-wasm@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-2.2.0.tgz#7c60afe01915281a6b71502821bc8e01afbfa70d" - integrity sha512-txmvaTiZpVV0/kWCRcE7tZvRESCEc1ynLJDVh9OUsFlaXfl13c7qdD3E6IJEJ8YiPMIn+PHogdfBZsO84reaMg== +"@matrix-org/matrix-sdk-crypto-wasm@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-3.0.1.tgz#56a0376f8a389264bcf4d5325b378a71f18b7664" + integrity sha512-r0PBfUKlLHm67+fpIV21netX5+DujbY2XjJy7JUGJ55oW4XWBNbSf9vElfaQkrdt/iDscL/8I5PoD5lCuVW6zA== "@matrix-org/matrix-wysiwyg@2.4.1": version "2.4.1" @@ -7564,13 +7564,12 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -matrix-js-sdk@30.0.1: +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": version "30.0.1" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-30.0.1.tgz#33a1fb2d9a9a8875f51f48a1b3124c1e82457472" - integrity sha512-/yefRQ7e8xU0Aox8w6lYUDjYdK+9Wmpz59K1SJZX3E1KE1SUvIo4rkPkGojN3RkRFqXXBBP4ciJiy5vH6OodAg== + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/76f993e7ff72768ba1769f6893712ec9a4f4a0c2" dependencies: "@babel/runtime" "^7.12.5" - "@matrix-org/matrix-sdk-crypto-wasm" "^2.2.0" + "@matrix-org/matrix-sdk-crypto-wasm" "^3.0.1" another-json "^0.2.0" bs58 "^5.0.0" content-type "^1.0.4"