mirror of
https://github.com/element-hq/element-web
synced 2024-11-27 19:56:47 +03:00
Merge pull request #4624 from matrix-org/t3chguy/toasts3_2
Migrate Banners to Toasts
This commit is contained in:
commit
0242b6f3f3
23 changed files with 506 additions and 626 deletions
|
@ -67,7 +67,3 @@ limitations under the License.
|
||||||
.mx_MatrixToolbar_action {
|
.mx_MatrixToolbar_action {
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MatrixToolbar_changelog {
|
|
||||||
white-space: pre;
|
|
||||||
}
|
|
||||||
|
|
|
@ -575,10 +575,12 @@ async function startMatrixClient(startSyncing=true) {
|
||||||
// to work).
|
// to work).
|
||||||
dis.dispatch({action: 'will_start_client'}, true);
|
dis.dispatch({action: 'will_start_client'}, true);
|
||||||
|
|
||||||
|
// reset things first just in case
|
||||||
|
TypingStore.sharedInstance().reset();
|
||||||
|
ToastStore.sharedInstance().reset();
|
||||||
|
|
||||||
Notifier.start();
|
Notifier.start();
|
||||||
UserActivity.sharedInstance().start();
|
UserActivity.sharedInstance().start();
|
||||||
TypingStore.sharedInstance().reset(); // just in case
|
|
||||||
ToastStore.sharedInstance().reset();
|
|
||||||
DMRoomMap.makeShared().start();
|
DMRoomMap.makeShared().start();
|
||||||
IntegrationManagers.sharedInstance().startWatching();
|
IntegrationManagers.sharedInstance().startWatching();
|
||||||
ActiveWidgetStore.start();
|
ActiveWidgetStore.start();
|
||||||
|
|
|
@ -26,6 +26,10 @@ import * as sdk from './index';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import SettingsStore, {SettingLevel} from "./settings/SettingsStore";
|
import SettingsStore, {SettingLevel} from "./settings/SettingsStore";
|
||||||
|
import {
|
||||||
|
showToast as showNotificationsToast,
|
||||||
|
hideToast as hideNotificationsToast,
|
||||||
|
} from "./toasts/DesktopNotificationsToast";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dispatches:
|
* Dispatches:
|
||||||
|
@ -184,6 +188,10 @@ const Notifier = {
|
||||||
MatrixClientPeg.get().on("sync", this.boundOnSyncStateChange);
|
MatrixClientPeg.get().on("sync", this.boundOnSyncStateChange);
|
||||||
this.toolbarHidden = false;
|
this.toolbarHidden = false;
|
||||||
this.isSyncing = false;
|
this.isSyncing = false;
|
||||||
|
|
||||||
|
if (this.shouldShowToolbar()) {
|
||||||
|
showNotificationsToast();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
stop: function() {
|
stop: function() {
|
||||||
|
@ -278,12 +286,7 @@ const Notifier = {
|
||||||
|
|
||||||
Analytics.trackEvent('Notifier', 'Set Toolbar Hidden', hidden);
|
Analytics.trackEvent('Notifier', 'Set Toolbar Hidden', hidden);
|
||||||
|
|
||||||
// XXX: why are we dispatching this here?
|
hideNotificationsToast();
|
||||||
// this is nothing to do with notifier_enabled
|
|
||||||
dis.dispatch({
|
|
||||||
action: "notifier_enabled",
|
|
||||||
value: this.isEnabled(),
|
|
||||||
});
|
|
||||||
|
|
||||||
// update the info to localStorage for persistent settings
|
// update the info to localStorage for persistent settings
|
||||||
if (persistent && global.localStorage) {
|
if (persistent && global.localStorage) {
|
||||||
|
|
|
@ -43,6 +43,15 @@ import ResizeNotifier from "../../utils/ResizeNotifier";
|
||||||
import PlatformPeg from "../../PlatformPeg";
|
import PlatformPeg from "../../PlatformPeg";
|
||||||
import { RoomListStoreTempProxy } from "../../stores/room-list/RoomListStoreTempProxy";
|
import { RoomListStoreTempProxy } from "../../stores/room-list/RoomListStoreTempProxy";
|
||||||
import { DefaultTagID } from "../../stores/room-list/models";
|
import { DefaultTagID } from "../../stores/room-list/models";
|
||||||
|
import {
|
||||||
|
showToast as showSetPasswordToast,
|
||||||
|
hideToast as hideSetPasswordToast
|
||||||
|
} from "../../toasts/SetPasswordToast";
|
||||||
|
import {
|
||||||
|
showToast as showServerLimitToast,
|
||||||
|
hideToast as hideServerLimitToast
|
||||||
|
} from "../../toasts/ServerLimitToast";
|
||||||
|
|
||||||
// We need to fetch each pinned message individually (if we don't already have it)
|
// We need to fetch each pinned message individually (if we don't already have it)
|
||||||
// so each pinned message may trigger a request. Limit the number per room for sanity.
|
// so each pinned message may trigger a request. Limit the number per room for sanity.
|
||||||
// NB. this is just for server notices rather than pinned messages in general.
|
// NB. this is just for server notices rather than pinned messages in general.
|
||||||
|
@ -65,10 +74,6 @@ interface IProps {
|
||||||
initialEventPixelOffset: number;
|
initialEventPixelOffset: number;
|
||||||
leftDisabled: boolean;
|
leftDisabled: boolean;
|
||||||
rightDisabled: boolean;
|
rightDisabled: boolean;
|
||||||
showCookieBar: boolean;
|
|
||||||
hasNewVersion: boolean;
|
|
||||||
userHasGeneratedPassword: boolean;
|
|
||||||
showNotifierToolbar: boolean;
|
|
||||||
page_type: string;
|
page_type: string;
|
||||||
autoJoin: boolean;
|
autoJoin: boolean;
|
||||||
thirdPartyInvite?: object;
|
thirdPartyInvite?: object;
|
||||||
|
@ -86,10 +91,8 @@ interface IProps {
|
||||||
currentUserId?: string;
|
currentUserId?: string;
|
||||||
currentGroupId?: string;
|
currentGroupId?: string;
|
||||||
currentGroupIsNew?: boolean;
|
currentGroupIsNew?: boolean;
|
||||||
version?: string;
|
|
||||||
newVersion?: string;
|
|
||||||
newVersionReleaseNotes?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
mouseDown?: {
|
mouseDown?: {
|
||||||
x: number;
|
x: number;
|
||||||
|
@ -97,8 +100,6 @@ interface IState {
|
||||||
};
|
};
|
||||||
syncErrorData: any;
|
syncErrorData: any;
|
||||||
useCompactLayout: boolean;
|
useCompactLayout: boolean;
|
||||||
serverNoticeEvents: MatrixEvent[];
|
|
||||||
userHasGeneratedPassword: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -141,11 +142,8 @@ class LoggedInView extends React.PureComponent<IProps, IState> {
|
||||||
this.state = {
|
this.state = {
|
||||||
mouseDown: undefined,
|
mouseDown: undefined,
|
||||||
syncErrorData: undefined,
|
syncErrorData: undefined,
|
||||||
userHasGeneratedPassword: false,
|
|
||||||
// use compact timeline view
|
// use compact timeline view
|
||||||
useCompactLayout: SettingsStore.getValue('useCompactLayout'),
|
useCompactLayout: SettingsStore.getValue('useCompactLayout'),
|
||||||
// any currently active server notice events
|
|
||||||
serverNoticeEvents: [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// stash the MatrixClient in case we log out before we are unmounted
|
// stash the MatrixClient in case we log out before we are unmounted
|
||||||
|
@ -182,10 +180,7 @@ class LoggedInView extends React.PureComponent<IProps, IState> {
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
// attempt to guess when a banner was opened or closed
|
// attempt to guess when a banner was opened or closed
|
||||||
if (
|
if (
|
||||||
(prevProps.showCookieBar !== this.props.showCookieBar) ||
|
(prevProps.checkingForUpdate !== this.props.checkingForUpdate)
|
||||||
(prevProps.hasNewVersion !== this.props.hasNewVersion) ||
|
|
||||||
(prevState.userHasGeneratedPassword !== this.state.userHasGeneratedPassword) ||
|
|
||||||
(prevProps.showNotifierToolbar !== this.props.showNotifierToolbar)
|
|
||||||
) {
|
) {
|
||||||
this.props.resizeNotifier.notifyBannersChanged();
|
this.props.resizeNotifier.notifyBannersChanged();
|
||||||
}
|
}
|
||||||
|
@ -220,9 +215,11 @@ class LoggedInView extends React.PureComponent<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
_setStateFromSessionStore = () => {
|
_setStateFromSessionStore = () => {
|
||||||
this.setState({
|
if (this._sessionStore.getCachedPassword()) {
|
||||||
userHasGeneratedPassword: Boolean(this._sessionStore.getCachedPassword()),
|
showSetPasswordToast();
|
||||||
});
|
} else {
|
||||||
|
hideSetPasswordToast();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_createResizer() {
|
_createResizer() {
|
||||||
|
@ -294,6 +291,8 @@ class LoggedInView extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
if (oldSyncState === 'PREPARED' && syncState === 'SYNCING') {
|
if (oldSyncState === 'PREPARED' && syncState === 'SYNCING') {
|
||||||
this._updateServerNoticeEvents();
|
this._updateServerNoticeEvents();
|
||||||
|
} else {
|
||||||
|
this._calculateServerLimitToast(data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -304,11 +303,24 @@ class LoggedInView extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_calculateServerLimitToast(syncErrorData, usageLimitEventContent?) {
|
||||||
|
const error = syncErrorData && syncErrorData.error && syncErrorData.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED";
|
||||||
|
if (error) {
|
||||||
|
usageLimitEventContent = syncErrorData.error.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usageLimitEventContent) {
|
||||||
|
showServerLimitToast(usageLimitEventContent.limit_type, usageLimitEventContent.admin_contact, error);
|
||||||
|
} else {
|
||||||
|
hideServerLimitToast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_updateServerNoticeEvents = async () => {
|
_updateServerNoticeEvents = async () => {
|
||||||
const roomLists = RoomListStoreTempProxy.getRoomLists();
|
const roomLists = RoomListStoreTempProxy.getRoomLists();
|
||||||
if (!roomLists[DefaultTagID.ServerNotice]) return [];
|
if (!roomLists[DefaultTagID.ServerNotice]) return [];
|
||||||
|
|
||||||
const pinnedEvents = [];
|
const events = [];
|
||||||
for (const room of roomLists[DefaultTagID.ServerNotice]) {
|
for (const room of roomLists[DefaultTagID.ServerNotice]) {
|
||||||
const pinStateEvent = room.currentState.getStateEvents("m.room.pinned_events", "");
|
const pinStateEvent = room.currentState.getStateEvents("m.room.pinned_events", "");
|
||||||
|
|
||||||
|
@ -318,12 +330,18 @@ class LoggedInView extends React.PureComponent<IProps, IState> {
|
||||||
for (const eventId of pinnedEventIds) {
|
for (const eventId of pinnedEventIds) {
|
||||||
const timeline = await this._matrixClient.getEventTimeline(room.getUnfilteredTimelineSet(), eventId, 0);
|
const timeline = await this._matrixClient.getEventTimeline(room.getUnfilteredTimelineSet(), eventId, 0);
|
||||||
const event = timeline.getEvents().find(ev => ev.getId() === eventId);
|
const event = timeline.getEvents().find(ev => ev.getId() === eventId);
|
||||||
if (event) pinnedEvents.push(event);
|
if (event) events.push(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.setState({
|
|
||||||
serverNoticeEvents: pinnedEvents,
|
const usageLimitEvent = events.find((e) => {
|
||||||
|
return (
|
||||||
|
e && e.getType() === 'm.room.message' &&
|
||||||
|
e.getContent()['server_notice_type'] === 'm.server_notice.usage_limit_reached'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._calculateServerLimitToast(this.state.syncErrorData, usageLimitEvent && usageLimitEvent.getContent());
|
||||||
};
|
};
|
||||||
|
|
||||||
_onPaste = (ev) => {
|
_onPaste = (ev) => {
|
||||||
|
@ -599,12 +617,7 @@ class LoggedInView extends React.PureComponent<IProps, IState> {
|
||||||
const GroupView = sdk.getComponent('structures.GroupView');
|
const GroupView = sdk.getComponent('structures.GroupView');
|
||||||
const MyGroups = sdk.getComponent('structures.MyGroups');
|
const MyGroups = sdk.getComponent('structures.MyGroups');
|
||||||
const ToastContainer = sdk.getComponent('structures.ToastContainer');
|
const ToastContainer = sdk.getComponent('structures.ToastContainer');
|
||||||
const MatrixToolbar = sdk.getComponent('globals.MatrixToolbar');
|
|
||||||
const CookieBar = sdk.getComponent('globals.CookieBar');
|
|
||||||
const NewVersionBar = sdk.getComponent('globals.NewVersionBar');
|
|
||||||
const UpdateCheckBar = sdk.getComponent('globals.UpdateCheckBar');
|
const UpdateCheckBar = sdk.getComponent('globals.UpdateCheckBar');
|
||||||
const PasswordNagBar = sdk.getComponent('globals.PasswordNagBar');
|
|
||||||
const ServerLimitBar = sdk.getComponent('globals.ServerLimitBar');
|
|
||||||
|
|
||||||
let pageElement;
|
let pageElement;
|
||||||
|
|
||||||
|
@ -648,40 +661,9 @@ class LoggedInView extends React.PureComponent<IProps, IState> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const usageLimitEvent = this.state.serverNoticeEvents.find((e) => {
|
|
||||||
return (
|
|
||||||
e && e.getType() === 'm.room.message' &&
|
|
||||||
e.getContent()['server_notice_type'] === 'm.server_notice.usage_limit_reached'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
let topBar;
|
let topBar;
|
||||||
if (this.state.syncErrorData && this.state.syncErrorData.error.errcode === 'M_RESOURCE_LIMIT_EXCEEDED') {
|
if (this.props.checkingForUpdate) {
|
||||||
topBar = <ServerLimitBar kind='hard'
|
|
||||||
adminContact={this.state.syncErrorData.error.data.admin_contact}
|
|
||||||
limitType={this.state.syncErrorData.error.data.limit_type}
|
|
||||||
/>;
|
|
||||||
} else if (usageLimitEvent) {
|
|
||||||
topBar = <ServerLimitBar kind='soft'
|
|
||||||
adminContact={usageLimitEvent.getContent().admin_contact}
|
|
||||||
limitType={usageLimitEvent.getContent().limit_type}
|
|
||||||
/>;
|
|
||||||
} else if (this.props.showCookieBar &&
|
|
||||||
this.props.config.piwik &&
|
|
||||||
navigator.doNotTrack !== "1"
|
|
||||||
) {
|
|
||||||
const policyUrl = this.props.config.piwik.policyUrl || null;
|
|
||||||
topBar = <CookieBar policyUrl={policyUrl} />;
|
|
||||||
} else if (this.props.hasNewVersion) {
|
|
||||||
topBar = <NewVersionBar version={this.props.version} newVersion={this.props.newVersion}
|
|
||||||
releaseNotes={this.props.newVersionReleaseNotes}
|
|
||||||
/>;
|
|
||||||
} else if (this.props.checkingForUpdate) {
|
|
||||||
topBar = <UpdateCheckBar {...this.props.checkingForUpdate} />;
|
topBar = <UpdateCheckBar {...this.props.checkingForUpdate} />;
|
||||||
} else if (this.state.userHasGeneratedPassword) {
|
|
||||||
topBar = <PasswordNagBar />;
|
|
||||||
} else if (this.props.showNotifierToolbar) {
|
|
||||||
topBar = <MatrixToolbar />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let bodyClasses = 'mx_MatrixChat';
|
let bodyClasses = 'mx_MatrixChat';
|
||||||
|
|
|
@ -67,6 +67,10 @@ import * as StorageManager from "../../utils/StorageManager";
|
||||||
import type LoggedInViewType from "./LoggedInView";
|
import type LoggedInViewType from "./LoggedInView";
|
||||||
import { ViewUserPayload } from "../../dispatcher/payloads/ViewUserPayload";
|
import { ViewUserPayload } from "../../dispatcher/payloads/ViewUserPayload";
|
||||||
import { Action } from "../../dispatcher/actions";
|
import { Action } from "../../dispatcher/actions";
|
||||||
|
import {
|
||||||
|
showToast as showAnalyticsToast,
|
||||||
|
hideToast as hideAnalyticsToast
|
||||||
|
} from "../../toasts/AnalyticsToast";
|
||||||
|
|
||||||
/** constants for MatrixChat.state.view */
|
/** constants for MatrixChat.state.view */
|
||||||
export enum Views {
|
export enum Views {
|
||||||
|
@ -168,12 +172,7 @@ interface IState {
|
||||||
leftDisabled: boolean;
|
leftDisabled: boolean;
|
||||||
middleDisabled: boolean;
|
middleDisabled: boolean;
|
||||||
// the right panel's disabled state is tracked in its store.
|
// the right panel's disabled state is tracked in its store.
|
||||||
version?: string;
|
|
||||||
newVersion?: string;
|
|
||||||
hasNewVersion: boolean;
|
|
||||||
newVersionReleaseNotes?: string;
|
|
||||||
checkingForUpdate?: string; // updateCheckStatusEnum
|
checkingForUpdate?: string; // updateCheckStatusEnum
|
||||||
showCookieBar: boolean;
|
|
||||||
// Parameters used in the registration dance with the IS
|
// Parameters used in the registration dance with the IS
|
||||||
register_client_secret?: string;
|
register_client_secret?: string;
|
||||||
register_session_id?: string;
|
register_session_id?: string;
|
||||||
|
@ -183,7 +182,6 @@ interface IState {
|
||||||
hideToSRUsers: boolean;
|
hideToSRUsers: boolean;
|
||||||
syncError?: Error;
|
syncError?: Error;
|
||||||
resizeNotifier: ResizeNotifier;
|
resizeNotifier: ResizeNotifier;
|
||||||
showNotifierToolbar: boolean;
|
|
||||||
serverConfig?: ValidatedServerConfig;
|
serverConfig?: ValidatedServerConfig;
|
||||||
ready: boolean;
|
ready: boolean;
|
||||||
thirdPartyInvite?: object;
|
thirdPartyInvite?: object;
|
||||||
|
@ -227,17 +225,12 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
leftDisabled: false,
|
leftDisabled: false,
|
||||||
middleDisabled: false,
|
middleDisabled: false,
|
||||||
|
|
||||||
hasNewVersion: false,
|
|
||||||
newVersionReleaseNotes: null,
|
|
||||||
checkingForUpdate: null,
|
checkingForUpdate: null,
|
||||||
|
|
||||||
showCookieBar: false,
|
|
||||||
|
|
||||||
hideToSRUsers: false,
|
hideToSRUsers: false,
|
||||||
|
|
||||||
syncError: null, // If the current syncing status is ERROR, the error object, otherwise null.
|
syncError: null, // If the current syncing status is ERROR, the error object, otherwise null.
|
||||||
resizeNotifier: new ResizeNotifier(),
|
resizeNotifier: new ResizeNotifier(),
|
||||||
showNotifierToolbar: false,
|
|
||||||
ready: false,
|
ready: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -338,12 +331,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SettingsStore.getValue("showCookieBar")) {
|
|
||||||
this.setState({
|
|
||||||
showCookieBar: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SettingsStore.getValue("analyticsOptIn")) {
|
if (SettingsStore.getValue("analyticsOptIn")) {
|
||||||
Analytics.enable();
|
Analytics.enable();
|
||||||
}
|
}
|
||||||
|
@ -685,9 +672,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
dis.dispatch({action: 'view_my_groups'});
|
dis.dispatch({action: 'view_my_groups'});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'notifier_enabled':
|
|
||||||
this.setState({showNotifierToolbar: Notifier.shouldShowToolbar()});
|
|
||||||
break;
|
|
||||||
case 'hide_left_panel':
|
case 'hide_left_panel':
|
||||||
this.setState({
|
this.setState({
|
||||||
collapseLhs: true,
|
collapseLhs: true,
|
||||||
|
@ -735,12 +719,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
case 'client_started':
|
case 'client_started':
|
||||||
this.onClientStarted();
|
this.onClientStarted();
|
||||||
break;
|
break;
|
||||||
case 'new_version':
|
|
||||||
this.onVersion(
|
|
||||||
payload.currentVersion, payload.newVersion,
|
|
||||||
payload.releaseNotes,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'check_updates':
|
case 'check_updates':
|
||||||
this.setState({ checkingForUpdate: payload.value });
|
this.setState({ checkingForUpdate: payload.value });
|
||||||
break;
|
break;
|
||||||
|
@ -760,19 +738,13 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
case 'accept_cookies':
|
case 'accept_cookies':
|
||||||
SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, true);
|
SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, true);
|
||||||
SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false);
|
SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false);
|
||||||
|
hideAnalyticsToast();
|
||||||
this.setState({
|
|
||||||
showCookieBar: false,
|
|
||||||
});
|
|
||||||
Analytics.enable();
|
Analytics.enable();
|
||||||
break;
|
break;
|
||||||
case 'reject_cookies':
|
case 'reject_cookies':
|
||||||
SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, false);
|
SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, false);
|
||||||
SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false);
|
SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false);
|
||||||
|
hideAnalyticsToast();
|
||||||
this.setState({
|
|
||||||
showCookieBar: false,
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1261,6 +1233,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageManager.tryPersistStorage();
|
StorageManager.tryPersistStorage();
|
||||||
|
|
||||||
|
if (SettingsStore.getValue("showCookieBar") && this.props.config.piwik && navigator.doNotTrack !== "1") {
|
||||||
|
showAnalyticsToast(this.props.config.piwik && this.props.config.piwik.policyUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private showScreenAfterLogin() {
|
private showScreenAfterLogin() {
|
||||||
|
@ -1391,7 +1367,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
dis.dispatch({action: 'focus_composer'});
|
dis.dispatch({action: 'focus_composer'});
|
||||||
this.setState({
|
this.setState({
|
||||||
ready: true,
|
ready: true,
|
||||||
showNotifierToolbar: Notifier.shouldShowToolbar(),
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
cli.on('Call.incoming', function(call) {
|
cli.on('Call.incoming', function(call) {
|
||||||
|
@ -1833,16 +1808,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
this.showScreen("settings");
|
this.showScreen("settings");
|
||||||
};
|
};
|
||||||
|
|
||||||
onVersion(current: string, latest: string, releaseNotes?: string) {
|
|
||||||
this.setState({
|
|
||||||
version: current,
|
|
||||||
newVersion: latest,
|
|
||||||
hasNewVersion: current !== latest,
|
|
||||||
newVersionReleaseNotes: releaseNotes,
|
|
||||||
checkingForUpdate: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onSendEvent(roomId: string, event: MatrixEvent) {
|
onSendEvent(roomId: string, event: MatrixEvent) {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
if (!cli) {
|
if (!cli) {
|
||||||
|
@ -2037,7 +2002,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
onCloseAllSettings={this.onCloseAllSettings}
|
onCloseAllSettings={this.onCloseAllSettings}
|
||||||
onRegistered={this.onRegistered}
|
onRegistered={this.onRegistered}
|
||||||
currentRoomId={this.state.currentRoomId}
|
currentRoomId={this.state.currentRoomId}
|
||||||
showCookieBar={this.state.showCookieBar}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,103 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2018 New Vector Ltd.
|
|
||||||
|
|
||||||
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 PropTypes from 'prop-types';
|
|
||||||
import dis from '../../../dispatcher/dispatcher';
|
|
||||||
import { _t } from '../../../languageHandler';
|
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import Analytics from '../../../Analytics';
|
|
||||||
|
|
||||||
export default class CookieBar extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
policyUrl: PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
onUsageDataClicked(e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
Analytics.showDetailsModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
onAccept() {
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'accept_cookies',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onReject() {
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'reject_cookies',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
|
||||||
const toolbarClasses = "mx_MatrixToolbar";
|
|
||||||
return (
|
|
||||||
<div className={toolbarClasses}>
|
|
||||||
<img className="mx_MatrixToolbar_warning" src={require("../../../../res/img/warning.svg")} width="24" height="23" alt="" />
|
|
||||||
<div className="mx_MatrixToolbar_content">
|
|
||||||
{ this.props.policyUrl ? _t(
|
|
||||||
"Please help improve Riot.im by sending <UsageDataLink>anonymous usage data</UsageDataLink>. " +
|
|
||||||
"This will use a cookie " +
|
|
||||||
"(please see our <PolicyLink>Cookie Policy</PolicyLink>).",
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
'UsageDataLink': (sub) => <a
|
|
||||||
className="mx_MatrixToolbar_link"
|
|
||||||
onClick={this.onUsageDataClicked}
|
|
||||||
>
|
|
||||||
{ sub }
|
|
||||||
</a>,
|
|
||||||
// XXX: We need to link to the page that explains our cookies
|
|
||||||
'PolicyLink': (sub) => <a
|
|
||||||
className="mx_MatrixToolbar_link"
|
|
||||||
target="_blank"
|
|
||||||
href={this.props.policyUrl}
|
|
||||||
>
|
|
||||||
{ sub }
|
|
||||||
</a>
|
|
||||||
,
|
|
||||||
},
|
|
||||||
) : _t(
|
|
||||||
"Please help improve Riot.im by sending <UsageDataLink>anonymous usage data</UsageDataLink>. " +
|
|
||||||
"This will use a cookie.",
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
'UsageDataLink': (sub) => <a
|
|
||||||
className="mx_MatrixToolbar_link"
|
|
||||||
onClick={this.onUsageDataClicked}
|
|
||||||
>
|
|
||||||
{ sub }
|
|
||||||
</a>,
|
|
||||||
},
|
|
||||||
) }
|
|
||||||
</div>
|
|
||||||
<AccessibleButton element='button' className="mx_MatrixToolbar_action" onClick={this.onAccept}>
|
|
||||||
{ _t("Yes, I want to help!") }
|
|
||||||
</AccessibleButton>
|
|
||||||
<AccessibleButton className="mx_MatrixToolbar_close" onClick={this.onReject}>
|
|
||||||
<img src={require("../../../../res/img/cancel.svg")} width="18" height="18" alt={_t('Close')} />
|
|
||||||
</AccessibleButton>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2015, 2016 OpenMarket Ltd
|
|
||||||
|
|
||||||
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 createReactClass from 'create-react-class';
|
|
||||||
import { _t } from '../../../languageHandler';
|
|
||||||
import Notifier from '../../../Notifier';
|
|
||||||
import AccessibleButton from '../../../components/views/elements/AccessibleButton';
|
|
||||||
|
|
||||||
export default createReactClass({
|
|
||||||
displayName: 'MatrixToolbar',
|
|
||||||
|
|
||||||
hideToolbar: function() {
|
|
||||||
Notifier.setToolbarHidden(true);
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function() {
|
|
||||||
Notifier.setEnabled(true);
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
return (
|
|
||||||
<div className="mx_MatrixToolbar">
|
|
||||||
<img className="mx_MatrixToolbar_warning" src={require("../../../../res/img/warning.svg")} width="24" height="23" alt="" />
|
|
||||||
<div className="mx_MatrixToolbar_content">
|
|
||||||
{ _t('You are not receiving desktop notifications') } <a className="mx_MatrixToolbar_link" onClick={ this.onClick }> { _t('Enable them now') }</a>
|
|
||||||
</div>
|
|
||||||
<AccessibleButton className="mx_MatrixToolbar_close" onClick={ this.hideToolbar } ><img src={require("../../../../res/img/cancel.svg")} width="18" height="18" alt={_t('Close')} /></AccessibleButton>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,108 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2015, 2016 OpenMarket Ltd
|
|
||||||
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
|
||||||
|
|
||||||
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 PropTypes from 'prop-types';
|
|
||||||
import createReactClass from 'create-react-class';
|
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import Modal from '../../../Modal';
|
|
||||||
import PlatformPeg from '../../../PlatformPeg';
|
|
||||||
import { _t } from '../../../languageHandler';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check a version string is compatible with the Changelog
|
|
||||||
* dialog ([vectorversion]-react-[react-sdk-version]-js-[js-sdk-version])
|
|
||||||
*/
|
|
||||||
function checkVersion(ver) {
|
|
||||||
const parts = ver.split('-');
|
|
||||||
return parts.length == 5 && parts[1] == 'react' && parts[3] == 'js';
|
|
||||||
}
|
|
||||||
|
|
||||||
export default createReactClass({
|
|
||||||
propTypes: {
|
|
||||||
version: PropTypes.string.isRequired,
|
|
||||||
newVersion: PropTypes.string.isRequired,
|
|
||||||
releaseNotes: PropTypes.string,
|
|
||||||
},
|
|
||||||
|
|
||||||
displayReleaseNotes: function(releaseNotes) {
|
|
||||||
const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog');
|
|
||||||
Modal.createTrackedDialog('Display release notes', '', QuestionDialog, {
|
|
||||||
title: _t("What's New"),
|
|
||||||
description: <div className="mx_MatrixToolbar_changelog">{releaseNotes}</div>,
|
|
||||||
button: _t("Update"),
|
|
||||||
onFinished: (update) => {
|
|
||||||
if (update && PlatformPeg.get()) {
|
|
||||||
PlatformPeg.get().installUpdate();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
displayChangelog: function() {
|
|
||||||
const ChangelogDialog = sdk.getComponent('dialogs.ChangelogDialog');
|
|
||||||
Modal.createTrackedDialog('Display Changelog', '', ChangelogDialog, {
|
|
||||||
version: this.props.version,
|
|
||||||
newVersion: this.props.newVersion,
|
|
||||||
onFinished: (update) => {
|
|
||||||
if (update && PlatformPeg.get()) {
|
|
||||||
PlatformPeg.get().installUpdate();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onUpdateClicked: function() {
|
|
||||||
PlatformPeg.get().installUpdate();
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
let action_button;
|
|
||||||
// If we have release notes to display, we display them. Otherwise,
|
|
||||||
// we display the Changelog Dialog which takes two versions and
|
|
||||||
// automatically tells you what's changed (provided the versions
|
|
||||||
// are in the right format)
|
|
||||||
if (this.props.releaseNotes) {
|
|
||||||
action_button = (
|
|
||||||
<button className="mx_MatrixToolbar_action" onClick={this.displayReleaseNotes}>
|
|
||||||
{ _t("What's new?") }
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
} else if (checkVersion(this.props.version) && checkVersion(this.props.newVersion)) {
|
|
||||||
action_button = (
|
|
||||||
<button className="mx_MatrixToolbar_action" onClick={this.displayChangelog}>
|
|
||||||
{ _t("What's new?") }
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
} else if (PlatformPeg.get()) {
|
|
||||||
action_button = (
|
|
||||||
<button className="mx_MatrixToolbar_action" onClick={this.onUpdateClicked}>
|
|
||||||
{ _t("Update") }
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className="mx_MatrixToolbar">
|
|
||||||
<img className="mx_MatrixToolbar_warning" src={require("../../../../res/img/warning.svg")} width="24" height="23" alt="" />
|
|
||||||
<div className="mx_MatrixToolbar_content">
|
|
||||||
{_t("A new version of Riot is available.")}
|
|
||||||
</div>
|
|
||||||
{action_button}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 Vector Creations Ltd
|
|
||||||
Copyright 2018 New Vector Ltd
|
|
||||||
|
|
||||||
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 createReactClass from 'create-react-class';
|
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import Modal from '../../../Modal';
|
|
||||||
import { _t } from '../../../languageHandler';
|
|
||||||
|
|
||||||
export default createReactClass({
|
|
||||||
onUpdateClicked: function() {
|
|
||||||
const SetPasswordDialog = sdk.getComponent('dialogs.SetPasswordDialog');
|
|
||||||
Modal.createTrackedDialog('Set Password Dialog', 'Password Nag Bar', SetPasswordDialog);
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
const toolbarClasses = "mx_MatrixToolbar mx_MatrixToolbar_clickable";
|
|
||||||
return (
|
|
||||||
<div className={toolbarClasses} onClick={this.onUpdateClicked}>
|
|
||||||
<img className="mx_MatrixToolbar_warning"
|
|
||||||
src={require("../../../../res/img/warning.svg")}
|
|
||||||
width="24"
|
|
||||||
height="23"
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
<div className="mx_MatrixToolbar_content">
|
|
||||||
{ _t(
|
|
||||||
"To return to your account in future you need to <u>set a password</u>",
|
|
||||||
{},
|
|
||||||
{ 'u': (sub) => <u>{ sub }</u> },
|
|
||||||
) }
|
|
||||||
</div>
|
|
||||||
<button className="mx_MatrixToolbar_action">
|
|
||||||
{ _t("Set Password") }
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,99 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2018 New Vector Ltd
|
|
||||||
|
|
||||||
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 PropTypes from 'prop-types';
|
|
||||||
import createReactClass from 'create-react-class';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { _td } from '../../../languageHandler';
|
|
||||||
import { messageForResourceLimitError } from '../../../utils/ErrorUtils';
|
|
||||||
|
|
||||||
export default createReactClass({
|
|
||||||
propTypes: {
|
|
||||||
// 'hard' if the logged in user has been locked out, 'soft' if they haven't
|
|
||||||
kind: PropTypes.string,
|
|
||||||
adminContact: PropTypes.string,
|
|
||||||
// The type of limit that has been hit.
|
|
||||||
limitType: PropTypes.string.isRequired,
|
|
||||||
},
|
|
||||||
|
|
||||||
getDefaultProps: function() {
|
|
||||||
return {
|
|
||||||
kind: 'hard',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
const toolbarClasses = {
|
|
||||||
'mx_MatrixToolbar': true,
|
|
||||||
};
|
|
||||||
|
|
||||||
let adminContact;
|
|
||||||
let limitError;
|
|
||||||
if (this.props.kind === 'hard') {
|
|
||||||
toolbarClasses['mx_MatrixToolbar_error'] = true;
|
|
||||||
|
|
||||||
adminContact = messageForResourceLimitError(
|
|
||||||
this.props.limitType,
|
|
||||||
this.props.adminContact,
|
|
||||||
{
|
|
||||||
'': _td("Please <a>contact your service administrator</a> to continue using the service."),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
limitError = messageForResourceLimitError(
|
|
||||||
this.props.limitType,
|
|
||||||
this.props.adminContact,
|
|
||||||
{
|
|
||||||
'monthly_active_user': _td("This homeserver has hit its Monthly Active User limit."),
|
|
||||||
'': _td("This homeserver has exceeded one of its resource limits."),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
toolbarClasses['mx_MatrixToolbar_info'] = true;
|
|
||||||
adminContact = messageForResourceLimitError(
|
|
||||||
this.props.limitType,
|
|
||||||
this.props.adminContact,
|
|
||||||
{
|
|
||||||
'': _td("Please <a>contact your service administrator</a> to get this limit increased."),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
limitError = messageForResourceLimitError(
|
|
||||||
this.props.limitType,
|
|
||||||
this.props.adminContact,
|
|
||||||
{
|
|
||||||
'monthly_active_user': _td(
|
|
||||||
"This homeserver has hit its Monthly Active User limit so " +
|
|
||||||
"<b>some users will not be able to log in</b>.",
|
|
||||||
),
|
|
||||||
'': _td(
|
|
||||||
"This homeserver has exceeded one of its resource limits so " +
|
|
||||||
"<b>some users will not be able to log in</b>.",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{'b': sub => <b>{sub}</b>},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className={classNames(toolbarClasses)}>
|
|
||||||
<div className="mx_MatrixToolbar_content">
|
|
||||||
{limitError}
|
|
||||||
{' '}
|
|
||||||
{adminContact}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2015, 2016 OpenMarket Ltd
|
|
||||||
|
|
||||||
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 createReactClass from 'create-react-class';
|
|
||||||
import Notifier from "../../../Notifier";
|
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
|
||||||
import { _t } from '../../../languageHandler';
|
|
||||||
|
|
||||||
export default createReactClass({
|
|
||||||
displayName: 'EnableNotificationsButton',
|
|
||||||
|
|
||||||
componentDidMount: function() {
|
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUnmount: function() {
|
|
||||||
dis.unregister(this.dispatcherRef);
|
|
||||||
},
|
|
||||||
|
|
||||||
onAction: function(payload) {
|
|
||||||
if (payload.action !== "notifier_enabled") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.forceUpdate();
|
|
||||||
},
|
|
||||||
|
|
||||||
enabled: function() {
|
|
||||||
return Notifier.isEnabled();
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function() {
|
|
||||||
const self = this;
|
|
||||||
if (!Notifier.supportsDesktopNotifications()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!Notifier.isEnabled()) {
|
|
||||||
Notifier.setEnabled(true, function() {
|
|
||||||
self.forceUpdate();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Notifier.setEnabled(false);
|
|
||||||
}
|
|
||||||
this.forceUpdate();
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
if (this.enabled()) {
|
|
||||||
return (
|
|
||||||
<button className="mx_EnableNotificationsButton" onClick={this.onClick}>
|
|
||||||
{ _t("Disable Notifications") }
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<button className="mx_EnableNotificationsButton" onClick={this.onClick}>
|
|
||||||
{ _t("Enable Notifications") }
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -391,10 +391,26 @@
|
||||||
"Common names and surnames are easy to guess": "Common names and surnames are easy to guess",
|
"Common names and surnames are easy to guess": "Common names and surnames are easy to guess",
|
||||||
"Straight rows of keys are easy to guess": "Straight rows of keys are easy to guess",
|
"Straight rows of keys are easy to guess": "Straight rows of keys are easy to guess",
|
||||||
"Short keyboard patterns are easy to guess": "Short keyboard patterns are easy to guess",
|
"Short keyboard patterns are easy to guess": "Short keyboard patterns are easy to guess",
|
||||||
|
"Help us improve Riot": "Help us improve Riot",
|
||||||
|
"Send <UsageDataLink>anonymous usage data</UsageDataLink> which helps us improve Riot. This will use a <PolicyLink>cookie</PolicyLink>.": "Send <UsageDataLink>anonymous usage data</UsageDataLink> which helps us improve Riot. This will use a <PolicyLink>cookie</PolicyLink>.",
|
||||||
|
"I want to help": "I want to help",
|
||||||
|
"No": "No",
|
||||||
"Review where you’re logged in": "Review where you’re logged in",
|
"Review where you’re logged in": "Review where you’re logged in",
|
||||||
"Verify all your sessions to ensure your account & messages are safe": "Verify all your sessions to ensure your account & messages are safe",
|
"Verify all your sessions to ensure your account & messages are safe": "Verify all your sessions to ensure your account & messages are safe",
|
||||||
"Review": "Review",
|
"Review": "Review",
|
||||||
"Later": "Later",
|
"Later": "Later",
|
||||||
|
"Notifications": "Notifications",
|
||||||
|
"You are not receiving desktop notifications": "You are not receiving desktop notifications",
|
||||||
|
"Enable them now": "Enable them now",
|
||||||
|
"Close": "Close",
|
||||||
|
"Your homeserver has exceeded its user limit.": "Your homeserver has exceeded its user limit.",
|
||||||
|
"Your homeserver has exceeded one of its resource limits.": "Your homeserver has exceeded one of its resource limits.",
|
||||||
|
"Contact your <a>server admin</a>.": "Contact your <a>server admin</a>.",
|
||||||
|
"Warning": "Warning",
|
||||||
|
"Ok": "Ok",
|
||||||
|
"Set password": "Set password",
|
||||||
|
"To return to your account in future you need to set a password": "To return to your account in future you need to set a password",
|
||||||
|
"Set Password": "Set Password",
|
||||||
"Set up encryption": "Set up encryption",
|
"Set up encryption": "Set up encryption",
|
||||||
"Encryption upgrade available": "Encryption upgrade available",
|
"Encryption upgrade available": "Encryption upgrade available",
|
||||||
"Verify this session": "Verify this session",
|
"Verify this session": "Verify this session",
|
||||||
|
@ -405,6 +421,12 @@
|
||||||
"Other users may not trust it": "Other users may not trust it",
|
"Other users may not trust it": "Other users may not trust it",
|
||||||
"New login. Was this you?": "New login. Was this you?",
|
"New login. Was this you?": "New login. Was this you?",
|
||||||
"Verify the new login accessing your account: %(name)s": "Verify the new login accessing your account: %(name)s",
|
"Verify the new login accessing your account: %(name)s": "Verify the new login accessing your account: %(name)s",
|
||||||
|
"What's new?": "What's new?",
|
||||||
|
"What's New": "What's New",
|
||||||
|
"Update": "Update",
|
||||||
|
"Restart": "Restart",
|
||||||
|
"Upgrade your Riot": "Upgrade your Riot",
|
||||||
|
"A new version of Riot is available!": "A new version of Riot is available!",
|
||||||
"There was an error joining the room": "There was an error joining the room",
|
"There was an error joining the room": "There was an error joining the room",
|
||||||
"Sorry, your homeserver is too old to participate in this room.": "Sorry, your homeserver is too old to participate in this room.",
|
"Sorry, your homeserver is too old to participate in this room.": "Sorry, your homeserver is too old to participate in this room.",
|
||||||
"Please contact your homeserver administrator.": "Please contact your homeserver administrator.",
|
"Please contact your homeserver administrator.": "Please contact your homeserver administrator.",
|
||||||
|
@ -643,8 +665,6 @@
|
||||||
"Last seen": "Last seen",
|
"Last seen": "Last seen",
|
||||||
"Failed to set display name": "Failed to set display name",
|
"Failed to set display name": "Failed to set display name",
|
||||||
"Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.",
|
"Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.",
|
||||||
"Disable Notifications": "Disable Notifications",
|
|
||||||
"Enable Notifications": "Enable Notifications",
|
|
||||||
"Securely cache encrypted messages locally for them to appear in search results, using ": "Securely cache encrypted messages locally for them to appear in search results, using ",
|
"Securely cache encrypted messages locally for them to appear in search results, using ": "Securely cache encrypted messages locally for them to appear in search results, using ",
|
||||||
" to store messages from ": " to store messages from ",
|
" to store messages from ": " to store messages from ",
|
||||||
"rooms.": "rooms.",
|
"rooms.": "rooms.",
|
||||||
|
@ -776,7 +796,6 @@
|
||||||
"Account management": "Account management",
|
"Account management": "Account management",
|
||||||
"Deactivating your account is a permanent action - be careful!": "Deactivating your account is a permanent action - be careful!",
|
"Deactivating your account is a permanent action - be careful!": "Deactivating your account is a permanent action - be careful!",
|
||||||
"Deactivate Account": "Deactivate Account",
|
"Deactivate Account": "Deactivate Account",
|
||||||
"Warning": "Warning",
|
|
||||||
"General": "General",
|
"General": "General",
|
||||||
"Discovery": "Discovery",
|
"Discovery": "Discovery",
|
||||||
"Deactivate account": "Deactivate account",
|
"Deactivate account": "Deactivate account",
|
||||||
|
@ -815,7 +834,6 @@
|
||||||
"Ban list rules - %(roomName)s": "Ban list rules - %(roomName)s",
|
"Ban list rules - %(roomName)s": "Ban list rules - %(roomName)s",
|
||||||
"Server rules": "Server rules",
|
"Server rules": "Server rules",
|
||||||
"User rules": "User rules",
|
"User rules": "User rules",
|
||||||
"Close": "Close",
|
|
||||||
"You have not ignored anyone.": "You have not ignored anyone.",
|
"You have not ignored anyone.": "You have not ignored anyone.",
|
||||||
"You are currently ignoring:": "You are currently ignoring:",
|
"You are currently ignoring:": "You are currently ignoring:",
|
||||||
"You are not subscribed to any lists": "You are not subscribed to any lists",
|
"You are not subscribed to any lists": "You are not subscribed to any lists",
|
||||||
|
@ -836,7 +854,6 @@
|
||||||
"If this isn't what you want, please use a different tool to ignore users.": "If this isn't what you want, please use a different tool to ignore users.",
|
"If this isn't what you want, please use a different tool to ignore users.": "If this isn't what you want, please use a different tool to ignore users.",
|
||||||
"Room ID or address of ban list": "Room ID or address of ban list",
|
"Room ID or address of ban list": "Room ID or address of ban list",
|
||||||
"Subscribe": "Subscribe",
|
"Subscribe": "Subscribe",
|
||||||
"Notifications": "Notifications",
|
|
||||||
"Start automatically after system login": "Start automatically after system login",
|
"Start automatically after system login": "Start automatically after system login",
|
||||||
"Always show the window menu bar": "Always show the window menu bar",
|
"Always show the window menu bar": "Always show the window menu bar",
|
||||||
"Show tray icon and minimize window to it on close": "Show tray icon and minimize window to it on close",
|
"Show tray icon and minimize window to it on close": "Show tray icon and minimize window to it on close",
|
||||||
|
@ -1287,7 +1304,6 @@
|
||||||
"Verify by emoji": "Verify by emoji",
|
"Verify by emoji": "Verify by emoji",
|
||||||
"Almost there! Is your other session showing the same shield?": "Almost there! Is your other session showing the same shield?",
|
"Almost there! Is your other session showing the same shield?": "Almost there! Is your other session showing the same shield?",
|
||||||
"Almost there! Is %(displayName)s showing the same shield?": "Almost there! Is %(displayName)s showing the same shield?",
|
"Almost there! Is %(displayName)s showing the same shield?": "Almost there! Is %(displayName)s showing the same shield?",
|
||||||
"No": "No",
|
|
||||||
"Yes": "Yes",
|
"Yes": "Yes",
|
||||||
"Verify all users in a room to ensure it's secure.": "Verify all users in a room to ensure it's secure.",
|
"Verify all users in a room to ensure it's secure.": "Verify all users in a room to ensure it's secure.",
|
||||||
"In encrypted rooms, verify all users to ensure it’s secure.": "In encrypted rooms, verify all users to ensure it’s secure.",
|
"In encrypted rooms, verify all users to ensure it’s secure.": "In encrypted rooms, verify all users to ensure it’s secure.",
|
||||||
|
@ -1381,20 +1397,6 @@
|
||||||
"Something went wrong when trying to get your communities.": "Something went wrong when trying to get your communities.",
|
"Something went wrong when trying to get your communities.": "Something went wrong when trying to get your communities.",
|
||||||
"Display your community flair in rooms configured to show it.": "Display your community flair in rooms configured to show it.",
|
"Display your community flair in rooms configured to show it.": "Display your community flair in rooms configured to show it.",
|
||||||
"You're not currently a member of any communities.": "You're not currently a member of any communities.",
|
"You're not currently a member of any communities.": "You're not currently a member of any communities.",
|
||||||
"Please help improve Riot.im by sending <UsageDataLink>anonymous usage data</UsageDataLink>. This will use a cookie (please see our <PolicyLink>Cookie Policy</PolicyLink>).": "Please help improve Riot.im by sending <UsageDataLink>anonymous usage data</UsageDataLink>. This will use a cookie (please see our <PolicyLink>Cookie Policy</PolicyLink>).",
|
|
||||||
"Please help improve Riot.im by sending <UsageDataLink>anonymous usage data</UsageDataLink>. This will use a cookie.": "Please help improve Riot.im by sending <UsageDataLink>anonymous usage data</UsageDataLink>. This will use a cookie.",
|
|
||||||
"Yes, I want to help!": "Yes, I want to help!",
|
|
||||||
"You are not receiving desktop notifications": "You are not receiving desktop notifications",
|
|
||||||
"Enable them now": "Enable them now",
|
|
||||||
"What's New": "What's New",
|
|
||||||
"Update": "Update",
|
|
||||||
"What's new?": "What's new?",
|
|
||||||
"A new version of Riot is available.": "A new version of Riot is available.",
|
|
||||||
"To return to your account in future you need to <u>set a password</u>": "To return to your account in future you need to <u>set a password</u>",
|
|
||||||
"Set Password": "Set Password",
|
|
||||||
"Please <a>contact your service administrator</a> to get this limit increased.": "Please <a>contact your service administrator</a> to get this limit increased.",
|
|
||||||
"This homeserver has hit its Monthly Active User limit so <b>some users will not be able to log in</b>.": "This homeserver has hit its Monthly Active User limit so <b>some users will not be able to log in</b>.",
|
|
||||||
"This homeserver has exceeded one of its resource limits so <b>some users will not be able to log in</b>.": "This homeserver has exceeded one of its resource limits so <b>some users will not be able to log in</b>.",
|
|
||||||
"Error encountered (%(errorDetail)s).": "Error encountered (%(errorDetail)s).",
|
"Error encountered (%(errorDetail)s).": "Error encountered (%(errorDetail)s).",
|
||||||
"Checking for an update...": "Checking for an update...",
|
"Checking for an update...": "Checking for an update...",
|
||||||
"No update available.": "No update available.",
|
"No update available.": "No update available.",
|
||||||
|
|
|
@ -68,13 +68,15 @@ export default class ToastStore extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
dismissToast(key) {
|
dismissToast(key) {
|
||||||
|
if (this.toasts[0] && this.toasts[0].key === key) {
|
||||||
|
this.countSeen++;
|
||||||
|
}
|
||||||
|
|
||||||
const length = this.toasts.length;
|
const length = this.toasts.length;
|
||||||
this.toasts = this.toasts.filter(t => t.key !== key);
|
this.toasts = this.toasts.filter(t => t.key !== key);
|
||||||
if (length !== this.toasts.length) {
|
if (length !== this.toasts.length) {
|
||||||
if (this.toasts.length === 0) {
|
if (this.toasts.length === 0) {
|
||||||
this.countSeen = 0;
|
this.countSeen = 0;
|
||||||
} else {
|
|
||||||
this.countSeen++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('update');
|
this.emit('update');
|
||||||
|
|
77
src/toasts/AnalyticsToast.tsx
Normal file
77
src/toasts/AnalyticsToast.tsx
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 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 { _t } from "../languageHandler";
|
||||||
|
import dis from "../dispatcher/dispatcher";
|
||||||
|
import Analytics from "../Analytics";
|
||||||
|
import AccessibleButton from "../components/views/elements/AccessibleButton";
|
||||||
|
import GenericToast from "../components/views/toasts/GenericToast";
|
||||||
|
import ToastStore from "../stores/ToastStore";
|
||||||
|
|
||||||
|
const onAccept = () => {
|
||||||
|
console.log("DEBUG onAccept AnalyticsToast");
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'accept_cookies',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onReject = () => {
|
||||||
|
console.log("DEBUG onReject AnalyticsToast");
|
||||||
|
dis.dispatch({
|
||||||
|
action: "reject_cookies",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onUsageDataClicked = () => {
|
||||||
|
Analytics.showDetailsModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const TOAST_KEY = "analytics";
|
||||||
|
|
||||||
|
export const showToast = (policyUrl?: string) => {
|
||||||
|
ToastStore.sharedInstance().addOrReplaceToast({
|
||||||
|
key: TOAST_KEY,
|
||||||
|
title: _t("Help us improve Riot"),
|
||||||
|
props: {
|
||||||
|
description: _t(
|
||||||
|
"Send <UsageDataLink>anonymous usage data</UsageDataLink> which helps us improve Riot. " +
|
||||||
|
"This will use a <PolicyLink>cookie</PolicyLink>.",
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
"UsageDataLink": (sub) => (
|
||||||
|
<AccessibleButton kind="link" onClick={onUsageDataClicked}>{ sub }</AccessibleButton>
|
||||||
|
),
|
||||||
|
// XXX: We need to link to the page that explains our cookies
|
||||||
|
"PolicyLink": (sub) => policyUrl ? (
|
||||||
|
<a target="_blank" href={policyUrl}>{ sub }</a>
|
||||||
|
) : sub,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
acceptLabel: _t("I want to help"),
|
||||||
|
onAccept,
|
||||||
|
rejectLabel: _t("No"),
|
||||||
|
onReject,
|
||||||
|
},
|
||||||
|
component: GenericToast,
|
||||||
|
priority: 10,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hideToast = () => {
|
||||||
|
ToastStore.sharedInstance().dismissToast(TOAST_KEY);
|
||||||
|
};
|
50
src/toasts/DesktopNotificationsToast.ts
Normal file
50
src/toasts/DesktopNotificationsToast.ts
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 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 { _t } from "../languageHandler";
|
||||||
|
import Notifier from "../Notifier";
|
||||||
|
import GenericToast from "../components/views/toasts/GenericToast";
|
||||||
|
import ToastStore from "../stores/ToastStore";
|
||||||
|
|
||||||
|
const onAccept = () => {
|
||||||
|
Notifier.setEnabled(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onReject = () => {
|
||||||
|
Notifier.setToolbarHidden(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TOAST_KEY = "desktopnotifications";
|
||||||
|
|
||||||
|
export const showToast = () => {
|
||||||
|
ToastStore.sharedInstance().addOrReplaceToast({
|
||||||
|
key: TOAST_KEY,
|
||||||
|
title: _t("Notifications"),
|
||||||
|
props: {
|
||||||
|
description: _t("You are not receiving desktop notifications"),
|
||||||
|
acceptLabel: _t("Enable them now"),
|
||||||
|
onAccept,
|
||||||
|
rejectLabel: _t("Close"),
|
||||||
|
onReject,
|
||||||
|
},
|
||||||
|
component: GenericToast,
|
||||||
|
priority: 30,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hideToast = () => {
|
||||||
|
ToastStore.sharedInstance().dismissToast(TOAST_KEY);
|
||||||
|
};
|
50
src/toasts/ServerLimitToast.tsx
Normal file
50
src/toasts/ServerLimitToast.tsx
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 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 { _t, _td } from "../languageHandler";
|
||||||
|
import GenericToast from "../components/views/toasts/GenericToast";
|
||||||
|
import ToastStore from "../stores/ToastStore";
|
||||||
|
import {messageForResourceLimitError} from "../utils/ErrorUtils";
|
||||||
|
|
||||||
|
const TOAST_KEY = "serverlimit";
|
||||||
|
|
||||||
|
export const showToast = (limitType: string, adminContact?: string, syncError?: boolean) => {
|
||||||
|
const errorText = messageForResourceLimitError(limitType, adminContact, {
|
||||||
|
'monthly_active_user': _td("Your homeserver has exceeded its user limit."),
|
||||||
|
'': _td("Your homeserver has exceeded one of its resource limits."),
|
||||||
|
});
|
||||||
|
const contactText = messageForResourceLimitError(limitType, adminContact, {
|
||||||
|
'': _td("Contact your <a>server admin</a>."),
|
||||||
|
});
|
||||||
|
|
||||||
|
ToastStore.sharedInstance().addOrReplaceToast({
|
||||||
|
key: TOAST_KEY,
|
||||||
|
title: _t("Warning"),
|
||||||
|
props: {
|
||||||
|
description: <React.Fragment>{errorText} {contactText}</React.Fragment>,
|
||||||
|
acceptLabel: _t("Ok"),
|
||||||
|
onAccept: hideToast,
|
||||||
|
},
|
||||||
|
component: GenericToast,
|
||||||
|
priority: 70,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hideToast = () => {
|
||||||
|
ToastStore.sharedInstance().dismissToast(TOAST_KEY);
|
||||||
|
};
|
47
src/toasts/SetPasswordToast.ts
Normal file
47
src/toasts/SetPasswordToast.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 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 { _t } from "../languageHandler";
|
||||||
|
import Modal from "../Modal";
|
||||||
|
import SetPasswordDialog from "../components/views/dialogs/SetPasswordDialog";
|
||||||
|
import GenericToast from "../components/views/toasts/GenericToast";
|
||||||
|
import ToastStore from "../stores/ToastStore";
|
||||||
|
|
||||||
|
const onAccept = () => {
|
||||||
|
Modal.createTrackedDialog('Set Password Dialog', 'Password Nag Bar', SetPasswordDialog);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TOAST_KEY = "setpassword";
|
||||||
|
|
||||||
|
export const showToast = () => {
|
||||||
|
ToastStore.sharedInstance().addOrReplaceToast({
|
||||||
|
key: TOAST_KEY,
|
||||||
|
title: _t("Set password"),
|
||||||
|
props: {
|
||||||
|
description: _t("To return to your account in future you need to set a password"),
|
||||||
|
acceptLabel: _t("Set Password"),
|
||||||
|
onAccept,
|
||||||
|
rejectLabel: _t("Later"),
|
||||||
|
onReject: hideToast, // it'll return on reload
|
||||||
|
},
|
||||||
|
component: GenericToast,
|
||||||
|
priority: 60,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hideToast = () => {
|
||||||
|
ToastStore.sharedInstance().dismissToast(TOAST_KEY);
|
||||||
|
};
|
90
src/toasts/UpdateToast.tsx
Normal file
90
src/toasts/UpdateToast.tsx
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 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 { _t } from "../languageHandler";
|
||||||
|
import GenericToast from "../components/views/toasts/GenericToast";
|
||||||
|
import ToastStore from "../stores/ToastStore";
|
||||||
|
import QuestionDialog from "../components/views/dialogs/QuestionDialog";
|
||||||
|
import ChangelogDialog from "../components/views/dialogs/ChangelogDialog";
|
||||||
|
import PlatformPeg from "../PlatformPeg";
|
||||||
|
import Modal from "../Modal";
|
||||||
|
|
||||||
|
const TOAST_KEY = "update";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check a version string is compatible with the Changelog
|
||||||
|
* dialog ([riot-version]-react-[react-sdk-version]-js-[js-sdk-version])
|
||||||
|
*/
|
||||||
|
function checkVersion(ver) {
|
||||||
|
const parts = ver.split('-');
|
||||||
|
return parts.length === 5 && parts[1] === 'react' && parts[3] === 'js';
|
||||||
|
}
|
||||||
|
|
||||||
|
function installUpdate() {
|
||||||
|
PlatformPeg.get().installUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
export const showToast = (version: string, newVersion: string, releaseNotes?: string) => {
|
||||||
|
let onAccept;
|
||||||
|
let acceptLabel = _t("What's new?");
|
||||||
|
if (releaseNotes) {
|
||||||
|
onAccept = () => {
|
||||||
|
Modal.createTrackedDialog('Display release notes', '', QuestionDialog, {
|
||||||
|
title: _t("What's New"),
|
||||||
|
description: <pre>{releaseNotes}</pre>,
|
||||||
|
button: _t("Update"),
|
||||||
|
onFinished: (update) => {
|
||||||
|
if (update && PlatformPeg.get()) {
|
||||||
|
PlatformPeg.get().installUpdate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
} else if (checkVersion(version) && checkVersion(newVersion)) {
|
||||||
|
onAccept = () => {
|
||||||
|
Modal.createTrackedDialog('Display Changelog', '', ChangelogDialog, {
|
||||||
|
version,
|
||||||
|
newVersion,
|
||||||
|
onFinished: (update) => {
|
||||||
|
if (update && PlatformPeg.get()) {
|
||||||
|
PlatformPeg.get().installUpdate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
onAccept = installUpdate;
|
||||||
|
acceptLabel = _t("Restart");
|
||||||
|
}
|
||||||
|
|
||||||
|
ToastStore.sharedInstance().addOrReplaceToast({
|
||||||
|
key: TOAST_KEY,
|
||||||
|
title: _t("Upgrade your Riot"),
|
||||||
|
props: {
|
||||||
|
description: _t("A new version of Riot is available!"),
|
||||||
|
acceptLabel,
|
||||||
|
onAccept,
|
||||||
|
},
|
||||||
|
component: GenericToast,
|
||||||
|
priority: 20,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hideToast = () => {
|
||||||
|
ToastStore.sharedInstance().dismissToast(TOAST_KEY);
|
||||||
|
};
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
|
|
||||||
const {range} = require('./util');
|
const {range} = require('./util');
|
||||||
const signup = require('./usecases/signup');
|
const signup = require('./usecases/signup');
|
||||||
|
const toastScenarios = require('./scenarios/toast');
|
||||||
const roomDirectoryScenarios = require('./scenarios/directory');
|
const roomDirectoryScenarios = require('./scenarios/directory');
|
||||||
const lazyLoadingScenarios = require('./scenarios/lazy-loading');
|
const lazyLoadingScenarios = require('./scenarios/lazy-loading');
|
||||||
const e2eEncryptionScenarios = require('./scenarios/e2e-encryption');
|
const e2eEncryptionScenarios = require('./scenarios/e2e-encryption');
|
||||||
|
@ -37,6 +38,7 @@ module.exports = async function scenario(createSession, restCreator) {
|
||||||
const alice = await createUser("alice");
|
const alice = await createUser("alice");
|
||||||
const bob = await createUser("bob");
|
const bob = await createUser("bob");
|
||||||
|
|
||||||
|
await toastScenarios(alice, bob);
|
||||||
await roomDirectoryScenarios(alice, bob);
|
await roomDirectoryScenarios(alice, bob);
|
||||||
await e2eEncryptionScenarios(alice, bob);
|
await e2eEncryptionScenarios(alice, bob);
|
||||||
console.log("create REST users:");
|
console.log("create REST users:");
|
||||||
|
|
49
test/end-to-end-tests/src/scenarios/toast.js
Normal file
49
test/end-to-end-tests/src/scenarios/toast.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const {assertNoToasts, acceptToast, rejectToast} = require("../usecases/toasts");
|
||||||
|
|
||||||
|
module.exports = async function toastScenarios(alice, bob) {
|
||||||
|
console.log(" checking and clearing toasts:");
|
||||||
|
|
||||||
|
alice.log.startGroup(`clears toasts`);
|
||||||
|
alice.log.step(`reject desktop notifications toast`);
|
||||||
|
await rejectToast(alice, "Notifications");
|
||||||
|
alice.log.done();
|
||||||
|
|
||||||
|
alice.log.step(`accepts analytics toast`);
|
||||||
|
await acceptToast(alice, "Help us improve Riot");
|
||||||
|
alice.log.done();
|
||||||
|
|
||||||
|
alice.log.step(`checks no remaining toasts`);
|
||||||
|
await assertNoToasts(alice);
|
||||||
|
alice.log.done();
|
||||||
|
alice.log.endGroup();
|
||||||
|
|
||||||
|
bob.log.startGroup(`clears toasts`);
|
||||||
|
bob.log.step(`reject desktop notifications toast`);
|
||||||
|
await rejectToast(bob, "Notifications");
|
||||||
|
bob.log.done();
|
||||||
|
|
||||||
|
bob.log.step(`reject analytics toast`);
|
||||||
|
await rejectToast(bob, "Help us improve Riot");
|
||||||
|
bob.log.done();
|
||||||
|
|
||||||
|
bob.log.step(`checks no remaining toasts`);
|
||||||
|
await assertNoToasts(bob);
|
||||||
|
bob.log.done();
|
||||||
|
bob.log.endGroup();
|
||||||
|
};
|
|
@ -122,8 +122,8 @@ module.exports = class RiotSession {
|
||||||
await input.type(text);
|
await input.type(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
query(selector, timeout = DEFAULT_TIMEOUT) {
|
query(selector, timeout = DEFAULT_TIMEOUT, hidden = false) {
|
||||||
return this.page.waitForSelector(selector, {visible: true, timeout});
|
return this.page.waitForSelector(selector, {visible: true, timeout, hidden});
|
||||||
}
|
}
|
||||||
|
|
||||||
async queryAll(selector) {
|
async queryAll(selector) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ const assert = require('assert');
|
||||||
async function assertDialog(session, expectedTitle) {
|
async function assertDialog(session, expectedTitle) {
|
||||||
const titleElement = await session.query(".mx_Dialog .mx_Dialog_title");
|
const titleElement = await session.query(".mx_Dialog .mx_Dialog_title");
|
||||||
const dialogHeader = await session.innerText(titleElement);
|
const dialogHeader = await session.innerText(titleElement);
|
||||||
assert(dialogHeader, expectedTitle);
|
assert.equal(dialogHeader, expectedTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function acceptDialog(session, expectedTitle) {
|
async function acceptDialog(session, expectedTitle) {
|
||||||
|
|
47
test/end-to-end-tests/src/usecases/toasts.js
Normal file
47
test/end-to-end-tests/src/usecases/toasts.js
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
async function assertNoToasts(session) {
|
||||||
|
try {
|
||||||
|
await session.query('.mx_Toast_toast', 1000, true);
|
||||||
|
} catch (e) {
|
||||||
|
const h2Element = await session.query('.mx_Toast_title h2', 1000);
|
||||||
|
const toastTitle = await session.innerText(h2Element);
|
||||||
|
throw new Error(`"${toastTitle}" toast found when none expected`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function assertToast(session, expectedTitle) {
|
||||||
|
const h2Element = await session.query('.mx_Toast_title h2');
|
||||||
|
const toastTitle = await session.innerText(h2Element);
|
||||||
|
assert.equal(toastTitle, expectedTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function acceptToast(session, expectedTitle) {
|
||||||
|
await assertToast(session, expectedTitle);
|
||||||
|
const btn = await session.query('.mx_Toast_buttons .mx_AccessibleButton_kind_primary');
|
||||||
|
await btn.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function rejectToast(session, expectedTitle) {
|
||||||
|
await assertToast(session, expectedTitle);
|
||||||
|
const btn = await session.query('.mx_Toast_buttons .mx_AccessibleButton_kind_danger');
|
||||||
|
await btn.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {assertNoToasts, assertToast, acceptToast, rejectToast};
|
Loading…
Reference in a new issue