Improve decryption error UI by consolidating error messages and providing instructions when possible (#9544)

* Improve decryption error UI by consolidating error messages and providing instructions when possible

* Fix TS strict errors

* Rename .scss to .pcss

* Avoid accessing clipboard, Cypress doesn't like it

* Display DecryptionFailureBar alongside other AuxPanel bars

* Add comments

* Add small margin off-screen for visible decryption failures

* Fix some more TS strict errors

* Add unit tests for DecryptionFailureBar

* Add button to resend key requests manually

* Remove references to matrix-js-sdk crypto internals

* Add hysteresis to visible decryption failures

* Add comment

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Add comment

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Don't create empty div if we're not showing resend requests button

* cancel updateSessions on unmount

* Update unit tests

* Fix lint and implicit any

* Simplify visible event bounds checking

* Adjust cypress test descriptions

* Add percy snapshots

* Update src/components/structures/TimelinePanel.tsx

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Add comments on TimelinePanel IState

* comment

* Add names to percy snapshots

* Show Resend Key Requests button when there are sessions that haven't already been requested via this bar

* We no longer request keys from senders

* update i18n

* update expected text in cypress test

* don't download keys ourselves, update device info in response to updates from client

* fix ts strict errors

* visibledecryptionfailures undefined handling

* Fix implicitAny errors

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Faye Duxovni 2022-12-15 12:24:33 -05:00 committed by GitHub
parent b728b27435
commit 4724506320
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1779 additions and 165 deletions

View file

@ -61,6 +61,7 @@ import RoomPreviewBar from "../views/rooms/RoomPreviewBar";
import RoomPreviewCard from "../views/rooms/RoomPreviewCard";
import SearchBar, { SearchScope } from "../views/rooms/SearchBar";
import RoomUpgradeWarningBar from "../views/rooms/RoomUpgradeWarningBar";
import { DecryptionFailureBar } from "../views/rooms/DecryptionFailureBar";
import AuxPanel from "../views/rooms/AuxPanel";
import RoomHeader, { ISearchInfo } from "../views/rooms/RoomHeader";
import { IOOBData, IThreepidInvite } from "../../stores/ThreepidInviteStore";
@ -220,6 +221,8 @@ export interface IRoomState {
threadId?: string;
liveTimeline?: EventTimeline;
narrow: boolean;
// List of undecryptable events currently visible on-screen
visibleDecryptionFailures?: MatrixEvent[];
}
interface LocalRoomViewProps {
@ -412,6 +415,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
timelineRenderingType: TimelineRenderingType.Room,
liveTimeline: undefined,
narrow: false,
visibleDecryptionFailures: [],
};
this.dispatcherRef = dis.register(this.onAction);
@ -1166,6 +1170,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
private onEventDecrypted = (ev: MatrixEvent) => {
if (!this.state.room || !this.state.matrixClientIsReady) return; // not ready at all
if (ev.getRoomId() !== this.state.room.roomId) return; // not for us
this.updateVisibleDecryptionFailures();
if (ev.isDecryptionFailure()) return;
this.handleEffects(ev);
};
@ -1470,7 +1475,21 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}
};
private onMessageListScroll = (ev) => {
private updateVisibleDecryptionFailures = throttle(
() =>
this.setState((prevState) => ({
visibleDecryptionFailures:
this.messagePanel?.getVisibleDecryptionFailures(
// If there were visible failures last time we checked,
// add a margin to provide hysteresis and prevent flickering
(prevState.visibleDecryptionFailures?.length ?? 0) > 0,
) ?? [],
})),
500,
{ leading: false, trailing: true },
);
private onMessageListScroll = () => {
if (this.messagePanel.isAtEndOfLiveTimeline()) {
this.setState({
numUnreadMessages: 0,
@ -1482,6 +1501,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
});
}
this.updateTopUnreadMessagesBar();
this.updateVisibleDecryptionFailures();
};
private resetJumpToEvent = (eventId?: string) => {
@ -2028,7 +2048,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
const hiddenHighlightCount = this.getHiddenHighlightCount();
let aux = null;
let aux: JSX.Element | undefined;
let previewBar;
if (this.state.timelineRenderingType === TimelineRenderingType.Search) {
aux = (
@ -2079,6 +2099,11 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
);
}
let decryptionFailureBar: JSX.Element | undefined;
if (this.state.visibleDecryptionFailures && this.state.visibleDecryptionFailures.length > 0) {
decryptionFailureBar = <DecryptionFailureBar failures={this.state.visibleDecryptionFailures} />;
}
if (this.state.room?.isSpaceRoom() && !this.props.forceTimeline) {
return (
<SpaceRoomView
@ -2103,6 +2128,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
resizeNotifier={this.props.resizeNotifier}
>
{aux}
{decryptionFailureBar}
</AuxPanel>
);