mirror of https://github.com/vector-im/riot-web
Use semantic headings in user settings - discovery (#10838)
* allow testids in settings sections * use semantic headings in LabsUserSettingsTab * put back margin var * use SettingsTab wrapper * use semantic headings for deactivate acc section * use semantic heading in manage integratios * i18n * use currentColor in warning-triangle svg, update use in RoomStatusBar * use semantic headings for discovery section * test manage integration settings * test deactivate account section display * remove SettingsFieldset margins * threepids styles * remove debug * test discovery email and phonepull/28788/head^2
parent
9211da20f4
commit
9f011b955b
|
@ -160,7 +160,7 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomStatusBar_connectionLostBar img {
|
.mx_RoomStatusBar_connectionLostBar svg {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
Copyright 2019, 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -14,8 +14,16 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_SetIdServer .mx_Field_input {
|
.mx_SetIdServer {
|
||||||
margin-inline-end: var(--SettingsTab_fullWidthField-margin-inline-end);
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: $spacing-8;
|
||||||
|
|
||||||
|
.mx_Field {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_SetIdServer_tooltip {
|
.mx_SetIdServer_tooltip {
|
||||||
|
|
|
@ -15,7 +15,6 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_SettingsFieldset {
|
.mx_SettingsFieldset {
|
||||||
margin: 10px 80px 10px 0;
|
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,8 +30,6 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_SettingsFieldset_description {
|
.mx_SettingsFieldset_description {
|
||||||
color: $settings-subsection-fg-color;
|
|
||||||
font-size: $font-14px;
|
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
|
|
@ -61,6 +61,8 @@ limitations under the License.
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_GeneralUserSettingsTab_heading_warningIcon {
|
.mx_GeneralUserSettingsTab_warningIcon {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
margin-right: $spacing-8;
|
||||||
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
viewBox="0 0 14 12" style="enable-background:new 0 0 14 12;" xml:space="preserve">
|
viewBox="0 0 14 12" style="enable-background:new 0 0 14 12;" xml:space="preserve">
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
.st0{fill:none;stroke:#454545;stroke-linecap:round;stroke-linejoin:round;}
|
.st0{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;}
|
||||||
</style>
|
</style>
|
||||||
<g>
|
<g>
|
||||||
<path class="st0" d="M6,1.5L1.2,9.3c-0.2,0.3-0.2,0.8,0,1.1c0.2,0.3,0.6,0.6,1,0.6h9.7c0.4,0,0.8-0.2,1-0.6c0.2-0.3,0.2-0.8,0-1.1
|
<path class="st0" d="M6,1.5L1.2,9.3c-0.2,0.3-0.2,0.8,0,1.1c0.2,0.3,0.6,0.6,1,0.6h9.7c0.4,0,0.8-0.2,1-0.6c0.2-0.3,0.2-0.8,0-1.1
|
||||||
|
|
Before Width: | Height: | Size: 704 B After Width: | Height: | Size: 709 B |
|
@ -20,6 +20,7 @@ import { SyncState, ISyncStateData } from "matrix-js-sdk/src/sync";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { MatrixError } from "matrix-js-sdk/src/matrix";
|
import { MatrixError } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
|
import { Icon as WarningIcon } from "../../../res/img/feather-customised/warning-triangle.svg";
|
||||||
import { _t, _td } from "../../languageHandler";
|
import { _t, _td } from "../../languageHandler";
|
||||||
import Resend from "../../Resend";
|
import Resend from "../../Resend";
|
||||||
import dis from "../../dispatcher/dispatcher";
|
import dis from "../../dispatcher/dispatcher";
|
||||||
|
@ -279,12 +280,7 @@ export default class RoomStatusBar extends React.PureComponent<IProps, IState> {
|
||||||
<div className="mx_RoomStatusBar">
|
<div className="mx_RoomStatusBar">
|
||||||
<div role="alert">
|
<div role="alert">
|
||||||
<div className="mx_RoomStatusBar_connectionLostBar">
|
<div className="mx_RoomStatusBar_connectionLostBar">
|
||||||
<img
|
<WarningIcon width="24" height="24" />
|
||||||
src={require("../../../res/img/feather-customised/warning-triangle.svg").default}
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
<div>
|
<div>
|
||||||
<div className="mx_RoomStatusBar_connectionLostBar_title">
|
<div className="mx_RoomStatusBar_connectionLostBar_title">
|
||||||
{_t("Connectivity to the server has been lost.")}
|
{_t("Connectivity to the server has been lost.")}
|
||||||
|
|
|
@ -32,6 +32,8 @@ import InlineSpinner from "../elements/InlineSpinner";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
import Field from "../elements/Field";
|
import Field from "../elements/Field";
|
||||||
import QuestionDialog from "../dialogs/QuestionDialog";
|
import QuestionDialog from "../dialogs/QuestionDialog";
|
||||||
|
import SettingsFieldset from "./SettingsFieldset";
|
||||||
|
import { SettingsSubsectionText } from "./shared/SettingsSubsection";
|
||||||
|
|
||||||
// We'll wait up to this long when checking for 3PID bindings on the IS.
|
// We'll wait up to this long when checking for 3PID bindings on the IS.
|
||||||
const REACHABILITY_TIMEOUT = 10000; // ms
|
const REACHABILITY_TIMEOUT = 10000; // ms
|
||||||
|
@ -428,41 +430,41 @@ export default class SetIdServer extends React.Component<IProps, IState> {
|
||||||
discoButtonContent = <InlineSpinner />;
|
discoButtonContent = <InlineSpinner />;
|
||||||
}
|
}
|
||||||
discoSection = (
|
discoSection = (
|
||||||
<div>
|
<>
|
||||||
<span className="mx_SettingsTab_subsectionText">{discoBodyText}</span>
|
<SettingsSubsectionText>{discoBodyText}</SettingsSubsectionText>
|
||||||
<AccessibleButton onClick={this.onDisconnectClicked} kind="danger_sm">
|
<AccessibleButton onClick={this.onDisconnectClicked} kind="danger_sm">
|
||||||
{discoButtonContent}
|
{discoButtonContent}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="mx_SetIdServer" onSubmit={this.checkIdServer}>
|
<SettingsFieldset legend={sectionTitle} description={bodyText}>
|
||||||
<span className="mx_SettingsTab_subheading">{sectionTitle}</span>
|
<form className="mx_SetIdServer" onSubmit={this.checkIdServer}>
|
||||||
<span className="mx_SettingsTab_subsectionText">{bodyText}</span>
|
<Field
|
||||||
<Field
|
label={_t("Enter a new identity server")}
|
||||||
label={_t("Enter a new identity server")}
|
type="text"
|
||||||
type="text"
|
autoComplete="off"
|
||||||
autoComplete="off"
|
placeholder={this.state.defaultIdServer}
|
||||||
placeholder={this.state.defaultIdServer}
|
value={this.state.idServer}
|
||||||
value={this.state.idServer}
|
onChange={this.onIdentityServerChanged}
|
||||||
onChange={this.onIdentityServerChanged}
|
tooltipContent={this.getTooltip()}
|
||||||
tooltipContent={this.getTooltip()}
|
tooltipClassName="mx_SetIdServer_tooltip"
|
||||||
tooltipClassName="mx_SetIdServer_tooltip"
|
disabled={this.state.busy}
|
||||||
disabled={this.state.busy}
|
forceValidity={this.state.error ? false : undefined}
|
||||||
forceValidity={this.state.error ? false : undefined}
|
/>
|
||||||
/>
|
<AccessibleButton
|
||||||
<AccessibleButton
|
type="submit"
|
||||||
type="submit"
|
kind="primary_sm"
|
||||||
kind="primary_sm"
|
onClick={this.checkIdServer}
|
||||||
onClick={this.checkIdServer}
|
disabled={!this.idServerChangeEnabled()}
|
||||||
disabled={!this.idServerChangeEnabled()}
|
>
|
||||||
>
|
{_t("Change")}
|
||||||
{_t("Change")}
|
</AccessibleButton>
|
||||||
</AccessibleButton>
|
{discoSection}
|
||||||
{discoSection}
|
</form>
|
||||||
</form>
|
</SettingsFieldset>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ limitations under the License.
|
||||||
import React, { ReactNode, HTMLAttributes } from "react";
|
import React, { ReactNode, HTMLAttributes } from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
import { SettingsSubsectionText } from "./shared/SettingsSubsection";
|
||||||
|
|
||||||
interface Props extends HTMLAttributes<HTMLFieldSetElement> {
|
interface Props extends HTMLAttributes<HTMLFieldSetElement> {
|
||||||
// section title
|
// section title
|
||||||
legend: string | ReactNode;
|
legend: string | ReactNode;
|
||||||
|
@ -24,7 +26,11 @@ interface Props extends HTMLAttributes<HTMLFieldSetElement> {
|
||||||
const SettingsFieldset: React.FC<Props> = ({ legend, className, children, description, ...rest }) => (
|
const SettingsFieldset: React.FC<Props> = ({ legend, className, children, description, ...rest }) => (
|
||||||
<fieldset {...rest} className={classNames("mx_SettingsFieldset", className)}>
|
<fieldset {...rest} className={classNames("mx_SettingsFieldset", className)}>
|
||||||
<legend className="mx_SettingsFieldset_legend">{legend}</legend>
|
<legend className="mx_SettingsFieldset_legend">{legend}</legend>
|
||||||
{description && <div className="mx_SettingsFieldset_description">{description}</div>}
|
{description && (
|
||||||
|
<div className="mx_SettingsFieldset_description">
|
||||||
|
<SettingsSubsectionText>{description}</SettingsSubsectionText>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{children}
|
{children}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
);
|
);
|
||||||
|
|
|
@ -25,6 +25,8 @@ import { MatrixClientPeg } from "../../../../MatrixClientPeg";
|
||||||
import Modal from "../../../../Modal";
|
import Modal from "../../../../Modal";
|
||||||
import AddThreepid, { Binding } from "../../../../AddThreepid";
|
import AddThreepid, { Binding } from "../../../../AddThreepid";
|
||||||
import ErrorDialog, { extractErrorMessageFromError } from "../../dialogs/ErrorDialog";
|
import ErrorDialog, { extractErrorMessageFromError } from "../../dialogs/ErrorDialog";
|
||||||
|
import SettingsSubsection from "../shared/SettingsSubsection";
|
||||||
|
import InlineSpinner from "../../elements/InlineSpinner";
|
||||||
import AccessibleButton, { ButtonEvent } from "../../elements/AccessibleButton";
|
import AccessibleButton, { ButtonEvent } from "../../elements/AccessibleButton";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -258,23 +260,32 @@ export class EmailAddress extends React.Component<IEmailAddressProps, IEmailAddr
|
||||||
}
|
}
|
||||||
interface IProps {
|
interface IProps {
|
||||||
emails: IThreepid[];
|
emails: IThreepid[];
|
||||||
|
isLoading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class EmailAddresses extends React.Component<IProps> {
|
export default class EmailAddresses extends React.Component<IProps> {
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
let content;
|
let content;
|
||||||
if (this.props.emails.length > 0) {
|
if (this.props.isLoading) {
|
||||||
|
content = <InlineSpinner />;
|
||||||
|
} else if (this.props.emails.length > 0) {
|
||||||
content = this.props.emails.map((e) => {
|
content = this.props.emails.map((e) => {
|
||||||
return <EmailAddress email={e} key={e.address} />;
|
return <EmailAddress email={e} key={e.address} />;
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
content = (
|
|
||||||
<span className="mx_SettingsTab_subsectionText">
|
|
||||||
{_t("Discovery options will appear once you have added an email above.")}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="mx_EmailAddresses">{content}</div>;
|
const hasEmails = !!this.props.emails.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingsSubsection
|
||||||
|
heading={_t("Email addresses")}
|
||||||
|
description={
|
||||||
|
(!hasEmails && _t("Discovery options will appear once you have added an email above.")) || undefined
|
||||||
|
}
|
||||||
|
stretchContent
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
</SettingsSubsection>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ import Modal from "../../../../Modal";
|
||||||
import AddThreepid, { Binding } from "../../../../AddThreepid";
|
import AddThreepid, { Binding } from "../../../../AddThreepid";
|
||||||
import ErrorDialog, { extractErrorMessageFromError } from "../../dialogs/ErrorDialog";
|
import ErrorDialog, { extractErrorMessageFromError } from "../../dialogs/ErrorDialog";
|
||||||
import Field from "../../elements/Field";
|
import Field from "../../elements/Field";
|
||||||
|
import SettingsSubsection from "../shared/SettingsSubsection";
|
||||||
|
import InlineSpinner from "../../elements/InlineSpinner";
|
||||||
import AccessibleButton, { ButtonEvent } from "../../elements/AccessibleButton";
|
import AccessibleButton, { ButtonEvent } from "../../elements/AccessibleButton";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -273,23 +275,32 @@ export class PhoneNumber extends React.Component<IPhoneNumberProps, IPhoneNumber
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
msisdns: IThreepid[];
|
msisdns: IThreepid[];
|
||||||
|
isLoading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class PhoneNumbers extends React.Component<IProps> {
|
export default class PhoneNumbers extends React.Component<IProps> {
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
let content;
|
let content;
|
||||||
if (this.props.msisdns.length > 0) {
|
if (this.props.isLoading) {
|
||||||
|
content = <InlineSpinner />;
|
||||||
|
} else if (this.props.msisdns.length > 0) {
|
||||||
content = this.props.msisdns.map((e) => {
|
content = this.props.msisdns.map((e) => {
|
||||||
return <PhoneNumber msisdn={e} key={e.address} />;
|
return <PhoneNumber msisdn={e} key={e.address} />;
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
content = (
|
|
||||||
<span className="mx_SettingsTab_subsectionText">
|
|
||||||
{_t("Discovery options will appear once you have added a phone number above.")}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="mx_PhoneNumbers">{content}</div>;
|
const description =
|
||||||
|
(!content && _t("Discovery options will appear once you have added a phone number above.")) || undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingsSubsection
|
||||||
|
data-testid="mx_PhoneNumbers"
|
||||||
|
heading={_t("Phone numbers")}
|
||||||
|
description={description}
|
||||||
|
stretchContent
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
</SettingsSubsection>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,14 +47,16 @@ export const SettingsSubsection: React.FC<SettingsSubsectionProps> = ({
|
||||||
<SettingsSubsectionText>{description}</SettingsSubsectionText>
|
<SettingsSubsectionText>{description}</SettingsSubsectionText>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div
|
{!!children && (
|
||||||
className={classNames("mx_SettingsSubsection_content", {
|
<div
|
||||||
mx_SettingsSubsection_contentStretch: !!stretchContent,
|
className={classNames("mx_SettingsSubsection_content", {
|
||||||
mx_SettingsSubsection_noHeading: !heading && !description,
|
mx_SettingsSubsection_contentStretch: !!stretchContent,
|
||||||
})}
|
mx_SettingsSubsection_noHeading: !heading && !description,
|
||||||
>
|
})}
|
||||||
{children}
|
>
|
||||||
</div>
|
{children}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,12 @@ limitations under the License.
|
||||||
|
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types";
|
import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types";
|
||||||
import { IThreepid } from "matrix-js-sdk/src/@types/threepids";
|
import { IThreepid, ThreepidMedium } from "matrix-js-sdk/src/@types/threepids";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { IDelegatedAuthConfig, M_AUTHENTICATION } from "matrix-js-sdk/src/matrix";
|
import { IDelegatedAuthConfig, M_AUTHENTICATION } from "matrix-js-sdk/src/matrix";
|
||||||
import { HTTPError } from "matrix-js-sdk/src/matrix";
|
import { HTTPError } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
|
import { Icon as WarningIcon } from "../../../../../../res/img/feather-customised/warning-triangle.svg";
|
||||||
import { UserFriendlyError, _t } from "../../../../../languageHandler";
|
import { UserFriendlyError, _t } from "../../../../../languageHandler";
|
||||||
import ProfileSettings from "../../ProfileSettings";
|
import ProfileSettings from "../../ProfileSettings";
|
||||||
import * as languageHandler from "../../../../../languageHandler";
|
import * as languageHandler from "../../../../../languageHandler";
|
||||||
|
@ -56,8 +57,9 @@ import ToggleSwitch from "../../../elements/ToggleSwitch";
|
||||||
import { IS_MAC } from "../../../../../Keyboard";
|
import { IS_MAC } from "../../../../../Keyboard";
|
||||||
import SettingsTab from "../SettingsTab";
|
import SettingsTab from "../SettingsTab";
|
||||||
import { SettingsSection } from "../../shared/SettingsSection";
|
import { SettingsSection } from "../../shared/SettingsSection";
|
||||||
import SettingsSubsection from "../../shared/SettingsSubsection";
|
import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection";
|
||||||
import { SettingsSubsectionHeading } from "../../shared/SettingsSubsectionHeading";
|
import { SettingsSubsectionHeading } from "../../shared/SettingsSubsectionHeading";
|
||||||
|
import Heading from "../../../typography/Heading";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
closeSettingsFn: () => void;
|
closeSettingsFn: () => void;
|
||||||
|
@ -194,9 +196,10 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
||||||
);
|
);
|
||||||
logger.warn(e);
|
logger.warn(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
emails: threepids.filter((a) => a.medium === "email"),
|
emails: threepids.filter((a) => a.medium === ThreepidMedium.Email),
|
||||||
msisdns: threepids.filter((a) => a.medium === "msisdn"),
|
msisdns: threepids.filter((a) => a.medium === ThreepidMedium.Phone),
|
||||||
loading3pids: false,
|
loading3pids: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -449,16 +452,16 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
||||||
private renderDiscoverySection(): JSX.Element {
|
private renderDiscoverySection(): JSX.Element {
|
||||||
if (this.state.requiredPolicyInfo.hasTerms) {
|
if (this.state.requiredPolicyInfo.hasTerms) {
|
||||||
const intro = (
|
const intro = (
|
||||||
<span className="mx_SettingsTab_subsectionText">
|
<SettingsSubsectionText>
|
||||||
{_t(
|
{_t(
|
||||||
"Agree to the identity server (%(serverName)s) Terms of Service to " +
|
"Agree to the identity server (%(serverName)s) Terms of Service to " +
|
||||||
"allow yourself to be discoverable by email address or phone number.",
|
"allow yourself to be discoverable by email address or phone number.",
|
||||||
{ serverName: this.state.idServerName },
|
{ serverName: this.state.idServerName },
|
||||||
)}
|
)}
|
||||||
</span>
|
</SettingsSubsectionText>
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
<InlineTermsAgreement
|
<InlineTermsAgreement
|
||||||
policiesAndServicePairs={this.state.requiredPolicyInfo.policiesAndServices}
|
policiesAndServicePairs={this.state.requiredPolicyInfo.policiesAndServices}
|
||||||
agreedUrls={this.state.requiredPolicyInfo.agreedUrls}
|
agreedUrls={this.state.requiredPolicyInfo.agreedUrls}
|
||||||
|
@ -467,29 +470,23 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
||||||
/>
|
/>
|
||||||
{/* has its own heading as it includes the current identity server */}
|
{/* has its own heading as it includes the current identity server */}
|
||||||
<SetIdServer missingTerms={true} />
|
<SetIdServer missingTerms={true} />
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const emails = this.state.loading3pids ? <Spinner /> : <DiscoveryEmailAddresses emails={this.state.emails} />;
|
|
||||||
const msisdns = this.state.loading3pids ? <Spinner /> : <DiscoveryPhoneNumbers msisdns={this.state.msisdns} />;
|
|
||||||
|
|
||||||
const threepidSection = this.state.haveIdServer ? (
|
const threepidSection = this.state.haveIdServer ? (
|
||||||
<>
|
<>
|
||||||
<span className="mx_SettingsTab_subheading">{_t("Email addresses")}</span>
|
<DiscoveryEmailAddresses emails={this.state.emails} isLoading={this.state.loading3pids} />
|
||||||
{emails}
|
<DiscoveryPhoneNumbers msisdns={this.state.msisdns} isLoading={this.state.loading3pids} />
|
||||||
|
|
||||||
<span className="mx_SettingsTab_subheading">{_t("Phone numbers")}</span>
|
|
||||||
{msisdns}
|
|
||||||
</>
|
</>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_SettingsTab_section mx_GeneralUserSettingsTab_section--discovery">
|
<>
|
||||||
{threepidSection}
|
{threepidSection}
|
||||||
{/* has its own heading as it includes the current identity server */}
|
{/* has its own heading as it includes the current identity server */}
|
||||||
<SetIdServer missingTerms={false} />
|
<SetIdServer missingTerms={false} />
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,16 +517,6 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
||||||
const plaf = PlatformPeg.get();
|
const plaf = PlatformPeg.get();
|
||||||
const supportsMultiLanguageSpellCheck = plaf?.supportsSpellCheckSettings();
|
const supportsMultiLanguageSpellCheck = plaf?.supportsSpellCheckSettings();
|
||||||
|
|
||||||
const discoWarning = this.state.requiredPolicyInfo.hasTerms ? (
|
|
||||||
<img
|
|
||||||
className="mx_GeneralUserSettingsTab_heading_warningIcon"
|
|
||||||
src={require("../../../../../../res/img/feather-customised/warning-triangle.svg").default}
|
|
||||||
width="18"
|
|
||||||
height="18"
|
|
||||||
alt={_t("Warning")}
|
|
||||||
/>
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
let accountManagementSection: JSX.Element | undefined;
|
let accountManagementSection: JSX.Element | undefined;
|
||||||
if (SettingsStore.getValue(UIFeature.Deactivate)) {
|
if (SettingsStore.getValue(UIFeature.Deactivate)) {
|
||||||
accountManagementSection = this.renderManagementSection();
|
accountManagementSection = this.renderManagementSection();
|
||||||
|
@ -537,14 +524,23 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
||||||
|
|
||||||
let discoverySection;
|
let discoverySection;
|
||||||
if (SettingsStore.getValue(UIFeature.IdentityServer)) {
|
if (SettingsStore.getValue(UIFeature.IdentityServer)) {
|
||||||
discoverySection = (
|
const discoWarning = this.state.requiredPolicyInfo.hasTerms ? (
|
||||||
<>
|
<WarningIcon
|
||||||
<div className="mx_SettingsTab_heading">
|
className="mx_GeneralUserSettingsTab_warningIcon"
|
||||||
{discoWarning} {_t("Discovery")}
|
width="18"
|
||||||
</div>
|
height="18"
|
||||||
{this.renderDiscoverySection()}
|
// override icon default values
|
||||||
</>
|
aria-hidden={false}
|
||||||
|
aria-label={_t("Warning")}
|
||||||
|
/>
|
||||||
|
) : null;
|
||||||
|
const heading = (
|
||||||
|
<Heading size="h2">
|
||||||
|
{discoWarning}
|
||||||
|
{_t("Discovery")}
|
||||||
|
</Heading>
|
||||||
);
|
);
|
||||||
|
discoverySection = <SettingsSection heading={heading}>{this.renderDiscoverySection()}</SettingsSection>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -14,7 +14,11 @@ exports[`<SettingsFieldset /> renders fieldset with plain text description 1`] =
|
||||||
<div
|
<div
|
||||||
class="mx_SettingsFieldset_description"
|
class="mx_SettingsFieldset_description"
|
||||||
>
|
>
|
||||||
Changes to who can read history.
|
<div
|
||||||
|
class="mx_SettingsSubsection_text"
|
||||||
|
>
|
||||||
|
Changes to who can read history.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
test
|
test
|
||||||
|
@ -37,14 +41,18 @@ exports[`<SettingsFieldset /> renders fieldset with react description 1`] = `
|
||||||
<div
|
<div
|
||||||
class="mx_SettingsFieldset_description"
|
class="mx_SettingsFieldset_description"
|
||||||
>
|
>
|
||||||
<p>
|
<div
|
||||||
Test
|
class="mx_SettingsSubsection_text"
|
||||||
</p>
|
|
||||||
<a
|
|
||||||
href="#test"
|
|
||||||
>
|
>
|
||||||
a link
|
<p>
|
||||||
</a>
|
Test
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
href="#test"
|
||||||
|
>
|
||||||
|
a link
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
test
|
test
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { IRequestTokenResponse } from "matrix-js-sdk/src/client";
|
||||||
import { MatrixError } from "matrix-js-sdk/src/http-api";
|
import { MatrixError } from "matrix-js-sdk/src/http-api";
|
||||||
|
|
||||||
import { UserFriendlyError } from "../../../../../src/languageHandler";
|
import { UserFriendlyError } from "../../../../../src/languageHandler";
|
||||||
import { EmailAddress } from "../../../../../src/components/views/settings/discovery/EmailAddresses";
|
import EmailAddresses, { EmailAddress } from "../../../../../src/components/views/settings/discovery/EmailAddresses";
|
||||||
import { clearAllModals, getMockClientWithEventEmitter } from "../../../../test-utils";
|
import { clearAllModals, getMockClientWithEventEmitter } from "../../../../test-utils";
|
||||||
|
|
||||||
const mockGetAccessToken = jest.fn().mockResolvedValue("getAccessToken");
|
const mockGetAccessToken = jest.fn().mockResolvedValue("getAccessToken");
|
||||||
|
@ -147,3 +147,23 @@ describe("<EmailAddress/>", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("<EmailAddresses />", () => {
|
||||||
|
it("should render a loader while loading", async () => {
|
||||||
|
const { container } = render(<EmailAddresses emails={[emailThreepidFixture]} isLoading={true} />);
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render email addresses", async () => {
|
||||||
|
const { container } = render(<EmailAddresses emails={[emailThreepidFixture]} isLoading={false} />);
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle no email addresses", async () => {
|
||||||
|
const { container } = render(<EmailAddresses emails={[]} isLoading={false} />);
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -18,18 +18,17 @@ import React from "react";
|
||||||
import { render, screen } from "@testing-library/react";
|
import { render, screen } from "@testing-library/react";
|
||||||
import { IThreepid, ThreepidMedium } from "matrix-js-sdk/src/@types/threepids";
|
import { IThreepid, ThreepidMedium } from "matrix-js-sdk/src/@types/threepids";
|
||||||
|
|
||||||
import { PhoneNumber } from "../../../../../src/components/views/settings/discovery/PhoneNumbers";
|
import PhoneNumbers, { PhoneNumber } from "../../../../../src/components/views/settings/discovery/PhoneNumbers";
|
||||||
|
|
||||||
|
const msisdn: IThreepid = {
|
||||||
|
medium: ThreepidMedium.Phone,
|
||||||
|
address: "+441111111111",
|
||||||
|
validated_at: 12345,
|
||||||
|
added_at: 12342,
|
||||||
|
bound: false,
|
||||||
|
};
|
||||||
describe("<PhoneNumber/>", () => {
|
describe("<PhoneNumber/>", () => {
|
||||||
it("should track props.msisdn.bound changes", async () => {
|
it("should track props.msisdn.bound changes", async () => {
|
||||||
const msisdn: IThreepid = {
|
|
||||||
medium: ThreepidMedium.Phone,
|
|
||||||
address: "+441111111111",
|
|
||||||
validated_at: 12345,
|
|
||||||
added_at: 12342,
|
|
||||||
bound: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const { rerender } = render(<PhoneNumber msisdn={msisdn} />);
|
const { rerender } = render(<PhoneNumber msisdn={msisdn} />);
|
||||||
await screen.findByText("Share");
|
await screen.findByText("Share");
|
||||||
|
|
||||||
|
@ -38,3 +37,23 @@ describe("<PhoneNumber/>", () => {
|
||||||
await screen.findByText("Revoke");
|
await screen.findByText("Revoke");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("<PhoneNumbers />", () => {
|
||||||
|
it("should render a loader while loading", async () => {
|
||||||
|
const { container } = render(<PhoneNumbers msisdns={[msisdn]} isLoading={true} />);
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render phone numbers", async () => {
|
||||||
|
const { container } = render(<PhoneNumbers msisdns={[msisdn]} isLoading={false} />);
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle no numbers", async () => {
|
||||||
|
const { container } = render(<PhoneNumbers msisdns={[]} isLoading={false} />);
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`<EmailAddresses /> should handle no email addresses 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsectionHeading"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
|
||||||
|
>
|
||||||
|
Email addresses
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection_description"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection_text"
|
||||||
|
>
|
||||||
|
Discovery options will appear once you have added an email above.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<EmailAddresses /> should render a loader while loading 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsectionHeading"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
|
||||||
|
>
|
||||||
|
Email addresses
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_InlineSpinner"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-label="Loading…"
|
||||||
|
class="mx_InlineSpinner_icon mx_Spinner_icon"
|
||||||
|
style="width: 16px; height: 16px;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<EmailAddresses /> should render email addresses 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsectionHeading"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
|
||||||
|
>
|
||||||
|
Email addresses
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_GeneralUserSettingsTab_section--discovery_existing"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="mx_GeneralUserSettingsTab_section--discovery_existing_address"
|
||||||
|
>
|
||||||
|
foo@bar.com
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="mx_AccessibleButton mx_GeneralUserSettingsTab_section--discovery_existing_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_sm"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
Share
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
|
@ -0,0 +1,101 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`<PhoneNumbers /> should handle no numbers 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection"
|
||||||
|
data-testid="mx_PhoneNumbers"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsectionHeading"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
|
||||||
|
>
|
||||||
|
Phone numbers
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection_description"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection_text"
|
||||||
|
>
|
||||||
|
Discovery options will appear once you have added a phone number above.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<PhoneNumbers /> should render a loader while loading 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection"
|
||||||
|
data-testid="mx_PhoneNumbers"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsectionHeading"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
|
||||||
|
>
|
||||||
|
Phone numbers
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_InlineSpinner"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-label="Loading…"
|
||||||
|
class="mx_InlineSpinner_icon mx_Spinner_icon"
|
||||||
|
style="width: 16px; height: 16px;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<PhoneNumbers /> should render phone numbers 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection"
|
||||||
|
data-testid="mx_PhoneNumbers"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsectionHeading"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
|
||||||
|
>
|
||||||
|
Phone numbers
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_GeneralUserSettingsTab_section--discovery_existing"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="mx_GeneralUserSettingsTab_section--discovery_existing_address"
|
||||||
|
>
|
||||||
|
+
|
||||||
|
+441111111111
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="mx_AccessibleButton mx_GeneralUserSettingsTab_section--discovery_existing_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_sm"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
Revoke
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
|
@ -12,7 +12,11 @@ exports[`<SecurityRoomSettingsTab /> history visibility uses shared as default h
|
||||||
<div
|
<div
|
||||||
class="mx_SettingsFieldset_description"
|
class="mx_SettingsFieldset_description"
|
||||||
>
|
>
|
||||||
Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.
|
<div
|
||||||
|
class="mx_SettingsSubsection_text"
|
||||||
|
>
|
||||||
|
Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label
|
<label
|
||||||
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
|
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
|
||||||
|
|
|
@ -46,7 +46,11 @@ exports[`<SpaceSettingsVisibilityTab /> renders container 1`] = `
|
||||||
<div
|
<div
|
||||||
class="mx_SettingsFieldset_description"
|
class="mx_SettingsFieldset_description"
|
||||||
>
|
>
|
||||||
Decide who can view and join mock-space.
|
<div
|
||||||
|
class="mx_SettingsSubsection_text"
|
||||||
|
>
|
||||||
|
Decide who can view and join mock-space.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label
|
<label
|
||||||
class="mx_StyledRadioButton mx_JoinRuleSettings_radioButton mx_StyledRadioButton_disabled mx_StyledRadioButton_checked"
|
class="mx_StyledRadioButton mx_JoinRuleSettings_radioButton mx_StyledRadioButton_disabled mx_StyledRadioButton_checked"
|
||||||
|
|
Loading…
Reference in New Issue