Merge branch 'develop' into sort-imports
Signed-off-by: Aaron Raimist <aaron@raim.ist>
This commit is contained in:
commit
7b94e13a84
642 changed files with 30052 additions and 8035 deletions
|
@ -25,7 +25,7 @@ import { _t } from '../../../languageHandler';
|
|||
import BaseDialog from "./BaseDialog";
|
||||
import Dropdown from "../elements/Dropdown";
|
||||
import SearchBox from "../../structures/SearchBox";
|
||||
import SpaceStore from "../../../stores/SpaceStore";
|
||||
import SpaceStore from "../../../stores/spaces/SpaceStore";
|
||||
import RoomAvatar from "../avatars/RoomAvatar";
|
||||
import { getDisplayAliasForRoom } from "../../../Rooms";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
|
|
109
src/components/views/dialogs/AnalyticsLearnMoreDialog.tsx
Normal file
109
src/components/views/dialogs/AnalyticsLearnMoreDialog.tsx
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
Copyright 2021 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 BaseDialog from "./BaseDialog";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import DialogButtons from "../elements/DialogButtons";
|
||||
import React from "react";
|
||||
import Modal from "../../../Modal";
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
|
||||
export enum ButtonClicked {
|
||||
Primary,
|
||||
Cancel,
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
onFinished?(buttonClicked?: ButtonClicked): void;
|
||||
analyticsOwner: string;
|
||||
privacyPolicyUrl?: string;
|
||||
primaryButton?: string;
|
||||
cancelButton?: string;
|
||||
hasCancel?: boolean;
|
||||
}
|
||||
|
||||
const AnalyticsLearnMoreDialog: React.FC<IProps> = ({
|
||||
onFinished,
|
||||
analyticsOwner,
|
||||
privacyPolicyUrl,
|
||||
primaryButton,
|
||||
cancelButton,
|
||||
hasCancel,
|
||||
}) => {
|
||||
const onPrimaryButtonClick = () => onFinished && onFinished(ButtonClicked.Primary);
|
||||
const onCancelButtonClick = () => onFinished && onFinished(ButtonClicked.Cancel);
|
||||
const privacyPolicyLink = privacyPolicyUrl ?
|
||||
<span>
|
||||
{
|
||||
_t("You can read all our terms <PrivacyPolicyUrl>here</PrivacyPolicyUrl>", {}, {
|
||||
"PrivacyPolicyUrl": (sub) => {
|
||||
return <a href={privacyPolicyUrl}
|
||||
rel="norefferer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
{ sub }
|
||||
<span className="mx_AnalyticsPolicyLink" />
|
||||
</a>;
|
||||
},
|
||||
})
|
||||
}
|
||||
</span> : "";
|
||||
return <BaseDialog
|
||||
className="mx_AnalyticsLearnMoreDialog"
|
||||
contentId="mx_AnalyticsLearnMore"
|
||||
title={_t("Help improve %(analyticsOwner)s", { analyticsOwner })}
|
||||
onFinished={onFinished}
|
||||
>
|
||||
<div className="mx_Dialog_content">
|
||||
<div className="mx_AnalyticsLearnMore_image_holder" />
|
||||
<div className="mx_AnalyticsLearnMore_copy">
|
||||
{ _t("Help us identify issues and improve Element by sharing anonymous usage data. " +
|
||||
"To understand how people use multiple devices, we'll generate a random identifier, " +
|
||||
"shared by your devices.",
|
||||
) }
|
||||
</div>
|
||||
<ul className="mx_AnalyticsLearnMore_bullets">
|
||||
<li>{ _t("We <Bold>don't</Bold> record or profile any account data",
|
||||
{}, { "Bold": (sub) => <b>{ sub }</b> }) }</li>
|
||||
<li>{ _t("We <Bold>don't</Bold> share information with third parties",
|
||||
{}, { "Bold": (sub) => <b>{ sub }</b> }) }</li>
|
||||
<li>{ _t("You can turn this off anytime in settings") }</li>
|
||||
</ul>
|
||||
{ privacyPolicyLink }
|
||||
</div>
|
||||
<DialogButtons
|
||||
primaryButton={primaryButton}
|
||||
cancelButton={cancelButton}
|
||||
onPrimaryButtonClick={onPrimaryButtonClick}
|
||||
onCancel={onCancelButtonClick}
|
||||
hasCancel={hasCancel}
|
||||
/>
|
||||
</BaseDialog>;
|
||||
};
|
||||
|
||||
export const showDialog = (props: Omit<IProps, "cookiePolicyUrl" | "analyticsOwner">): void => {
|
||||
const privacyPolicyUrl = SdkConfig.get().piwik?.policyUrl;
|
||||
const analyticsOwner = SdkConfig.get().analyticsOwner ?? SdkConfig.get().brand;
|
||||
Modal.createTrackedDialog(
|
||||
"Analytics Learn More",
|
||||
"",
|
||||
AnalyticsLearnMoreDialog,
|
||||
{ privacyPolicyUrl, analyticsOwner, ...props },
|
||||
"mx_AnalyticsLearnMoreDialog_wrapper",
|
||||
);
|
||||
};
|
||||
|
||||
export default AnalyticsLearnMoreDialog;
|
|
@ -15,10 +15,10 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React, { ComponentProps, useMemo, useState } from 'react';
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
|
||||
import ConfirmUserActionDialog from "./ConfirmUserActionDialog";
|
||||
import SpaceStore from "../../../stores/SpaceStore";
|
||||
import SpaceStore from "../../../stores/spaces/SpaceStore";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import SpaceChildrenPicker from "../spaces/SpaceChildrenPicker";
|
||||
|
||||
type BaseProps = ComponentProps<typeof ConfirmUserActionDialog>;
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { ChangeEvent, ReactNode } from 'react';
|
||||
import React, { ChangeEvent, FormEvent, ReactNode } from 'react';
|
||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||
import classNames from "classnames";
|
||||
|
@ -76,7 +76,8 @@ export default class ConfirmUserActionDialog extends React.Component<IProps, ISt
|
|||
};
|
||||
}
|
||||
|
||||
private onOk = (): void => {
|
||||
private onOk = (ev: FormEvent): void => {
|
||||
ev.preventDefault();
|
||||
this.props.onFinished(true, this.state.reason);
|
||||
};
|
||||
|
||||
|
@ -144,7 +145,8 @@ export default class ConfirmUserActionDialog extends React.Component<IProps, ISt
|
|||
{ reasonBox }
|
||||
{ this.props.children }
|
||||
</div>
|
||||
<DialogButtons primaryButton={this.props.action}
|
||||
<DialogButtons
|
||||
primaryButton={this.props.action}
|
||||
onPrimaryButtonClick={this.onOk}
|
||||
primaryButtonClass={confirmButtonClass}
|
||||
focus={!this.props.askReason}
|
||||
|
|
|
@ -25,6 +25,7 @@ import AccessibleButton from "../elements/AccessibleButton";
|
|||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import InfoTooltip from "../elements/InfoTooltip";
|
||||
import dis from "../../../dispatcher/dispatcher";
|
||||
import { Action } from '../../../dispatcher/actions';
|
||||
import { showCommunityRoomInviteDialog } from "../../../RoomInvite";
|
||||
import GroupStore from "../../../stores/GroupStore";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
|
@ -100,7 +101,7 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
|
|||
// Force the group store to update as it might have missed the general chat
|
||||
await GroupStore.refreshGroupRooms(result.group_id);
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
action: Action.ViewRoom,
|
||||
room_id: result.room_id,
|
||||
});
|
||||
showCommunityRoomInviteDialog(result.room_id, this.state.name);
|
||||
|
|
|
@ -32,7 +32,7 @@ import RoomAliasField from "../elements/RoomAliasField";
|
|||
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
|
||||
import DialogButtons from "../elements/DialogButtons";
|
||||
import BaseDialog from "../dialogs/BaseDialog";
|
||||
import SpaceStore from "../../../stores/SpaceStore";
|
||||
import SpaceStore from "../../../stores/spaces/SpaceStore";
|
||||
import JoinRuleDropdown from "../elements/JoinRuleDropdown";
|
||||
|
||||
interface IProps {
|
||||
|
@ -284,7 +284,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
|
|||
let microcopy;
|
||||
if (privateShouldBeEncrypted()) {
|
||||
if (this.state.canChangeEncryption) {
|
||||
microcopy = _t("You can’t disable this later. Bridges & most bots won’t work yet.");
|
||||
microcopy = _t("You can't disable this later. Bridges & most bots won't work yet.");
|
||||
} else {
|
||||
microcopy = _t("Your server requires encryption to be enabled in private rooms.");
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ import { calculateRoomVia, makeRoomPermalink } from "../../../utils/permalinks/P
|
|||
import { useAsyncMemo } from "../../../hooks/useAsyncMemo";
|
||||
import Spinner from "../elements/Spinner";
|
||||
import { mediaFromMxc } from "../../../customisations/Media";
|
||||
import SpaceStore from "../../../stores/SpaceStore";
|
||||
import SpaceStore from "../../../stores/spaces/SpaceStore";
|
||||
import Modal from "../../../Modal";
|
||||
import InfoDialog from "./InfoDialog";
|
||||
import dis from "../../../dispatcher/dispatcher";
|
||||
|
|
|
@ -26,7 +26,7 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
|||
import { BetaPill } from "../beta/BetaCard";
|
||||
import Field from "../elements/Field";
|
||||
import RoomAliasField from "../elements/RoomAliasField";
|
||||
import SpaceStore from "../../../stores/SpaceStore";
|
||||
import SpaceStore from "../../../stores/spaces/SpaceStore";
|
||||
import { createSpace, SpaceCreateForm } from "../spaces/SpaceCreateMenu";
|
||||
import { SubspaceSelector } from "./AddExistingToSpaceDialog";
|
||||
import JoinRuleDropdown from "../elements/JoinRuleDropdown";
|
||||
|
|
103
src/components/views/dialogs/EndPollDialog.tsx
Normal file
103
src/components/views/dialogs/EndPollDialog.tsx
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
Copyright 2021 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 React from "react";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { Relations } from "matrix-js-sdk/src/models/relations";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { IDialogProps } from "./IDialogProps";
|
||||
import QuestionDialog from "./QuestionDialog";
|
||||
import { IPollEndContent, POLL_END_EVENT_TYPE, TEXT_NODE_TYPE } from "../../../polls/consts";
|
||||
import { findTopAnswer } from "../messages/MPollBody";
|
||||
import Modal from "../../../Modal";
|
||||
import ErrorDialog from "./ErrorDialog";
|
||||
|
||||
interface IProps extends IDialogProps {
|
||||
matrixClient: MatrixClient;
|
||||
event: MatrixEvent;
|
||||
onFinished: (success: boolean) => void;
|
||||
getRelationsForEvent?: (
|
||||
eventId: string,
|
||||
relationType: string,
|
||||
eventType: string
|
||||
) => Relations;
|
||||
}
|
||||
|
||||
export default class EndPollDialog extends React.Component<IProps> {
|
||||
private onFinished = (endPoll: boolean) => {
|
||||
const topAnswer = findTopAnswer(
|
||||
this.props.event,
|
||||
this.props.matrixClient,
|
||||
this.props.getRelationsForEvent,
|
||||
);
|
||||
|
||||
const message = (
|
||||
(topAnswer === "")
|
||||
? _t("The poll has ended. No votes were cast.")
|
||||
: _t(
|
||||
"The poll has ended. Top answer: %(topAnswer)s",
|
||||
{ topAnswer },
|
||||
)
|
||||
);
|
||||
|
||||
if (endPoll) {
|
||||
const endContent: IPollEndContent = {
|
||||
[POLL_END_EVENT_TYPE.name]: {},
|
||||
"m.relates_to": {
|
||||
"event_id": this.props.event.getId(),
|
||||
"rel_type": "m.reference",
|
||||
},
|
||||
[TEXT_NODE_TYPE.name]: message,
|
||||
};
|
||||
|
||||
this.props.matrixClient.sendEvent(
|
||||
this.props.event.getRoomId(), POLL_END_EVENT_TYPE.name, endContent,
|
||||
).catch((e: any) => {
|
||||
console.error("Failed to submit poll response event:", e);
|
||||
Modal.createTrackedDialog(
|
||||
'Failed to end poll',
|
||||
'',
|
||||
ErrorDialog,
|
||||
{
|
||||
title: _t("Failed to end poll"),
|
||||
description: _t(
|
||||
"Sorry, the poll did not end. Please try again."),
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
this.props.onFinished(endPoll);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<QuestionDialog
|
||||
title={_t("End Poll")}
|
||||
description={
|
||||
_t(
|
||||
"Are you sure you want to end this poll? " +
|
||||
"This will show the final results of the poll and " +
|
||||
"stop people from being able to vote.",
|
||||
)
|
||||
}
|
||||
button={_t("End Poll")}
|
||||
onFinished={(endPoll: boolean) => this.onFinished(endPoll)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -14,8 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import QuestionDialog from './QuestionDialog';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import Field from "../elements/Field";
|
||||
|
@ -27,6 +26,9 @@ import BugReportDialog from "./BugReportDialog";
|
|||
import InfoDialog from "./InfoDialog";
|
||||
import StyledRadioGroup from "../elements/StyledRadioGroup";
|
||||
import { IDialogProps } from "./IDialogProps";
|
||||
import { submitFeedback } from "../../../rageshake/submit-rageshake";
|
||||
import { useStateToggle } from "../../../hooks/useStateToggle";
|
||||
import StyledCheckbox from "../elements/StyledCheckbox";
|
||||
|
||||
const existingIssuesUrl = "https://github.com/vector-im/element-web/issues" +
|
||||
"?q=is%3Aopen+is%3Aissue+sort%3Areactions-%2B1-desc";
|
||||
|
@ -35,18 +37,33 @@ const newIssueUrl = "https://github.com/vector-im/element-web/issues/new/choose"
|
|||
interface IProps extends IDialogProps {}
|
||||
|
||||
const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
||||
const feedbackRef = useRef<Field>();
|
||||
const [rating, setRating] = useState<Rating>();
|
||||
const [comment, setComment] = useState<string>("");
|
||||
const [canContact, toggleCanContact] = useStateToggle(false);
|
||||
|
||||
useEffect(() => {
|
||||
// autofocus doesn't work on textareas
|
||||
feedbackRef.current?.focus();
|
||||
}, []);
|
||||
|
||||
const onDebugLogsLinkClick = (): void => {
|
||||
props.onFinished();
|
||||
Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {});
|
||||
};
|
||||
|
||||
const hasFeedback = CountlyAnalytics.instance.canEnable();
|
||||
const countlyEnabled = CountlyAnalytics.instance.canEnable();
|
||||
const rageshakeUrl = SdkConfig.get().bug_report_endpoint_url;
|
||||
|
||||
const hasFeedback = countlyEnabled || rageshakeUrl;
|
||||
const onFinished = (sendFeedback: boolean): void => {
|
||||
if (hasFeedback && sendFeedback) {
|
||||
CountlyAnalytics.instance.reportFeedback(rating, comment);
|
||||
if (rageshakeUrl) {
|
||||
submitFeedback(rageshakeUrl, "feedback", comment, canContact);
|
||||
} else if (countlyEnabled) {
|
||||
CountlyAnalytics.instance.reportFeedback(rating, comment);
|
||||
}
|
||||
|
||||
Modal.createTrackedDialog('Feedback sent', '', InfoDialog, {
|
||||
title: _t('Feedback sent'),
|
||||
description: _t('Thank you!'),
|
||||
|
@ -57,56 +74,73 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
|||
|
||||
const brand = SdkConfig.get().brand;
|
||||
|
||||
let countlyFeedbackSection;
|
||||
if (hasFeedback) {
|
||||
countlyFeedbackSection = <React.Fragment>
|
||||
<hr />
|
||||
<div className="mx_FeedbackDialog_section mx_FeedbackDialog_rateApp">
|
||||
<h3>{ _t("Rate %(brand)s", { brand }) }</h3>
|
||||
let feedbackSection;
|
||||
if (rageshakeUrl) {
|
||||
feedbackSection = <div className="mx_FeedbackDialog_section mx_FeedbackDialog_rateApp">
|
||||
<h3>{ _t("Comment") }</h3>
|
||||
|
||||
<p>{ _t("Tell us below how you feel about %(brand)s so far.", { brand }) }</p>
|
||||
<p>{ _t("Please go into as much detail as you like, so we can track down the problem.") }</p>
|
||||
<p>{ _t("Your platform and username will be noted to help us use your feedback as much as we can.") }</p>
|
||||
|
||||
<StyledRadioGroup
|
||||
name="feedbackRating"
|
||||
value={String(rating)}
|
||||
onChange={(r) => setRating(parseInt(r, 10) as Rating)}
|
||||
definitions={[
|
||||
{ value: "1", label: "😠" },
|
||||
{ value: "2", label: "😞" },
|
||||
{ value: "3", label: "😑" },
|
||||
{ value: "4", label: "😄" },
|
||||
{ value: "5", label: "😍" },
|
||||
]}
|
||||
/>
|
||||
<Field
|
||||
id="feedbackComment"
|
||||
label={_t("Feedback")}
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
value={comment}
|
||||
element="textarea"
|
||||
onChange={(ev) => {
|
||||
setComment(ev.target.value);
|
||||
}}
|
||||
ref={feedbackRef}
|
||||
/>
|
||||
|
||||
<Field
|
||||
id="feedbackComment"
|
||||
label={_t("Add comment")}
|
||||
placeholder={_t("Comment")}
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
value={comment}
|
||||
element="textarea"
|
||||
onChange={(ev) => {
|
||||
setComment(ev.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>;
|
||||
}
|
||||
<StyledCheckbox
|
||||
checked={canContact}
|
||||
onChange={toggleCanContact}
|
||||
>
|
||||
{ _t("You may contact me if you want to follow up or to let me test out upcoming ideas") }
|
||||
</StyledCheckbox>
|
||||
</div>;
|
||||
} else if (countlyEnabled) {
|
||||
feedbackSection = <div className="mx_FeedbackDialog_section mx_FeedbackDialog_rateApp">
|
||||
<h3>{ _t("Rate %(brand)s", { brand }) }</h3>
|
||||
|
||||
let subheading;
|
||||
if (hasFeedback) {
|
||||
subheading = (
|
||||
<h2>{ _t("There are two ways you can provide feedback and help us improve %(brand)s.", { brand }) }</h2>
|
||||
);
|
||||
<p>{ _t("Tell us below how you feel about %(brand)s so far.", { brand }) }</p>
|
||||
<p>{ _t("Please go into as much detail as you like, so we can track down the problem.") }</p>
|
||||
|
||||
<StyledRadioGroup
|
||||
name="feedbackRating"
|
||||
value={String(rating)}
|
||||
onChange={(r) => setRating(parseInt(r, 10) as Rating)}
|
||||
definitions={[
|
||||
{ value: "1", label: "😠" },
|
||||
{ value: "2", label: "😞" },
|
||||
{ value: "3", label: "😑" },
|
||||
{ value: "4", label: "😄" },
|
||||
{ value: "5", label: "😍" },
|
||||
]}
|
||||
/>
|
||||
|
||||
<Field
|
||||
id="feedbackComment"
|
||||
label={_t("Add comment")}
|
||||
placeholder={_t("Comment")}
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
value={comment}
|
||||
element="textarea"
|
||||
onChange={(ev) => {
|
||||
setComment(ev.target.value);
|
||||
}}
|
||||
ref={feedbackRef}
|
||||
/>
|
||||
</div>;
|
||||
}
|
||||
|
||||
let bugReports = null;
|
||||
if (SdkConfig.get().bug_report_endpoint_url) {
|
||||
if (rageshakeUrl) {
|
||||
bugReports = (
|
||||
<p>{
|
||||
<p className="mx_FeedbackDialog_section_microcopy">{
|
||||
_t("PRO TIP: If you start a bug, please submit <debugLogsLink>debug logs</debugLogsLink> " +
|
||||
"to help us track down the problem.", {}, {
|
||||
debugLogsLink: sub => (
|
||||
|
@ -122,8 +156,6 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
|||
hasCancelButton={!!hasFeedback}
|
||||
title={_t("Feedback")}
|
||||
description={<React.Fragment>
|
||||
{ subheading }
|
||||
|
||||
<div className="mx_FeedbackDialog_section mx_FeedbackDialog_reportBug">
|
||||
<h3>{ _t("Report a bug") }</h3>
|
||||
<p>{
|
||||
|
@ -139,10 +171,10 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
|||
}</p>
|
||||
{ bugReports }
|
||||
</div>
|
||||
{ countlyFeedbackSection }
|
||||
{ feedbackSection }
|
||||
</React.Fragment>}
|
||||
button={hasFeedback ? _t("Send feedback") : _t("Go back")}
|
||||
buttonDisabled={hasFeedback && !rating}
|
||||
buttonDisabled={hasFeedback && !rating && !comment}
|
||||
onFinished={onFinished}
|
||||
/>);
|
||||
};
|
||||
|
|
|
@ -25,7 +25,7 @@ import { _t } from "../../../languageHandler";
|
|||
import dis from "../../../dispatcher/dispatcher";
|
||||
import { useSettingValue, useFeatureEnabled } from "../../../hooks/useSettings";
|
||||
import { UIFeature } from "../../../settings/UIFeature";
|
||||
import { Layout } from "../../../settings/Layout";
|
||||
import { Layout } from "../../../settings/enums/Layout";
|
||||
import { IDialogProps } from "./IDialogProps";
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import { avatarUrlForUser } from "../../../Avatar";
|
||||
|
@ -43,7 +43,8 @@ import QueryMatcher from "../../../autocomplete/QueryMatcher";
|
|||
import TruncatedList from "../elements/TruncatedList";
|
||||
import EntityTile from "../rooms/EntityTile";
|
||||
import BaseAvatar from "../avatars/BaseAvatar";
|
||||
import SpaceStore from "../../../stores/SpaceStore";
|
||||
import SpaceStore from "../../../stores/spaces/SpaceStore";
|
||||
import { roomContextDetailsText } from "../../../Rooms";
|
||||
|
||||
const AVATAR_SIZE = 30;
|
||||
|
||||
|
@ -121,6 +122,8 @@ const Entry: React.FC<IEntryProps> = ({ room, event, matrixClient: cli, onFinish
|
|||
/>;
|
||||
}
|
||||
|
||||
const detailsText = roomContextDetailsText(room);
|
||||
|
||||
return <div className="mx_ForwardList_entry">
|
||||
<AccessibleTooltipButton
|
||||
className="mx_ForwardList_roomButton"
|
||||
|
@ -131,6 +134,9 @@ const Entry: React.FC<IEntryProps> = ({ room, event, matrixClient: cli, onFinish
|
|||
>
|
||||
<DecoratedRoomAvatar room={room} avatarSize={32} />
|
||||
<span className="mx_ForwardList_entry_name">{ room.name }</span>
|
||||
{ detailsText && <span className="mx_ForwardList_entry_detail">
|
||||
{ detailsText }
|
||||
</span> }
|
||||
</AccessibleTooltipButton>
|
||||
<AccessibleTooltipButton
|
||||
kind={sendState === SendState.Failed ? "danger_outline" : "primary_outline"}
|
||||
|
|
|
@ -253,8 +253,8 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
|||
<AccessibleButton
|
||||
className="mx_HostSignup_maximize_button"
|
||||
onClick={this.maximizeDialog}
|
||||
aria-label={_t("Maximize dialog")}
|
||||
title={_t("Maximize dialog")}
|
||||
aria-label={_t("Maximise dialog")}
|
||||
title={_t("Maximise dialog")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
@ -263,8 +263,8 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
|||
<AccessibleButton
|
||||
onClick={this.minimizeDialog}
|
||||
className="mx_HostSignup_minimize_button"
|
||||
aria-label={_t("Minimize dialog")}
|
||||
title={_t("Minimize dialog")}
|
||||
aria-label={_t("Minimise dialog")}
|
||||
title={_t("Minimise dialog")}
|
||||
/>
|
||||
<AccessibleButton
|
||||
onClick={this.onCloseClick}
|
||||
|
|
|
@ -39,7 +39,7 @@ const PHASE_VERIFIED = 3;
|
|||
const PHASE_CANCELLED = 4;
|
||||
|
||||
interface IProps extends IDialogProps {
|
||||
verifier: VerificationBase; // TODO types
|
||||
verifier: VerificationBase;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
|
|
@ -44,6 +44,7 @@ export default class InfoDialog extends React.Component<IProps> {
|
|||
};
|
||||
|
||||
render() {
|
||||
// FIXME: Using a regular import will break the app
|
||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||
return (
|
||||
|
|
|
@ -18,9 +18,10 @@ import React from 'react';
|
|||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
import * as sdk from "../../../index";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import { IDialogProps } from "./IDialogProps";
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import DialogButtons from "../elements/DialogButtons";
|
||||
|
||||
interface IProps extends IDialogProps {}
|
||||
|
||||
|
@ -32,8 +33,6 @@ export default class IntegrationsImpossibleDialog extends React.Component<IProps
|
|||
|
||||
public render(): JSX.Element {
|
||||
const brand = SdkConfig.get().brand;
|
||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
|
|
|
@ -63,7 +63,6 @@ import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
|||
import * as ContextMenu from "../../structures/ContextMenu";
|
||||
import { toRightOf } from "../../structures/ContextMenu";
|
||||
import GenericTextContextMenu from "../context_menus/GenericTextContextMenu";
|
||||
import { TransferCallPayload } from '../../../dispatcher/payloads/TransferCallPayload';
|
||||
import Field from '../elements/Field';
|
||||
import TabbedView, { Tab, TabLocation } from '../../structures/TabbedView';
|
||||
import Dialpad from '../voip/DialPad';
|
||||
|
@ -71,7 +70,8 @@ import QuestionDialog from "./QuestionDialog";
|
|||
import Spinner from "../elements/Spinner";
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import DialPadBackspaceButton from "../elements/DialPadBackspaceButton";
|
||||
import SpaceStore from "../../../stores/SpaceStore";
|
||||
import SpaceStore from "../../../stores/spaces/SpaceStore";
|
||||
import CallHandler from "../../../CallHandler";
|
||||
|
||||
// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
|
||||
/* eslint-disable camelcase */
|
||||
|
@ -675,7 +675,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
|||
}
|
||||
if (existingRoom) {
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
action: Action.ViewRoom,
|
||||
room_id: existingRoom.roomId,
|
||||
should_peek: false,
|
||||
joining: false,
|
||||
|
@ -804,19 +804,17 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
|||
return;
|
||||
}
|
||||
|
||||
dis.dispatch({
|
||||
action: Action.TransferCallToMatrixID,
|
||||
call: this.props.call,
|
||||
destination: targetIds[0],
|
||||
consultFirst: this.state.consultFirst,
|
||||
} as TransferCallPayload);
|
||||
CallHandler.instance.startTransferToMatrixID(
|
||||
this.props.call,
|
||||
targetIds[0],
|
||||
this.state.consultFirst,
|
||||
);
|
||||
} else {
|
||||
dis.dispatch({
|
||||
action: Action.TransferCallToPhoneNumber,
|
||||
call: this.props.call,
|
||||
destination: this.state.dialPadValue,
|
||||
consultFirst: this.state.consultFirst,
|
||||
} as TransferCallPayload);
|
||||
CallHandler.instance.startTransferToPhoneNumber(
|
||||
this.props.call,
|
||||
this.state.dialPadValue,
|
||||
this.state.consultFirst,
|
||||
);
|
||||
}
|
||||
this.props.onFinished();
|
||||
};
|
||||
|
@ -1410,7 +1408,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
|||
goButtonFn = this.startDm;
|
||||
extraSection = <div className="mx_InviteDialog_section_hidden_suggestions_disclaimer">
|
||||
<span>{ _t("Some suggestions may be hidden for privacy.") }</span>
|
||||
<p>{ _t("If you can't see who you’re looking for, send them your invite link below.") }</p>
|
||||
<p>{ _t("If you can't see who you're looking for, send them your invite link below.") }</p>
|
||||
</div>;
|
||||
const link = makeUserPermalink(MatrixClientPeg.get().getUserId());
|
||||
footer = <div className="mx_InviteDialog_footer">
|
||||
|
|
|
@ -21,7 +21,7 @@ import { JoinRule } from "matrix-js-sdk/src/@types/partials";
|
|||
import { _t } from '../../../languageHandler';
|
||||
import DialogButtons from "../elements/DialogButtons";
|
||||
import BaseDialog from "../dialogs/BaseDialog";
|
||||
import SpaceStore from "../../../stores/SpaceStore";
|
||||
import SpaceStore from "../../../stores/spaces/SpaceStore";
|
||||
import SpaceChildrenPicker from "../spaces/SpaceChildrenPicker";
|
||||
|
||||
interface IProps {
|
||||
|
|
|
@ -17,16 +17,19 @@ limitations under the License.
|
|||
|
||||
import React, { ComponentType } from 'react';
|
||||
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import Modal from '../../../Modal';
|
||||
import * as sdk from '../../../index';
|
||||
import dis from '../../../dispatcher/dispatcher';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||
import RestoreKeyBackupDialog from './security/RestoreKeyBackupDialog';
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import QuestionDialog from "./QuestionDialog";
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import Spinner from "../elements/Spinner";
|
||||
import DialogButtons from "../elements/DialogButtons";
|
||||
|
||||
interface IProps {
|
||||
onFinished: (success: boolean) => void;
|
||||
}
|
||||
|
@ -133,8 +136,6 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
|
|||
|
||||
render() {
|
||||
if (this.state.shouldLoadBackupStatus) {
|
||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||
|
||||
const description = <div>
|
||||
<p>{ _t(
|
||||
"Encrypted messages are secured with end-to-end encryption. " +
|
||||
|
@ -145,11 +146,8 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
|
|||
|
||||
let dialogContent;
|
||||
if (this.state.loading) {
|
||||
const Spinner = sdk.getComponent('views.elements.Spinner');
|
||||
|
||||
dialogContent = <Spinner />;
|
||||
} else {
|
||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||
let setupButtonCaption;
|
||||
if (this.state.backupInfo) {
|
||||
setupButtonCaption = _t("Connect this session to Key Backup");
|
||||
|
@ -192,7 +190,6 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
|
|||
{ dialogContent }
|
||||
</BaseDialog>);
|
||||
} else {
|
||||
const QuestionDialog = sdk.getComponent('views.dialogs.QuestionDialog');
|
||||
return (<QuestionDialog
|
||||
hasCancelButton={true}
|
||||
title={_t("Sign out")}
|
||||
|
|
|
@ -21,7 +21,7 @@ import { _t } from '../../../languageHandler';
|
|||
import { IDialogProps } from "./IDialogProps";
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import SearchBox from "../../structures/SearchBox";
|
||||
import SpaceStore from "../../../stores/SpaceStore";
|
||||
import SpaceStore from "../../../stores/spaces/SpaceStore";
|
||||
import RoomAvatar from "../avatars/RoomAvatar";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
|
||||
|
@ -66,6 +66,17 @@ const Entry = ({ room, checked, onChange }) => {
|
|||
</label>;
|
||||
};
|
||||
|
||||
const addAllParents = (set: Set<Room>, room: Room): void => {
|
||||
const cli = room.client;
|
||||
const parents = Array.from(SpaceStore.instance.getKnownParents(room.roomId)).map(parentId => cli.getRoom(parentId));
|
||||
|
||||
parents.forEach(parent => {
|
||||
if (set.has(parent)) return;
|
||||
set.add(parent);
|
||||
addAllParents(set, parent);
|
||||
});
|
||||
};
|
||||
|
||||
const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [], onFinished }) => {
|
||||
const cli = room.client;
|
||||
const [newSelected, setNewSelected] = useState(new Set<string>(selected));
|
||||
|
@ -73,9 +84,10 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
|||
const lcQuery = query.toLowerCase().trim();
|
||||
|
||||
const [spacesContainingRoom, otherEntries] = useMemo(() => {
|
||||
const spaces = cli.getVisibleRooms().filter(r => r.getMyMembership() === "join" && r.isSpaceRoom());
|
||||
const parents = new Set<Room>();
|
||||
addAllParents(parents, room);
|
||||
return [
|
||||
spaces.filter(r => SpaceStore.instance.getSpaceFilteredRoomIds(r).has(room.roomId)),
|
||||
Array.from(parents),
|
||||
selected.map(roomId => {
|
||||
const room = cli.getRoom(roomId);
|
||||
if (!room) {
|
||||
|
@ -86,9 +98,9 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
|||
}
|
||||
}).filter(Boolean),
|
||||
];
|
||||
}, [cli, selected, room.roomId]);
|
||||
}, [cli, selected, room]);
|
||||
|
||||
const [filteredSpacesContainingRooms, filteredOtherEntries] = useMemo(() => [
|
||||
const [filteredSpacesContainingRoom, filteredOtherEntries] = useMemo(() => [
|
||||
spacesContainingRoom.filter(r => r.name.toLowerCase().includes(lcQuery)),
|
||||
otherEntries.filter(r => r.name.toLowerCase().includes(lcQuery)),
|
||||
], [spacesContainingRoom, otherEntries, lcQuery]);
|
||||
|
@ -129,10 +141,14 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
|||
autoFocus={true}
|
||||
/>
|
||||
<AutoHideScrollbar className="mx_ManageRestrictedJoinRuleDialog_content">
|
||||
{ filteredSpacesContainingRooms.length > 0 ? (
|
||||
{ filteredSpacesContainingRoom.length > 0 ? (
|
||||
<div className="mx_ManageRestrictedJoinRuleDialog_section">
|
||||
<h3>{ _t("Spaces you know that contain this room") }</h3>
|
||||
{ filteredSpacesContainingRooms.map(space => {
|
||||
<h3>
|
||||
{ room.isSpaceRoom()
|
||||
? _t("Spaces you know that contain this space")
|
||||
: _t("Spaces you know that contain this room") }
|
||||
</h3>
|
||||
{ filteredSpacesContainingRoom.map(space => {
|
||||
return <Entry
|
||||
key={space.roomId}
|
||||
room={space}
|
||||
|
@ -164,7 +180,7 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
|||
</div>
|
||||
) : null }
|
||||
|
||||
{ filteredSpacesContainingRooms.length + filteredOtherEntries.length < 1
|
||||
{ filteredSpacesContainingRoom.length + filteredOtherEntries.length < 1
|
||||
? <span className="mx_ManageRestrictedJoinRuleDialog_noResults">
|
||||
{ _t("No results") }
|
||||
</span>
|
||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||
import * as React from "react";
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { _t, _td } from '../../../languageHandler';
|
||||
import { IDialogProps } from "./IDialogProps";
|
||||
import Field from "../elements/Field";
|
||||
import CountlyAnalytics from "../../../CountlyAnalytics";
|
||||
|
@ -64,7 +64,7 @@ const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => {
|
|||
<EmailField
|
||||
fieldRef={fieldRef}
|
||||
autoFocus={true}
|
||||
label={_t("Email (optional)")}
|
||||
label={_td("Email (optional)")}
|
||||
value={email}
|
||||
onChange={ev => {
|
||||
const target = ev.target as HTMLInputElement;
|
||||
|
|
|
@ -114,7 +114,7 @@ export default class RoomSettingsDialog extends React.Component<IProps, IState>
|
|||
ROOM_NOTIFICATIONS_TAB,
|
||||
_td("Notifications"),
|
||||
"mx_RoomSettingsDialog_notificationsIcon",
|
||||
<NotificationSettingsTab roomId={this.props.roomId} />,
|
||||
<NotificationSettingsTab roomId={this.props.roomId} closeSettingsFn={() => this.props.onFinished(true)} />,
|
||||
));
|
||||
|
||||
if (SettingsStore.getValue("feature_bridge_state")) {
|
||||
|
|
116
src/components/views/dialogs/ScrollableBaseModal.tsx
Normal file
116
src/components/views/dialogs/ScrollableBaseModal.tsx
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
Copyright 2021 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 React, { FormEvent } from "react";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import { Key } from "../../../Keyboard";
|
||||
import { IDialogProps } from "./IDialogProps";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import FocusLock from "react-focus-lock";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
|
||||
export interface IScrollableBaseState {
|
||||
canSubmit: boolean;
|
||||
title: string;
|
||||
actionLabel: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrollable dialog base from Compound (Web Components).
|
||||
*/
|
||||
export default abstract class ScrollableBaseModal<TProps extends IDialogProps, TState extends IScrollableBaseState>
|
||||
extends React.PureComponent<TProps, TState> {
|
||||
protected constructor(props: TProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
protected get matrixClient(): MatrixClient {
|
||||
return MatrixClientPeg.get();
|
||||
}
|
||||
|
||||
private onKeyDown = (e: KeyboardEvent | React.KeyboardEvent): void => {
|
||||
if (e.key === Key.ESCAPE) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
private onCancel = () => {
|
||||
this.cancel();
|
||||
};
|
||||
|
||||
private onSubmit = (e: MouseEvent | FormEvent) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (!this.state.canSubmit) return; // pretend the submit button was disabled
|
||||
this.submit();
|
||||
};
|
||||
|
||||
protected abstract cancel(): void;
|
||||
protected abstract submit(): void;
|
||||
protected abstract renderContent(): React.ReactNode;
|
||||
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<MatrixClientContext.Provider value={this.matrixClient}>
|
||||
<FocusLock
|
||||
returnFocus={true}
|
||||
lockProps={{
|
||||
onKeyDown: this.onKeyDown,
|
||||
role: "dialog",
|
||||
["aria-labelledby"]: "mx_CompoundDialog_title",
|
||||
|
||||
// Like BaseDialog, we'll just point this at the whole content
|
||||
["aria-describedby"]: "mx_CompoundDialog_content",
|
||||
}}
|
||||
className="mx_CompoundDialog mx_ScrollableBaseDialog"
|
||||
>
|
||||
<div className="mx_CompoundDialog_header">
|
||||
<h1>{ this.state.title }</h1>
|
||||
<AccessibleButton
|
||||
onClick={this.onCancel}
|
||||
className="mx_CompoundDialog_cancelButton"
|
||||
aria-label={_t("Close dialog")}
|
||||
/>
|
||||
</div>
|
||||
<form onSubmit={this.onSubmit}>
|
||||
<div className="mx_CompoundDialog_content">
|
||||
{ this.renderContent() }
|
||||
</div>
|
||||
<div className="mx_CompoundDialog_footer">
|
||||
<AccessibleButton onClick={this.onCancel} kind="primary_outline">
|
||||
{ _t("Cancel") }
|
||||
</AccessibleButton>
|
||||
<AccessibleButton
|
||||
onClick={this.onSubmit}
|
||||
kind="primary"
|
||||
disabled={!this.state.canSubmit}
|
||||
type="submit"
|
||||
element="button"
|
||||
className="mx_Dialog_nonDialogButton"
|
||||
>
|
||||
{ this.state.actionLabel }
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
</form>
|
||||
</FocusLock>
|
||||
</MatrixClientContext.Provider>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -166,7 +166,7 @@ export default class ServerPickerDialog extends React.PureComponent<IProps, ISta
|
|||
public render() {
|
||||
let text;
|
||||
if (this.defaultServer.hsName === "matrix.org") {
|
||||
text = _t("Matrix.org is the biggest public homeserver in the world, so it’s a good place for many.");
|
||||
text = _t("Matrix.org is the biggest public homeserver in the world, so it's a good place for many.");
|
||||
}
|
||||
|
||||
let defaultServerName: React.ReactNode = this.defaultServer.hsName;
|
||||
|
@ -188,7 +188,7 @@ export default class ServerPickerDialog extends React.PureComponent<IProps, ISta
|
|||
>
|
||||
<form className="mx_Dialog_content" id="mx_ServerPickerDialog" onSubmit={this.onSubmit}>
|
||||
<p>
|
||||
{ _t("We call the places where you can host your account ‘homeservers’.") } { text }
|
||||
{ _t("We call the places where you can host your account 'homeservers'.") } { text }
|
||||
</p>
|
||||
|
||||
<StyledRadioButton
|
||||
|
|
|
@ -29,13 +29,15 @@ import DialogButtons from "../elements/DialogButtons";
|
|||
import { IDialogProps } from "./IDialogProps";
|
||||
|
||||
interface IProps extends IDialogProps {
|
||||
error: string;
|
||||
error: Error;
|
||||
}
|
||||
|
||||
@replaceableComponent("views.dialogs.SessionRestoreErrorDialog")
|
||||
export default class SessionRestoreErrorDialog extends React.Component<IProps> {
|
||||
private sendBugReport = (): void => {
|
||||
Modal.createTrackedDialog('Session Restore Error', 'Send Bug Report Dialog', BugReportDialog, {});
|
||||
Modal.createTrackedDialog('Session Restore Error', 'Send Bug Report Dialog', BugReportDialog, {
|
||||
error: this.props.error,
|
||||
});
|
||||
};
|
||||
|
||||
private onClearStorageClick = (): void => {
|
||||
|
|
|
@ -35,6 +35,7 @@ import { UIFeature } from "../../../settings/UIFeature";
|
|||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import { IDialogProps } from "./IDialogProps";
|
||||
import SidebarUserSettingsTab from "../settings/tabs/user/SidebarUserSettingsTab";
|
||||
|
||||
export enum UserTab {
|
||||
General = "USER_GENERAL_TAB",
|
||||
|
@ -42,6 +43,7 @@ export enum UserTab {
|
|||
Flair = "USER_FLAIR_TAB",
|
||||
Notifications = "USER_NOTIFICATIONS_TAB",
|
||||
Preferences = "USER_PREFERENCES_TAB",
|
||||
Sidebar = "USER_SIDEBAR_TAB",
|
||||
Voice = "USER_VOICE_TAB",
|
||||
Security = "USER_SECURITY_TAB",
|
||||
Labs = "USER_LABS_TAB",
|
||||
|
@ -118,6 +120,15 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
|
|||
<PreferencesUserSettingsTab closeSettingsFn={this.props.onFinished} />,
|
||||
));
|
||||
|
||||
if (SettingsStore.getValue("feature_spaces_metaspaces")) {
|
||||
tabs.push(new Tab(
|
||||
UserTab.Sidebar,
|
||||
_td("Sidebar"),
|
||||
"mx_UserSettingsDialog_sidebarIcon",
|
||||
<SidebarUserSettingsTab />,
|
||||
));
|
||||
}
|
||||
|
||||
if (SettingsStore.getValue(UIFeature.Voip)) {
|
||||
tabs.push(new Tab(
|
||||
UserTab.Voice,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue