diff --git a/res/css/_components.pcss b/res/css/_components.pcss index bbc6a3eadc1..9805f6eae1c 100644 --- a/res/css/_components.pcss +++ b/res/css/_components.pcss @@ -30,6 +30,7 @@ @import "./components/views/location/_ZoomButtons.pcss"; @import "./components/views/messages/_MBeaconBody.pcss"; @import "./components/views/messages/shared/_MediaProcessingError.pcss"; +@import "./components/views/settings/devices/_CurrentDeviceSection.pcss"; @import "./components/views/settings/devices/_DeviceDetailHeading.pcss"; @import "./components/views/settings/devices/_DeviceDetails.pcss"; @import "./components/views/settings/devices/_DeviceExpandDetailsButton.pcss"; diff --git a/res/css/components/views/settings/devices/_CurrentDeviceSection.pcss b/res/css/components/views/settings/devices/_CurrentDeviceSection.pcss new file mode 100644 index 00000000000..552270db1d0 --- /dev/null +++ b/res/css/components/views/settings/devices/_CurrentDeviceSection.pcss @@ -0,0 +1,20 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_CurrentDeviceSection_deviceDetails { + // align with text of session tile + margin-left: 56px; +} diff --git a/res/css/components/views/settings/devices/_DeviceDetails.pcss b/res/css/components/views/settings/devices/_DeviceDetails.pcss index 8c4aac6cbf2..9b34fa378aa 100644 --- a/res/css/components/views/settings/devices/_DeviceDetails.pcss +++ b/res/css/components/views/settings/devices/_DeviceDetails.pcss @@ -19,8 +19,6 @@ limitations under the License. flex-direction: column; box-sizing: border-box; - width: 100%; - margin-top: $spacing-16; padding: $spacing-24; border-radius: 8px; diff --git a/res/css/components/views/settings/devices/_FilteredDeviceList.pcss b/res/css/components/views/settings/devices/_FilteredDeviceList.pcss index d34270e8ad8..9f9bd0cc712 100644 --- a/res/css/components/views/settings/devices/_FilteredDeviceList.pcss +++ b/res/css/components/views/settings/devices/_FilteredDeviceList.pcss @@ -50,3 +50,8 @@ limitations under the License. flex-direction: row; gap: $spacing-8; } + +.mx_FilteredDeviceList_deviceDetails { + // align with text of session tile + margin-left: 88px; +} diff --git a/src/components/views/settings/devices/CurrentDeviceSection.tsx b/src/components/views/settings/devices/CurrentDeviceSection.tsx index 9044f882ec8..46c6f3e7d12 100644 --- a/src/components/views/settings/devices/CurrentDeviceSection.tsx +++ b/src/components/views/settings/devices/CurrentDeviceSection.tsx @@ -124,11 +124,16 @@ const CurrentDeviceSection: React.FC = ({ onVerifyDevice={onVerifyCurrentDevice} onSignOutDevice={onSignOutCurrentDevice} saveDeviceName={saveDeviceName} + className="mx_CurrentDeviceSection_deviceDetails" /> ) : ( <>
- + )} diff --git a/src/components/views/settings/devices/DeviceDetails.tsx b/src/components/views/settings/devices/DeviceDetails.tsx index 7e47f835041..1793fc8b5ee 100644 --- a/src/components/views/settings/devices/DeviceDetails.tsx +++ b/src/components/views/settings/devices/DeviceDetails.tsx @@ -15,6 +15,7 @@ limitations under the License. */ import React from "react"; +import classNames from "classnames"; import { IPusher } from "matrix-js-sdk/src/@types/PushRules"; import { PUSHER_ENABLED } from "matrix-js-sdk/src/@types/event"; import { LocalNotificationSettings } from "matrix-js-sdk/src/@types/local_notifications"; @@ -38,6 +39,8 @@ interface Props { saveDeviceName: (deviceName: string) => Promise; setPushNotifications?: (deviceId: string, enabled: boolean) => Promise | undefined; supportsMSC3881?: boolean | undefined; + className?: string; + isCurrentDevice?: boolean; } interface MetadataTable { @@ -56,6 +59,8 @@ const DeviceDetails: React.FC = ({ saveDeviceName, setPushNotifications, supportsMSC3881, + className, + isCurrentDevice, }) => { const metadata: MetadataTable[] = [ { @@ -113,10 +118,10 @@ const DeviceDetails: React.FC = ({ } return ( -
+
- +

{_t("Session details")}

diff --git a/src/components/views/settings/devices/DeviceVerificationStatusCard.tsx b/src/components/views/settings/devices/DeviceVerificationStatusCard.tsx index 6f7d71ff275..2c7af18512c 100644 --- a/src/components/views/settings/devices/DeviceVerificationStatusCard.tsx +++ b/src/components/views/settings/devices/DeviceVerificationStatusCard.tsx @@ -22,25 +22,30 @@ import DeviceSecurityCard from "./DeviceSecurityCard"; import { DeviceSecurityLearnMore } from "./DeviceSecurityLearnMore"; import { DeviceSecurityVariation, ExtendedDevice } from "./types"; -interface Props { +export interface DeviceVerificationStatusCardProps { device: ExtendedDevice; + isCurrentDevice?: boolean; onVerifyDevice?: () => void; } const getCardProps = ( device: ExtendedDevice, + isCurrentDevice?: boolean, ): { variation: DeviceSecurityVariation; heading: string; description: React.ReactNode; } => { if (device.isVerified) { + const descriptionText = isCurrentDevice + ? _t("Your current session is ready for secure messaging.") + : _t("This session is ready for secure messaging."); return { variation: DeviceSecurityVariation.Verified, heading: _t("Verified session"), description: ( <> - {_t("This session is ready for secure messaging.")} + {descriptionText} ), @@ -59,20 +64,27 @@ const getCardProps = ( }; } + const descriptionText = isCurrentDevice + ? _t("Verify your current session for enhanced secure messaging.") + : _t("Verify or sign out from this session for best security and reliability."); return { variation: DeviceSecurityVariation.Unverified, heading: _t("Unverified session"), description: ( <> - {_t("Verify or sign out from this session for best security and reliability.")} + {descriptionText} ), }; }; -export const DeviceVerificationStatusCard: React.FC = ({ device, onVerifyDevice }) => { - const securityCardProps = getCardProps(device); +export const DeviceVerificationStatusCard: React.FC = ({ + device, + isCurrentDevice, + onVerifyDevice, +}) => { + const securityCardProps = getCardProps(device, isCurrentDevice); return ( diff --git a/src/components/views/settings/devices/FilteredDeviceList.tsx b/src/components/views/settings/devices/FilteredDeviceList.tsx index 026add74a40..c31fb8ca30d 100644 --- a/src/components/views/settings/devices/FilteredDeviceList.tsx +++ b/src/components/views/settings/devices/FilteredDeviceList.tsx @@ -213,6 +213,7 @@ const DeviceListItem: React.FC<{ saveDeviceName={saveDeviceName} setPushNotifications={setPushNotifications} supportsMSC3881={supportsMSC3881} + className="mx_FilteredDeviceList_deviceDetails" /> )} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 43247b0bd1d..13ee074d581 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1817,9 +1817,11 @@ "Mobile session": "Mobile session", "Web session": "Web session", "Unknown session type": "Unknown session type", - "Verified session": "Verified session", + "Your current session is ready for secure messaging.": "Your current session is ready for secure messaging.", "This session is ready for secure messaging.": "This session is ready for secure messaging.", + "Verified session": "Verified session", "This session doesn't support encryption and thus can't be verified.": "This session doesn't support encryption and thus can't be verified.", + "Verify your current session for enhanced secure messaging.": "Verify your current session for enhanced secure messaging.", "Verify or sign out from this session for best security and reliability.": "Verify or sign out from this session for best security and reliability.", "Verify session": "Verify session", "For best security, sign out from any session that you don't recognize or use anymore.": "For best security, sign out from any session that you don't recognize or use anymore.", diff --git a/test/components/views/settings/devices/DeviceVerificationStatusCard-test.tsx b/test/components/views/settings/devices/DeviceVerificationStatusCard-test.tsx new file mode 100644 index 00000000000..51af4248167 --- /dev/null +++ b/test/components/views/settings/devices/DeviceVerificationStatusCard-test.tsx @@ -0,0 +1,96 @@ +/* +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 { render } from "@testing-library/react"; +import React from "react"; + +import { + DeviceVerificationStatusCard, + DeviceVerificationStatusCardProps, +} from "../../../../../src/components/views/settings/devices/DeviceVerificationStatusCard"; +import { ExtendedDevice } from "../../../../../src/components/views/settings/devices/types"; +import { DeviceType } from "../../../../../src/utils/device/parseUserAgent"; + +describe("", () => { + const deviceId = "test-device"; + const unverifiedDevice: ExtendedDevice = { + device_id: deviceId, + isVerified: false, + deviceType: DeviceType.Unknown, + }; + const verifiedDevice: ExtendedDevice = { + ...unverifiedDevice, + isVerified: true, + }; + const unverifiableDevice: ExtendedDevice = { + ...unverifiedDevice, + isVerified: null, + }; + const defaultProps = { + device: unverifiedDevice, + onVerifyDevice: jest.fn(), + }; + const getComponent = (props: Partial = {}) => ( + + ); + + const verifyButtonTestId = `verification-status-button-${deviceId}`; + + describe("for the current device", () => { + // current device uses different copy + it("renders an unverified device", () => { + const { getByText } = render(getComponent({ isCurrentDevice: true })); + expect(getByText("Verify your current session for enhanced secure messaging.")).toBeTruthy(); + }); + + it("renders an unverifiable device", () => { + const { getByText } = render( + getComponent({ + device: unverifiableDevice, + isCurrentDevice: true, + }), + ); + expect(getByText("This session doesn't support encryption and thus can't be verified.")).toBeTruthy(); + }); + + it("renders a verified device", () => { + const { getByText } = render( + getComponent({ + device: verifiedDevice, + isCurrentDevice: true, + }), + ); + expect(getByText("Your current session is ready for secure messaging.")).toBeTruthy(); + }); + }); + + it("renders an unverified device", () => { + const { container } = render(getComponent()); + expect(container).toMatchSnapshot(); + }); + + it("renders an unverifiable device", () => { + const { container, queryByTestId } = render(getComponent({ device: unverifiableDevice })); + expect(container).toMatchSnapshot(); + expect(queryByTestId(verifyButtonTestId)).toBeFalsy(); + }); + + it("renders a verified device", () => { + const { container, queryByTestId } = render(getComponent({ device: verifiedDevice })); + expect(container).toMatchSnapshot(); + expect(queryByTestId(verifyButtonTestId)).toBeFalsy(); + }); +}); diff --git a/test/components/views/settings/devices/__snapshots__/CurrentDeviceSection-test.tsx.snap b/test/components/views/settings/devices/__snapshots__/CurrentDeviceSection-test.tsx.snap index 739f559ad40..907e6396ddb 100644 --- a/test/components/views/settings/devices/__snapshots__/CurrentDeviceSection-test.tsx.snap +++ b/test/components/views/settings/devices/__snapshots__/CurrentDeviceSection-test.tsx.snap @@ -3,7 +3,7 @@ exports[` displays device details on toggle click 1`] = ` HTMLCollection [
- Verify or sign out from this session for best security and reliability. + Verify your current session for enhanced secure messaging.