Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Fix decryption failure bar covering the timeline #10360

Merged
merged 24 commits into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d2d9a6a
Use grid layout instead
luixxiul Mar 12, 2023
8640784
Unset height of spinner
luixxiul Mar 12, 2023
2758b15
Break lines at newline characters with white-space: pre-line
luixxiul Mar 12, 2023
cc671b1
Edit tests to check decryption failure bars on narrow timeline
luixxiul Mar 12, 2023
6d7b8c6
Remove a line
luixxiul Mar 13, 2023
2a343d5
Edit the test to have it check mx_EventTile_last only inside mx_RoomV…
luixxiul Mar 14, 2023
45572ff
Fix double underscores
luixxiul Mar 15, 2023
981b601
Fix double underscores - pcss
luixxiul Mar 15, 2023
8b69e62
Merge branch 'develop' into fix-decryption-failure-bar
luixxiul Mar 17, 2023
eb6d902
Iterate - buttons at the bottom
luixxiul Mar 15, 2023
228c195
Check waiting headline as well
luixxiul Mar 18, 2023
06f9dd9
Increase spacing between the message and the buttons
luixxiul Mar 18, 2023
d1e272d
lint
luixxiul Mar 18, 2023
626b808
Increase block gap between wrapped buttons for clickability
luixxiul Mar 20, 2023
69281b4
Merge branch 'develop' into fix-decryption-failure-bar
luixxiul Mar 20, 2023
58a023d
Merge branch 'develop' into fix-decryption-failure-bar
luixxiul Mar 22, 2023
af1177b
Revert bottom margin of buttons which are not expected to be wrapped
luixxiul Mar 22, 2023
04ad0a8
Check visibility instead of existence
luixxiul Mar 27, 2023
02b4249
Remove redundant gap between 'mx_DecryptionFailureBar_start' and the …
luixxiul Mar 27, 2023
02afe55
lint - prettier
luixxiul Mar 27, 2023
bb399ce
Merge branch 'develop' into fix-decryption-failure-bar
luixxiul Mar 27, 2023
ab39b65
Have Percy take a snapshot of the bar loading spinner before checkTim…
luixxiul Mar 28, 2023
779e74b
Merge branch 'develop' into fix-decryption-failure-bar
Mar 29, 2023
917a6a6
Merge branch 'develop' into fix-decryption-failure-bar
luixxiul Mar 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 49 additions & 10 deletions cypress/e2e/crypto/decryption-failure.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,28 @@ const handleVerificationRequest = (request: VerificationRequest): Chainable<Emoj
);
};

const checkTimelineNarrow = (button = true) => {
cy.viewport(800, 600); // SVGA
cy.get(".mx_LeftPanel_minimized").should("exist"); // Wait until the left panel is minimized
cy.get(".mx_RightPanel_roomSummaryButton").click(); // Open the right panel to make the timeline narrow
cy.get(".mx_BaseCard").should("exist");

// Ensure the failure bar does not cover the timeline
cy.get(".mx_RoomView_body .mx_EventTile.mx_EventTile_last").should("be.visible");

// Ensure the indicator does not overflow the timeline
cy.get("[data-testid='decryption-failure-bar-indicator']").should("be.visible");

if (button) {
// Ensure the button does not overflow the timeline
cy.get("[data-testid='decryption-failure-bar-button']:last-of-type").should("be.visible");
}

cy.get(".mx_RightPanel_roomSummaryButton").click(); // Close the right panel
cy.get(".mx_BaseCard").should("not.exist");
cy.viewport(1000, 660); // Reset to the default size
};

describe("Decryption Failure Bar", () => {
let homeserver: HomeserverInstance | undefined;
let testUser: UserCredentials | undefined;
Expand Down Expand Up @@ -114,19 +136,23 @@ describe("Decryption Failure Bar", () => {
.then(() => {
cy.botSendMessage(bot, roomId, "test");
cy.contains(
".mx_DecryptionFailureBar .mx_DecryptionFailureBar_message_headline",
".mx_DecryptionFailureBar .mx_DecryptionFailureBar__header__headline",
"Verify this device to access all messages",
);

checkTimelineNarrow();

cy.get(".mx_DecryptionFailureBar").percySnapshotElement(
"DecryptionFailureBar prompts user to verify",
{
widths: [320, 640],
},
);

cy.contains(".mx_DecryptionFailureBar_button", "Resend key requests").should("not.exist");
cy.contains(".mx_DecryptionFailureBar_button", "Verify").click();
cy.contains(".mx_DecryptionFailureBar__header__buttons__button", "Resend key requests").should(
"not.exist",
);
cy.contains(".mx_DecryptionFailureBar__header__buttons__button", "Verify").click();

const verificationRequestPromise = waitForVerificationRequest(otherDevice);
cy.get(".mx_CompleteSecurity_actionRow .mx_AccessibleButton").click();
Expand All @@ -146,11 +172,13 @@ describe("Decryption Failure Bar", () => {
cy.get(".mx_VerificationPanel_verified_section .mx_E2EIcon_verified").should("exist");
cy.contains(".mx_AccessibleButton", "Got it").click();

cy.get(".mx_DecryptionFailureBar .mx_DecryptionFailureBar_message_headline").should(
cy.get(".mx_DecryptionFailureBar .mx_DecryptionFailureBar__header__headline").should(
"have.text",
"Open another device to load encrypted messages",
);

checkTimelineNarrow();

cy.get(".mx_DecryptionFailureBar").percySnapshotElement(
"DecryptionFailureBar prompts user to open another device, with Resend Key Requests button",
{
Expand All @@ -159,9 +187,12 @@ describe("Decryption Failure Bar", () => {
);

cy.intercept("/_matrix/client/r0/sendToDevice/m.room_key_request/*").as("keyRequest");
cy.contains(".mx_DecryptionFailureBar_button", "Resend key requests").click();
cy.contains(".mx_DecryptionFailureBar__header__buttons__button", "Resend key requests").click();
cy.wait("@keyRequest");
cy.contains(".mx_DecryptionFailureBar_button", "Resend key requests").should("not.exist");
luixxiul marked this conversation as resolved.
Show resolved Hide resolved
cy.contains(".mx_DecryptionFailureBar__header__buttons__button", "Resend key requests").should("not.exist");
cy.contains(".mx_DecryptionFailureBar__header__buttons__button", "View your device list").should("exist");

checkTimelineNarrow();

cy.get(".mx_DecryptionFailureBar").percySnapshotElement(
"DecryptionFailureBar prompts user to open another device, without Resend Key Requests button",
Expand All @@ -184,15 +215,17 @@ describe("Decryption Failure Bar", () => {

cy.botSendMessage(bot, roomId, "test");
cy.contains(
".mx_DecryptionFailureBar .mx_DecryptionFailureBar_message_headline",
".mx_DecryptionFailureBar .mx_DecryptionFailureBar__header__headline",
"Reset your keys to prevent future decryption errors",
);

checkTimelineNarrow();

cy.get(".mx_DecryptionFailureBar").percySnapshotElement("DecryptionFailureBar prompts user to reset keys", {
widths: [320, 640],
});

cy.contains(".mx_DecryptionFailureBar_button", "Reset").click();
cy.contains(".mx_DecryptionFailureBar__header__buttons__button", "Reset").click();

// Set up key backup
cy.get(".mx_Dialog").within(() => {
Expand All @@ -204,11 +237,13 @@ describe("Decryption Failure Bar", () => {
cy.contains("Done").click();
});

cy.get(".mx_DecryptionFailureBar .mx_DecryptionFailureBar_message_headline").should(
cy.get(".mx_DecryptionFailureBar .mx_DecryptionFailureBar__header__headline").should(
"have.text",
"Some messages could not be decrypted",
);

checkTimelineNarrow(false); // button should not be rendered here

cy.get(".mx_DecryptionFailureBar").percySnapshotElement(
"DecryptionFailureBar displays general message with no call to action",
{
Expand All @@ -228,14 +263,16 @@ describe("Decryption Failure Bar", () => {
cy.get(".mx_DecryptionFailureBar").should("exist");
cy.get(".mx_DecryptionFailureBar .mx_Spinner").should("exist");

checkTimelineNarrow();

cy.get(".mx_DecryptionFailureBar").percySnapshotElement("DecryptionFailureBar displays loading spinner", {
allowSpinners: true,
widths: [320, 640],
});

cy.wait(5000);
cy.get(".mx_DecryptionFailureBar .mx_Spinner").should("not.exist");
cy.get(".mx_DecryptionFailureBar .mx_DecryptionFailureBar_icon").should("exist");
cy.get(".mx_DecryptionFailureBar .mx_DecryptionFailureBar__icon").should("exist");

cy.get(".mx_RoomView_messagePanel").scrollTo("top");
cy.get(".mx_DecryptionFailureBar").should("not.exist");
Expand All @@ -245,5 +282,7 @@ describe("Decryption Failure Bar", () => {

cy.get(".mx_RoomView_messagePanel").scrollTo("bottom");
cy.get(".mx_DecryptionFailureBar").should("exist");

checkTimelineNarrow();
});
});
90 changes: 57 additions & 33 deletions res/css/views/rooms/_DecryptionFailureBar.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -15,46 +15,70 @@ limitations under the License.
*/

.mx_DecryptionFailureBar {
--gap: $spacing-8 $spacing-12;

display: grid;
grid-template-areas:
"indicator header header"
". message message"; /* Empty grid item under grid-area "indicator" */
grid-template-columns: min-content auto auto;
align-items: start;

background-color: $system;
padding: $spacing-12;
margin-left: $spacing-16;
margin-right: $spacing-16;
margin-inline: $spacing-16;
border-radius: 4px;
display: flex;
align-items: flex-start;
gap: $spacing-12;
}
gap: var(--gap);

.mx_DecryptionFailureBar_icon {
width: 24px;
height: 24px;
mask-image: url("$(res)/img/e2e/decryption-failure.svg");
background-color: $e2e-warning-color;
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
}
.mx_DecryptionFailureBar__indicator {
grid-area: indicator;

.mx_DecryptionFailureBar_icon,
.mx_DecryptionFailureBar .mx_Spinner {
flex-shrink: 0;
flex-grow: 0;
}
.mx_Spinner,
.mx_DecryptionFailureBar__icon {
align-self: start;
}

.mx_DecryptionFailureBar_message {
flex-grow: 1;
}
.mx_Spinner {
height: unset; /* Unset height: 100% */
}
}

.mx_DecryptionFailureBar_message_headline {
font-weight: $font-semi-bold;
font-size: $font-16px;
margin-bottom: $spacing-4;
}
.mx_DecryptionFailureBar__icon {
--size: 24px;

.mx_DecryptionFailureBar_message_body {
color: $secondary-content;
}
width: var(--size);
height: var(--size);
mask-image: url("$(res)/img/e2e/decryption-failure.svg");
background-color: $e2e-warning-color;
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
}

.mx_DecryptionFailureBar__header {
grid-area: header;

display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: var(--gap);

.mx_DecryptionFailureBar__header__headline {
font-weight: $font-semi-bold;
font-size: $font-16px;
}

.mx_DecryptionFailureBar__header__buttons {
display: flex;
flex-wrap: wrap; /* Let the buttons wrapped on a narrow column */
gap: var(--gap);
}
}

.mx_DecryptionFailureBar__message {
grid-area: message;

.mx_DecryptionFailureBar_button {
flex-shrink: 0;
white-space: pre-line; /* Break lines at newline characters */
color: $secondary-content;
}
}
70 changes: 46 additions & 24 deletions src/components/views/rooms/DecryptionFailureBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,68 +145,83 @@ export const DecryptionFailureBar: React.FC<IProps> = ({ failures }) => {
store.resetConfirm();
};

const statusIndicator = waiting ? <Spinner /> : <div className="mx_DecryptionFailureBar_icon" />;
const statusIndicator = waiting ? <Spinner /> : <div className="mx_DecryptionFailureBar__icon" />;

let headline: JSX.Element;
let body: JSX.Element;
let message: JSX.Element;
let button = <React.Fragment />;
if (waiting) {
headline = <React.Fragment>{_t("Decrypting messages…")}</React.Fragment>;
body = (
message = (
<React.Fragment>
{_t("Please wait as we try to decrypt your messages. This may take a few moments.")}
</React.Fragment>
);
} else if (needsVerification) {
if (hasOtherVerifiedDevices || hasKeyBackup) {
headline = <React.Fragment>{_t("Verify this device to access all messages")}</React.Fragment>;
body = (
message = (
<React.Fragment>
{_t("This device was unable to decrypt some messages because it has not been verified yet.")}
</React.Fragment>
);
button = (
<AccessibleButton kind="primary" onClick={onVerifyClick}>
<AccessibleButton
className="mx_DecryptionFailureBar__header__buttons__button"
kind="primary"
onClick={onVerifyClick}
data-testid="decryption-failure-bar-button"
>
{_t("Verify")}
</AccessibleButton>
);
} else {
headline = <React.Fragment>{_t("Reset your keys to prevent future decryption errors")}</React.Fragment>;
body = (
message = (
<React.Fragment>
{_t(
"You will not be able to access old undecryptable messages, " +
"You will not be able to access old undecryptable messages,\n" +
"but resetting your keys will allow you to receive new messages.",
)}
</React.Fragment>
);
button = (
<AccessibleButton kind="primary" onClick={onResetClick}>
<AccessibleButton
className="mx_DecryptionFailureBar__header__buttons__button"
kind="primary"
onClick={onResetClick}
data-testid="decryption-failure-bar-button"
>
{_t("Reset")}
</AccessibleButton>
);
}
} else if (hasOtherVerifiedDevices) {
headline = <React.Fragment>{_t("Open another device to load encrypted messages")}</React.Fragment>;
body = (
message = (
<React.Fragment>
{_t(
"This device is requesting decryption keys from your other devices. " +
"This device is requesting decryption keys from your other devices.\n" +
"Opening one of your other devices may speed this up.",
)}
</React.Fragment>
);
button = (
<AccessibleButton kind="primary_outline" onClick={onDeviceListClick}>
<AccessibleButton
className="mx_DecryptionFailureBar__header__buttons__button"
kind="primary_outline"
onClick={onDeviceListClick}
data-testid="decryption-failure-bar-button"
>
{_t("View your device list")}
</AccessibleButton>
);
} else {
headline = <React.Fragment>{_t("Some messages could not be decrypted")}</React.Fragment>;
body = (
message = (
<React.Fragment>
{_t(
"Unfortunately, there are no other verified devices to request decryption keys from. " +
"Unfortunately, there are no other verified devices to request decryption keys from.\n" +
luixxiul marked this conversation as resolved.
Show resolved Hide resolved
"Signing in and verifying other devices may help avoid this situation in the future.",
)}
</React.Fragment>
Expand All @@ -216,23 +231,30 @@ export const DecryptionFailureBar: React.FC<IProps> = ({ failures }) => {
let keyRequestButton = <React.Fragment />;
if (!needsVerification && hasOtherVerifiedDevices && anyUnrequestedSessions) {
keyRequestButton = (
<div className="mx_DecryptionFailureBar_button">
<AccessibleButton kind="primary" onClick={sendKeyRequests}>
{_t("Resend key requests")}
</AccessibleButton>
</div>
<AccessibleButton
className="mx_DecryptionFailureBar__header__buttons__button"
luixxiul marked this conversation as resolved.
Show resolved Hide resolved
kind="primary"
onClick={sendKeyRequests}
data-testid="decryption-failure-bar-button"
>
{_t("Resend key requests")}
</AccessibleButton>
);
}

return (
<div className="mx_DecryptionFailureBar">
{statusIndicator}
<div className="mx_DecryptionFailureBar_message">
<div className="mx_DecryptionFailureBar_message_headline">{headline}</div>
<div className="mx_DecryptionFailureBar_message_body">{body}</div>
<div className="mx_DecryptionFailureBar__indicator" data-testid="decryption-failure-bar-indicator">
{statusIndicator}
</div>
<div className="mx_DecryptionFailureBar__header">
<div className="mx_DecryptionFailureBar__header__headline">{headline}</div>
<div className="mx_DecryptionFailureBar__header__buttons">
{button}
{keyRequestButton}
</div>
</div>
<div className="mx_DecryptionFailureBar_button">{button}</div>
{keyRequestButton}
<div className="mx_DecryptionFailureBar__message">{message}</div>
</div>
);
};
Loading