use Compound and make comments into doc comments

pull/28211/head
Hubert Chathi 2024-10-21 16:47:58 -04:00
parent 6fa98f8683
commit 9f2c1a1098
2 changed files with 87 additions and 65 deletions

View File

@ -6,18 +6,20 @@ Please see LICENSE files in the repository root for full details.
*/ */
.mx_UserIdentityWarning { .mx_UserIdentityWarning {
border-top: 1px solid $separator; /* 42px is the padding-left of .mx_MessageComposer_wrapper in res/css/views/rooms/_MessageComposer.pcss */
padding-top: 5px;
margin-left: calc(-42px + var(--RoomView_MessageList-padding)); margin-left: calc(-42px + var(--RoomView_MessageList-padding));
display: flex;
align-items: center;
.mx_BaseAvatar { .mx_UserIdentityWarning_row {
margin-left: 8px; display: flex;
} align-items: center;
.mx_UserIdentityWarning_main {
margin-left: 24px; .mx_BaseAvatar {
flex-grow: 1; margin-left: var(--cpd-space-2x);
}
.mx_UserIdentityWarning_main {
margin-left: var(--cpd-space-6x);
flex-grow: 1;
}
} }
} }

View File

@ -16,25 +16,31 @@ import {
RoomMember, RoomMember,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { Button, Separator } from "@vector-im/compound-web";
import type { CryptoApi, UserVerificationStatus } from "matrix-js-sdk/src/crypto-api"; import type { CryptoApi, UserVerificationStatus } from "matrix-js-sdk/src/crypto-api";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import MemberAvatar from "../avatars/MemberAvatar"; import MemberAvatar from "../avatars/MemberAvatar";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { SDKContext } from "../../../contexts/SDKContext"; import { SDKContext } from "../../../contexts/SDKContext";
interface IProps { interface UserIdentityWarningProps {
// The current room being viewed. /**
* The current room being viewed.
*/
room: Room; room: Room;
} }
interface IState { interface UserIdentityWarningState {
// The current room member that we are prompting the user to approve. /**
* The current room member that we are prompting the user to approve.
*/
currentPrompt: RoomMember | undefined; currentPrompt: RoomMember | undefined;
} }
// Does the given user's identity need to be approved? /**
* Does the given user's identity need to be approved?
*/
async function userNeedsApproval(crypto: CryptoApi, userId: string): Promise<boolean> { async function userNeedsApproval(crypto: CryptoApi, userId: string): Promise<boolean> {
const verificationStatus = await crypto.getUserVerificationStatus(userId); const verificationStatus = await crypto.getUserVerificationStatus(userId);
return verificationStatus.needsUserApproval; return verificationStatus.needsUserApproval;
@ -46,26 +52,30 @@ async function userNeedsApproval(crypto: CryptoApi, userId: string): Promise<boo
* Warns when an unverified user's identity has changed, and gives the user a * Warns when an unverified user's identity has changed, and gives the user a
* button to acknowledge the change. * button to acknowledge the change.
*/ */
export default class UserIdentityWarning extends React.Component<IProps, IState> { export default class UserIdentityWarning extends React.Component<UserIdentityWarningProps, UserIdentityWarningState> {
// Which room members need their identity approved. /**
* Which room members need their identity approved.
*/
private membersNeedingApproval: Map<string, RoomMember>; private membersNeedingApproval: Map<string, RoomMember>;
// Whether we got a verification status update while we were fetching a /**
// user's verification status. * Whether we got a verification status update while we were fetching a
// * user's verification status.
// We set the entry for a user to `false` when we fetch a user's *
// verification status, and remove the user's entry when we are done * We set the entry for a user to `false` when we fetch a user's
// fetching. When we receive a verification status update, if the entry for * verification status, and remove the user's entry when we are done
// the user is `false`, we set it to `true`. After we have finished * fetching. When we receive a verification status update, if the entry for
// fetching the user's verification status, if the entry for the user is * the user is `false`, we set it to `true`. After we have finished
// `true`, rather than `false`, we know that we got an update, and so we * fetching the user's verification status, if the entry for the user is
// discard the value that we fetched. We always use the value from the * `true`, rather than `false`, we know that we got an update, and so we
// update and consider it as the most up-to-date version. If the fetched * discard the value that we fetched. We always use the value from the
// value is more up-to-date, then we should be getting a new update soon * update and consider it as the most up-to-date version. If the fetched
// with the newer value, so it will fix itself in the end. * value is more up-to-date, then we should be getting a new update soon
* with the newer value, so it will fix itself in the end.
*/
private gotVerificationStatusUpdate: Map<string, boolean>; private gotVerificationStatusUpdate: Map<string, boolean>;
private mounted: boolean; private mounted: boolean;
private initialised: boolean; private initialised: boolean;
public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) { public constructor(props: UserIdentityWarningProps, context: React.ContextType<typeof SDKContext>) {
super(props, context); super(props, context);
this.state = { this.state = {
currentPrompt: undefined, currentPrompt: undefined,
@ -91,8 +101,10 @@ export default class UserIdentityWarning extends React.Component<IProps, IState>
this.removeListeners(); this.removeListeners();
} }
// Select a new user to display a warning for. This is called after the /**
// current prompted user no longer needs their identity approved. * Select a new user to display a warning for. This is called after the
* current prompted user no longer needs their identity approved.
*/
private selectCurrentPrompt(): void { private selectCurrentPrompt(): void {
if (this.membersNeedingApproval.size === 0) { if (this.membersNeedingApproval.size === 0) {
this.setState({ this.setState({
@ -107,8 +119,10 @@ export default class UserIdentityWarning extends React.Component<IProps, IState>
}); });
} }
// Initialise the component. Get the room members, check which ones need /**
// their identity approved, and pick one to display. * Initialise the component. Get the room members, check which ones need
* their identity approved, and pick one to display.
*/
public async initialise(): Promise<void> { public async initialise(): Promise<void> {
if (!this.mounted || this.initialised) { if (!this.mounted || this.initialised) {
return; return;
@ -186,11 +200,12 @@ export default class UserIdentityWarning extends React.Component<IProps, IState>
} }
} }
/**
* Handle a change in user trust. If the user's identity now needs
* approval, make sure that a warning is shown. If the user's identity
* doesn't need approval, remove the warning (if any).
*/
private onUserTrustStatusChanged = (userId: string, verificationStatus: UserVerificationStatus): void => { private onUserTrustStatusChanged = (userId: string, verificationStatus: UserVerificationStatus): void => {
// Handle a change in user trust. If the user's identity now needs
// approval, make sure that a warning is shown. If the user's identity
// doesn't need approval, remove the warning (if any).
if (!this.initialised) { if (!this.initialised) {
return; return;
} }
@ -258,8 +273,10 @@ export default class UserIdentityWarning extends React.Component<IProps, IState>
} }
}; };
// Callback for when the user hits the "OK" button /**
public confirmIdentity = async (ev: ButtonEvent): Promise<void> => { * Callback for when the user hits the "OK" button.
*/
public confirmIdentity = async (): Promise<void> => {
if (this.state.currentPrompt) { if (this.state.currentPrompt) {
await MatrixClientPeg.safeGet().getCrypto()!.pinCurrentUserIdentity(this.state.currentPrompt.userId); await MatrixClientPeg.safeGet().getCrypto()!.pinCurrentUserIdentity(this.state.currentPrompt.userId);
} }
@ -276,29 +293,32 @@ export default class UserIdentityWarning extends React.Component<IProps, IState>
const substituteBTag = (sub: string): React.ReactNode => <b>{sub}</b>; const substituteBTag = (sub: string): React.ReactNode => <b>{sub}</b>;
return ( return (
<div className="mx_UserIdentityWarning"> <div className="mx_UserIdentityWarning">
<MemberAvatar member={currentPrompt} title={currentPrompt.userId} size="30px" /> <Separator />
<span className="mx_UserIdentityWarning_main"> <div className = "mx_UserIdentityWarning_row">
{currentPrompt.rawDisplayName === currentPrompt.userId <MemberAvatar member={currentPrompt} title={currentPrompt.userId} size="30px" />
? _t( <span className="mx_UserIdentityWarning_main">
"encryption|pinned_identity_changed_no_displayname", {currentPrompt.rawDisplayName === currentPrompt.userId
{ userId: currentPrompt.userId }, ? _t(
{ "encryption|pinned_identity_changed_no_displayname",
a: substituteATag, { userId: currentPrompt.userId },
b: substituteBTag, {
}, a: substituteATag,
) b: substituteBTag,
: _t( },
"encryption|pinned_identity_changed", )
{ displayName: currentPrompt.rawDisplayName, userId: currentPrompt.userId }, : _t(
{ "encryption|pinned_identity_changed",
a: substituteATag, { displayName: currentPrompt.rawDisplayName, userId: currentPrompt.userId },
b: substituteBTag, {
}, a: substituteATag,
)} b: substituteBTag,
</span> },
<AccessibleButton kind="primary" onClick={this.confirmIdentity}> )}
{_t("action|ok")} </span>
</AccessibleButton> <Button kind="primary" size="sm" onClick={this.confirmIdentity}>
{_t("action|ok")}
</Button>
</div>
</div> </div>
); );
} else { } else {