Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/fix/15175
Conflicts: src/settings/Settings.ts src/settings/UIFeature.ts
This commit is contained in:
commit
4213a557f2
11 changed files with 105 additions and 73 deletions
|
@ -170,15 +170,19 @@ class Analytics {
|
|||
return !this.baseUrl;
|
||||
}
|
||||
|
||||
canEnable() {
|
||||
const config = SdkConfig.get();
|
||||
return navigator.doNotTrack !== "1" && config && config.piwik && config.piwik.url && config.piwik.siteId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Analytics if initialized but disabled
|
||||
* otherwise try and initalize, no-op if piwik config missing
|
||||
*/
|
||||
async enable() {
|
||||
if (!this.disabled) return;
|
||||
|
||||
if (!this.canEnable()) return;
|
||||
const config = SdkConfig.get();
|
||||
if (!config || !config.piwik || !config.piwik.url || !config.piwik.siteId) return;
|
||||
|
||||
this.baseUrl = new URL("piwik.php", config.piwik.url);
|
||||
// set constants
|
||||
|
|
|
@ -1234,8 +1234,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
|
||||
StorageManager.tryPersistStorage();
|
||||
|
||||
if (SettingsStore.getValue("showCookieBar") && this.props.config.piwik && navigator.doNotTrack !== "1") {
|
||||
showAnalyticsToast(this.props.config.piwik && this.props.config.piwik.policyUrl);
|
||||
if (SettingsStore.getValue("showCookieBar") && Analytics.canEnable()) {
|
||||
showAnalyticsToast(this.props.config.piwik?.policyUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,10 +70,10 @@ export default class RoomDirectory extends React.Component {
|
|||
this.scrollPanel = null;
|
||||
this.protocols = null;
|
||||
|
||||
this.setState({protocolsLoading: true});
|
||||
this.state.protocolsLoading = true;
|
||||
if (!MatrixClientPeg.get()) {
|
||||
// We may not have a client yet when invoked from welcome page
|
||||
this.setState({protocolsLoading: false});
|
||||
this.state.protocolsLoading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -102,14 +102,16 @@ export default class RoomDirectory extends React.Component {
|
|||
});
|
||||
} else {
|
||||
// We don't use the protocols in the communities v2 prototype experience
|
||||
this.setState({protocolsLoading: false});
|
||||
this.state.protocolsLoading = false;
|
||||
|
||||
// Grab the profile info async
|
||||
FlairStore.getGroupProfileCached(MatrixClientPeg.get(), this.state.selectedCommunityId).then(profile => {
|
||||
this.setState({communityName: profile.name});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.refreshRoomList();
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ import dis from "../../dispatcher/dispatcher";
|
|||
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
||||
import ErrorDialog from "../views/dialogs/ErrorDialog";
|
||||
import EditCommunityPrototypeDialog from "../views/dialogs/EditCommunityPrototypeDialog";
|
||||
import {UIFeature} from "../../settings/UIFeature";
|
||||
|
||||
interface IProps {
|
||||
isMinimized: boolean;
|
||||
|
@ -285,6 +286,15 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
|||
);
|
||||
}
|
||||
|
||||
let feedbackButton;
|
||||
if (SettingsStore.getValue(UIFeature.Feedback)) {
|
||||
feedbackButton = <IconizedContextMenuOption
|
||||
iconClassName="mx_UserMenu_iconMessage"
|
||||
label={_t("Feedback")}
|
||||
onClick={this.onProvideFeedback}
|
||||
/>;
|
||||
}
|
||||
|
||||
let primaryHeader = (
|
||||
<div className="mx_UserMenu_contextMenu_name">
|
||||
<span className="mx_UserMenu_contextMenu_displayName">
|
||||
|
@ -319,11 +329,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
|||
label={_t("Archived rooms")}
|
||||
onClick={this.onShowArchived}
|
||||
/> */}
|
||||
<IconizedContextMenuOption
|
||||
iconClassName="mx_UserMenu_iconMessage"
|
||||
label={_t("Feedback")}
|
||||
onClick={this.onProvideFeedback}
|
||||
/>
|
||||
{ feedbackButton }
|
||||
</IconizedContextMenuOptionList>
|
||||
<IconizedContextMenuOptionList red>
|
||||
<IconizedContextMenuOption
|
||||
|
@ -384,11 +390,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
|||
aria-label={_t("User settings")}
|
||||
onClick={(e) => this.onSettingsOpen(e, null)}
|
||||
/>
|
||||
<IconizedContextMenuOption
|
||||
iconClassName="mx_UserMenu_iconMessage"
|
||||
label={_t("Feedback")}
|
||||
onClick={this.onProvideFeedback}
|
||||
/>
|
||||
{ feedbackButton }
|
||||
</IconizedContextMenuOptionList>
|
||||
<IconizedContextMenuOptionList red>
|
||||
<IconizedContextMenuOption
|
||||
|
|
|
@ -20,6 +20,7 @@ import { _t } from '../../../languageHandler';
|
|||
import {MatrixClientPeg} from '../../../MatrixClientPeg';
|
||||
import PlatformPeg from '../../../PlatformPeg';
|
||||
import Modal from '../../../Modal';
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
|
||||
/**
|
||||
* This error boundary component can be used to wrap large content areas and
|
||||
|
@ -73,9 +74,10 @@ export default class ErrorBoundary extends React.PureComponent {
|
|||
if (this.state.error) {
|
||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||
const newIssueUrl = "https://github.com/vector-im/element-web/issues/new";
|
||||
return <div className="mx_ErrorBoundary">
|
||||
<div className="mx_ErrorBoundary_body">
|
||||
<h1>{_t("Something went wrong!")}</h1>
|
||||
|
||||
let bugReportSection;
|
||||
if (SdkConfig.get().bug_report_endpoint_url) {
|
||||
bugReportSection = <React.Fragment>
|
||||
<p>{_t(
|
||||
"Please <newIssueLink>create a new issue</newIssueLink> " +
|
||||
"on GitHub so that we can investigate this bug.", {}, {
|
||||
|
@ -94,6 +96,13 @@ export default class ErrorBoundary extends React.PureComponent {
|
|||
<AccessibleButton onClick={this._onBugReport} kind='primary'>
|
||||
{_t("Submit debug logs")}
|
||||
</AccessibleButton>
|
||||
</React.Fragment>;
|
||||
}
|
||||
|
||||
return <div className="mx_ErrorBoundary">
|
||||
<div className="mx_ErrorBoundary_body">
|
||||
<h1>{_t("Something went wrong!")}</h1>
|
||||
{ bugReportSection }
|
||||
<AccessibleButton onClick={this._onClearCacheAndReload} kind='danger'>
|
||||
{_t("Clear cache and reload")}
|
||||
</AccessibleButton>
|
||||
|
|
|
@ -19,6 +19,7 @@ import classNames from 'classnames';
|
|||
import { _t } from '../../../languageHandler';
|
||||
import * as sdk from '../../../index';
|
||||
import Modal from '../../../Modal';
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
|
||||
export default class TileErrorBoundary extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -54,14 +55,20 @@ export default class TileErrorBoundary extends React.Component {
|
|||
mx_EventTile_content: true,
|
||||
mx_EventTile_tileError: true,
|
||||
};
|
||||
|
||||
let submitLogsButton;
|
||||
if (SdkConfig.get().bug_report_endpoint_url) {
|
||||
submitLogsButton = <a onClick={this._onBugReport} href="#">
|
||||
{_t("Submit logs")}
|
||||
</a>;
|
||||
}
|
||||
|
||||
return (<div className={classNames(classes)}>
|
||||
<div className="mx_EventTile_line">
|
||||
<span>
|
||||
{_t("Can't load this message")}
|
||||
{ mxEvent && ` (${mxEvent.getType()})` }
|
||||
<a onClick={this._onBugReport} href="#">
|
||||
{_t("Submit logs")}
|
||||
</a>
|
||||
{ submitLogsButton }
|
||||
</span>
|
||||
</div>
|
||||
</div>);
|
||||
|
|
|
@ -952,30 +952,26 @@ function useRoomPermissions(cli, room, user) {
|
|||
|
||||
const PowerLevelSection = ({user, room, roomPermissions, powerLevels}) => {
|
||||
const [isEditing, setEditing] = useState(false);
|
||||
if (room && user.roomId) { // is in room
|
||||
if (isEditing) {
|
||||
return (<PowerLevelEditor
|
||||
user={user} room={room} roomPermissions={roomPermissions}
|
||||
onFinished={() => setEditing(false)} />);
|
||||
} else {
|
||||
const IconButton = sdk.getComponent('elements.IconButton');
|
||||
const powerLevelUsersDefault = powerLevels.users_default || 0;
|
||||
const powerLevel = parseInt(user.powerLevel, 10);
|
||||
const modifyButton = roomPermissions.canEdit ?
|
||||
(<IconButton icon="edit" onClick={() => setEditing(true)} />) : null;
|
||||
const role = textualPowerLevel(powerLevel, powerLevelUsersDefault);
|
||||
const label = _t("<strong>%(role)s</strong> in %(roomName)s",
|
||||
{role, roomName: room.name},
|
||||
{strong: label => <strong>{label}</strong>},
|
||||
);
|
||||
return (
|
||||
<div className="mx_UserInfo_profileField">
|
||||
<div className="mx_UserInfo_roleDescription">{label}{modifyButton}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (isEditing) {
|
||||
return (<PowerLevelEditor
|
||||
user={user} room={room} roomPermissions={roomPermissions}
|
||||
onFinished={() => setEditing(false)} />);
|
||||
} else {
|
||||
return null;
|
||||
const IconButton = sdk.getComponent('elements.IconButton');
|
||||
const powerLevelUsersDefault = powerLevels.users_default || 0;
|
||||
const powerLevel = parseInt(user.powerLevel, 10);
|
||||
const modifyButton = roomPermissions.canEdit ?
|
||||
(<IconButton icon="edit" onClick={() => setEditing(true)} />) : null;
|
||||
const role = textualPowerLevel(powerLevel, powerLevelUsersDefault);
|
||||
const label = _t("<strong>%(role)s</strong> in %(roomName)s",
|
||||
{role, roomName: room.name},
|
||||
{strong: label => <strong>{label}</strong>},
|
||||
);
|
||||
return (
|
||||
<div className="mx_UserInfo_profileField">
|
||||
<div className="mx_UserInfo_roleDescription">{label}{modifyButton}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1268,14 +1264,15 @@ const BasicUserInfo = ({room, member, groupId, devices, isRoomEncrypted}) => {
|
|||
spinner = <Loader imgClassName="mx_ContextualMenu_spinner" />;
|
||||
}
|
||||
|
||||
const memberDetails = (
|
||||
<PowerLevelSection
|
||||
let memberDetails;
|
||||
if (room && member.roomId) {
|
||||
memberDetails = <PowerLevelSection
|
||||
powerLevels={powerLevels}
|
||||
user={member}
|
||||
room={room}
|
||||
roomPermissions={roomPermissions}
|
||||
/>
|
||||
);
|
||||
/>;
|
||||
}
|
||||
|
||||
// only display the devices list if our client supports E2E
|
||||
const cryptoEnabled = cli.isCryptoEnabled();
|
||||
|
|
|
@ -329,6 +329,29 @@ export default class SecurityUserSettingsTab extends React.Component {
|
|||
</div>;
|
||||
}
|
||||
|
||||
let privacySection;
|
||||
if (Analytics.canEnable()) {
|
||||
privacySection = <React.Fragment>
|
||||
<div className="mx_SettingsTab_heading">{_t("Privacy")}</div>
|
||||
<div className="mx_SettingsTab_section">
|
||||
<span className="mx_SettingsTab_subheading">{_t("Analytics")}</span>
|
||||
<div className="mx_SettingsTab_subsectionText">
|
||||
{_t(
|
||||
"%(brand)s collects anonymous analytics to allow us to improve the application.",
|
||||
{ brand },
|
||||
)}
|
||||
|
||||
{_t("Privacy is important to us, so we don't collect any personal or " +
|
||||
"identifiable data for our analytics.")}
|
||||
<AccessibleButton className="mx_SettingsTab_linkBtn" onClick={Analytics.showDetailsModal}>
|
||||
{_t("Learn more about how we use analytics.")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
<SettingsFlag name="analyticsOptIn" level={SettingLevel.DEVICE} onChange={this._updateAnalytics} />
|
||||
</div>
|
||||
</React.Fragment>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_SettingsTab mx_SecurityUserSettingsTab">
|
||||
{warning}
|
||||
|
@ -357,24 +380,7 @@ export default class SecurityUserSettingsTab extends React.Component {
|
|||
{crossSigning}
|
||||
{this._renderCurrentDeviceInfo()}
|
||||
</div>
|
||||
<div className="mx_SettingsTab_heading">{_t("Privacy")}</div>
|
||||
<div className="mx_SettingsTab_section">
|
||||
<span className="mx_SettingsTab_subheading">{_t("Analytics")}</span>
|
||||
<div className='mx_SettingsTab_subsectionText'>
|
||||
{_t(
|
||||
"%(brand)s collects anonymous analytics to allow us to improve the application.",
|
||||
{ brand },
|
||||
)}
|
||||
|
||||
{_t("Privacy is important to us, so we don't collect any personal or " +
|
||||
"identifiable data for our analytics.")}
|
||||
<AccessibleButton className="mx_SettingsTab_linkBtn" onClick={Analytics.showDetailsModal}>
|
||||
{_t("Learn more about how we use analytics.")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
<SettingsFlag name='analyticsOptIn' level={SettingLevel.DEVICE}
|
||||
onChange={this._updateAnalytics} />
|
||||
</div>
|
||||
{ privacySection }
|
||||
<div className="mx_SettingsTab_heading">{_t("Advanced")}</div>
|
||||
<div className="mx_SettingsTab_section">
|
||||
{this._renderIgnoredUsers()}
|
||||
|
|
|
@ -912,13 +912,13 @@
|
|||
"Message search": "Message search",
|
||||
"Cross-signing": "Cross-signing",
|
||||
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.",
|
||||
"Where you’re logged in": "Where you’re logged in",
|
||||
"Manage the names of and sign out of your sessions below or <a>verify them in your User Profile</a>.": "Manage the names of and sign out of your sessions below or <a>verify them in your User Profile</a>.",
|
||||
"A session's public name is visible to people you communicate with": "A session's public name is visible to people you communicate with",
|
||||
"Privacy": "Privacy",
|
||||
"%(brand)s collects anonymous analytics to allow us to improve the application.": "%(brand)s collects anonymous analytics to allow us to improve the application.",
|
||||
"Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.",
|
||||
"Learn more about how we use analytics.": "Learn more about how we use analytics.",
|
||||
"Where you’re logged in": "Where you’re logged in",
|
||||
"Manage the names of and sign out of your sessions below or <a>verify them in your User Profile</a>.": "Manage the names of and sign out of your sessions below or <a>verify them in your User Profile</a>.",
|
||||
"A session's public name is visible to people you communicate with": "A session's public name is visible to people you communicate with",
|
||||
"No media permissions": "No media permissions",
|
||||
"You may need to manually permit %(brand)s to access your microphone/webcam": "You may need to manually permit %(brand)s to access your microphone/webcam",
|
||||
"Missing media permissions, click the button below to request.": "Missing media permissions, click the button below to request.",
|
||||
|
@ -1440,8 +1440,8 @@
|
|||
"Click to view edits": "Click to view edits",
|
||||
"Edited at %(date)s. Click to view edits.": "Edited at %(date)s. Click to view edits.",
|
||||
"edited": "edited",
|
||||
"Can't load this message": "Can't load this message",
|
||||
"Submit logs": "Submit logs",
|
||||
"Can't load this message": "Can't load this message",
|
||||
"Failed to load group members": "Failed to load group members",
|
||||
"Filter community members": "Filter community members",
|
||||
"Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Are you sure you want to remove '%(roomName)s' from %(groupId)s?",
|
||||
|
@ -2132,10 +2132,10 @@
|
|||
"Uploading %(filename)s and %(count)s others|zero": "Uploading %(filename)s",
|
||||
"Uploading %(filename)s and %(count)s others|one": "Uploading %(filename)s and %(count)s other",
|
||||
"Failed to find the general chat for this community": "Failed to find the general chat for this community",
|
||||
"Feedback": "Feedback",
|
||||
"Notification settings": "Notification settings",
|
||||
"Security & privacy": "Security & privacy",
|
||||
"All settings": "All settings",
|
||||
"Feedback": "Feedback",
|
||||
"Community settings": "Community settings",
|
||||
"User settings": "User settings",
|
||||
"Switch to light mode": "Switch to light mode",
|
||||
|
|
|
@ -627,4 +627,8 @@ export const SETTINGS: {[setting: string]: ISetting} = {
|
|||
supportedLevels: LEVELS_UI_FEATURE,
|
||||
default: true,
|
||||
},
|
||||
[UIFeature.Feedback]: {
|
||||
supportedLevels: LEVELS_UI_FEATURE,
|
||||
default: true,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -19,4 +19,5 @@ export enum UIFeature {
|
|||
URLPreviews = "UIFeature.urlPreviews",
|
||||
Widgets = "UIFeature.widgets",
|
||||
Voip = "UIFeature.voip",
|
||||
Feedback = "UIFeature.feedback",
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue