From 6593ee09d1c254d94db9227cce0291790835e698 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 7 Aug 2018 17:04:37 +0100 Subject: [PATCH 1/5] Warning bar for MAU limit hit Somewhat untested, sorry --- res/css/views/globals/_MatrixToolbar.scss | 6 ++ res/themes/dark/css/_dark.scss | 1 + res/themes/light/css/_base.scss | 1 + src/components/structures/LoggedInView.js | 57 ++++++++++++++++++- .../views/globals/ServerLimitBar.js | 51 ++++++++++++++++- src/i18n/strings/en_EN.json | 5 +- 6 files changed, 115 insertions(+), 6 deletions(-) diff --git a/res/css/views/globals/_MatrixToolbar.scss b/res/css/views/globals/_MatrixToolbar.scss index 1109b9e264..1791d619ae 100644 --- a/res/css/views/globals/_MatrixToolbar.scss +++ b/res/css/views/globals/_MatrixToolbar.scss @@ -28,6 +28,12 @@ limitations under the License. margin-top: -2px; } +.mx_MatrixToolbar_info { + padding-left: 16px; + padding-right: 8px; + background-color: $info-bg-color; +} + .mx_MatrixToolbar_error { padding-left: 16px; padding-right: 8px; diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index ad4630d668..8ab338790e 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -20,6 +20,7 @@ $focus-brightness: 200%; // red warning colour $warning-color: #ff0064; $warning-bg-color: #DF2A8B; +$info-bg-color: #2A9EDF; // groups $info-plinth-bg-color: #454545; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index dedfeaeb2f..7d004bd831 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -27,6 +27,7 @@ $focus-brightness: 125%; $warning-color: #ff0064; // background colour for warnings $warning-bg-color: #DF2A8B; +$info-bg-color: #2A9EDF; $mention-user-pill-bg-color: #ff0064; $other-user-pill-bg-color: rgba(0, 0, 0, 0.1); diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 65ef69d547..a6c373f7ef 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -30,10 +30,16 @@ import dis from '../../dispatcher'; import sessionStore from '../../stores/SessionStore'; import MatrixClientPeg from '../../MatrixClientPeg'; import SettingsStore from "../../settings/SettingsStore"; +import RoomListStore from "../../stores/RoomListStore"; import TagOrderActions from '../../actions/TagOrderActions'; import RoomListActions from '../../actions/RoomListActions'; +// 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. +// NB. this is just for server notices rather than pinned messages in general. +const MAX_PINNED_NOTICES_PER_ROOM = 2; + /** * This is what our MatrixChat shows when we are logged in. The precise view is * determined by the page_type property. @@ -80,6 +86,8 @@ const LoggedInView = React.createClass({ return { // use compact timeline view useCompactLayout: SettingsStore.getValue('useCompactLayout'), + // any currently active server notice events + serverNoticeEvents: [], }; }, @@ -97,13 +105,18 @@ const LoggedInView = React.createClass({ ); this._setStateFromSessionStore(); + this._updateServerNoticeEvents(); + this._matrixClient.on("accountData", this.onAccountData); this._matrixClient.on("sync", this.onSync); + this._matrixClient.on("RoomState.events", this.onRoomStateEvents); }, componentWillUnmount: function() { document.removeEventListener('keydown', this._onKeyDown); this._matrixClient.removeListener("accountData", this.onAccountData); + this._matrixClient.removeListener("sync", this.onSync); + this._matrixClient.removeListener("RoomState.events", this.onRoomStateEvents); if (this._sessionStoreToken) { this._sessionStoreToken.remove(); } @@ -157,8 +170,42 @@ const LoggedInView = React.createClass({ syncErrorData: null, }); } + + if (oldSyncState === 'PREPARED' && syncState === 'SYNCING') { + this._updateServerNoticeEvents(); + } }, + onRoomStateEvents: function(ev, state) { + const roomLists = RoomListStore.getRoomLists(); + if (roomLists['m.server_notices'] && roomLists['m.server_notices'].includes(ev.getRoomId())) { + this._updateServerNoticeEvents(); + } + }, + + _updateServerNoticeEvents: async function() { + const roomLists = RoomListStore.getRoomLists(); + if (!roomLists['m.server_notice']) return []; + + const pinnedEvents = []; + for (const room of roomLists['m.server_notice']) { + const pinStateEvent = room.currentState.getStateEvents("m.room.pinned_events", ""); + + if (!pinStateEvent || !pinStateEvent.getContent().pinned) continue; + + const pinnedEventIds = pinStateEvent.getContent().pinned.slice(0, MAX_PINNED_NOTICES_PER_ROOM); + for (const eventId of pinnedEventIds) { + const timeline = await this._matrixClient.getEventTimeline(room.getUnfilteredTimelineSet(), eventId, 0); + const ev = timeline.getEvents().find(ev => ev.getId() === eventId); + if (ev) pinnedEvents.push(ev); + } + } + this.setState({ + serverNoticeEvents: pinnedEvents, + }); + }, + + _onKeyDown: function(ev) { /* // Remove this for now as ctrl+alt = alt-gr so this breaks keyboards which rely on alt-gr for numbers @@ -386,10 +433,18 @@ const LoggedInView = React.createClass({ break; } + const mauLimitEvent = this.state.serverNoticeEvents.find((e) => { + return e && e.getType() === 'm.server_notice.usage_limit_reached' && + e.getContent().limit && + e.getContent().limit === 'monthly_active_user' + }); + let topBar; const isGuest = this.props.matrixClient.isGuest(); if (this.state.syncErrorData && this.state.syncErrorData.error.errcode === 'M_MAU_LIMIT_EXCEEDED') { - topBar = ; + topBar = ; + } else if (mauLimitEvent) { + topBar = ; } else if (this.props.showCookieBar && this.props.config.piwik ) { diff --git a/src/components/views/globals/ServerLimitBar.js b/src/components/views/globals/ServerLimitBar.js index 638e85634f..26cc5ca566 100644 --- a/src/components/views/globals/ServerLimitBar.js +++ b/src/components/views/globals/ServerLimitBar.js @@ -15,15 +15,60 @@ limitations under the License. */ import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; import { _t } from '../../../languageHandler'; export default React.createClass({ + propTypes: { + // 'hard' if the logged in user has been locked out, 'soft' if they haven't + kind: PropTypes.string, + adminContent: PropTypes.string, + }, + + getDefaultProps: function() { + return { + kind: 'hard', + } + }, + render: function() { - const toolbarClasses = "mx_MatrixToolbar mx_MatrixToolbar_error"; + const toolbarClasses = { + 'mx_MatrixToolbar': true, + }; + let content; + + const translateLink = (sub) => { + if (this.props.adminContent) { + return {sub}; + } else { + return sub; + } + } + + if (this.props.kind === 'hard') { + toolbarClasses['mx_MatrixToolbar_error'] = true; + content = _t( + "This homeserver has hit its Monthly Active User limit. Please contact your service administrator to continue using the service.", + {}, + { + 'a': translateLink, + }, + ); + } else { + toolbarClasses['mx_MatrixToolbar_info'] = true; + content = _t( + "This homeserver has hit its Monthly Active User limit so some users will not be able to log in. Please contact your service administrator to get this limit increased.", + {}, + { + 'a': translateLink, + }, + ); + } return ( -
+
- { _t("This homeserver has hit its Monthly Active User limit. Please contact your service administrator to continue using the service.") } + { content }
); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index d44187b834..6fe775770c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -464,9 +464,9 @@ "People": "People", "Rooms": "Rooms", "Low priority": "Low priority", - "System Alerts": "System Alerts", "You have no historical rooms": "You have no historical rooms", "Historical": "Historical", + "System Alerts": "System Alerts", "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Unable to ascertain that the address this invite was sent to matches one associated with your account.", "This invitation was sent to an email address which is not associated with this account:": "This invitation was sent to an email address which is not associated with this account:", "You may wish to login with a different account, or add this email to this account.": "You may wish to login with a different account, or add this email to this account.", @@ -678,7 +678,8 @@ "A new version of Riot is available.": "A new version of Riot is available.", "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", - "This homeserver has hit its Monthly Active User limit. Please contact your service administrator to continue using the service.": "This homeserver has hit its Monthly Active User limit. Please contact your service administrator to continue using the service.", + "This homeserver has hit its Monthly Active User limit. Please contact your service administrator to continue using the service.": "This homeserver has hit its Monthly Active User limit. Please contact your service administrator to continue using the service.", + "This homeserver has hit its Monthly Active User limit so some users will not be able to log in. Please contact your service administrator to get this limit increased.": "This homeserver has hit its Monthly Active User limit so some users will not be able to log in. Please contact your service administrator to get this limit increased.", "Error encountered (%(errorDetail)s).": "Error encountered (%(errorDetail)s).", "Checking for an update...": "Checking for an update...", "No update available.": "No update available.", From 16b7763c0ea5f2f32d5d1a0dc30c0c5233412d30 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 7 Aug 2018 17:22:12 +0100 Subject: [PATCH 2/5] s/limit/limit_type/ --- src/components/structures/LoggedInView.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index a6c373f7ef..c23dbaf444 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -435,8 +435,8 @@ const LoggedInView = React.createClass({ const mauLimitEvent = this.state.serverNoticeEvents.find((e) => { return e && e.getType() === 'm.server_notice.usage_limit_reached' && - e.getContent().limit && - e.getContent().limit === 'monthly_active_user' + e.getContent().limit_type && + e.getContent().limit_type === 'monthly_active_user' }); let topBar; From 05bf200a722545a8433b7d2b3908e9b9ce520151 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 13 Aug 2018 13:49:22 +0100 Subject: [PATCH 3/5] Don't crash if scrollbars updated before init The initialisation here is done on a timer to allow the DOM elements to be in place before it's run, so it's possible for an update to happen ebfore the initialisation. Stop & bail out if there is no this.stickies. --- src/components/views/rooms/RoomList.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 2bd0f473bc..759951d36d 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -1,6 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd -Copyright 2017 Vector Creations Ltd +Copyright 2017, 2018 Vector Creations Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -451,6 +451,8 @@ module.exports = React.createClass({ } } + if (!this.stickies) return; + const self = this; let scrollStuckOffset = 0; // Scroll to the passed in position, i.e. a header was clicked and in a scroll to state From d84ecbe97c884e69d3e177ebe10b8e74a4916b70 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 13 Aug 2018 13:53:38 +0100 Subject: [PATCH 4/5] s/m.server_notices/m.server_notice/ --- src/components/structures/LoggedInView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index c23dbaf444..5b617feb68 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -178,7 +178,7 @@ const LoggedInView = React.createClass({ onRoomStateEvents: function(ev, state) { const roomLists = RoomListStore.getRoomLists(); - if (roomLists['m.server_notices'] && roomLists['m.server_notices'].includes(ev.getRoomId())) { + if (roomLists['m.server_notice'] && roomLists['m.server_notice'].some(r => r.roomId === ev.getRoomId())) { this._updateServerNoticeEvents(); } }, From f7f62ba09daf47ee11d965645858ee441b69347a Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 13 Aug 2018 14:04:08 +0100 Subject: [PATCH 5/5] Lint --- src/components/views/globals/ServerLimitBar.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/views/globals/ServerLimitBar.js b/src/components/views/globals/ServerLimitBar.js index 26cc5ca566..c0a7376bd6 100644 --- a/src/components/views/globals/ServerLimitBar.js +++ b/src/components/views/globals/ServerLimitBar.js @@ -29,7 +29,7 @@ export default React.createClass({ getDefaultProps: function() { return { kind: 'hard', - } + }; }, render: function() { @@ -44,12 +44,13 @@ export default React.createClass({ } else { return sub; } - } + }; if (this.props.kind === 'hard') { toolbarClasses['mx_MatrixToolbar_error'] = true; content = _t( - "This homeserver has hit its Monthly Active User limit. Please contact your service administrator to continue using the service.", + "This homeserver has hit its Monthly Active User limit. " + + "Please contact your service administrator to continue using the service.", {}, { 'a': translateLink, @@ -58,7 +59,9 @@ export default React.createClass({ } else { toolbarClasses['mx_MatrixToolbar_info'] = true; content = _t( - "This homeserver has hit its Monthly Active User limit so some users will not be able to log in. Please contact your service administrator to get this limit increased.", + "This homeserver has hit its Monthly Active User " + + "limit so some users will not be able to log in. " + + "Please contact your service administrator to get this limit increased.", {}, { 'a': translateLink,