From 712241d71074f5c937911ed4eb68b60910a69871 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Mon, 24 Dec 2018 14:27:50 +0000 Subject: [PATCH 1/6] Add simple state counters to room heading --- res/css/_components.scss | 1 + res/css/views/rooms/_AuxPanel.scss | 48 +++++++++++++++++ src/components/views/rooms/AuxPanel.js | 73 ++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 res/css/views/rooms/_AuxPanel.scss diff --git a/res/css/_components.scss b/res/css/_components.scss index d8f966603d..1f99699e73 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -91,6 +91,7 @@ @import "./views/messages/_UnknownBody.scss"; @import "./views/rooms/_AppsDrawer.scss"; @import "./views/rooms/_Autocomplete.scss"; +@import "./views/rooms/_AuxPanel.scss"; @import "./views/rooms/_EntityTile.scss"; @import "./views/rooms/_EventTile.scss"; @import "./views/rooms/_LinkPreviewWidget.scss"; diff --git a/res/css/views/rooms/_AuxPanel.scss b/res/css/views/rooms/_AuxPanel.scss new file mode 100644 index 0000000000..690a5e5b55 --- /dev/null +++ b/res/css/views/rooms/_AuxPanel.scss @@ -0,0 +1,48 @@ +/* +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. +*/ + +.m_RoomView_auxPanel_stateViews { + padding-top: 3px; +} + +.m_RoomView_auxPanel_stateViews_span a { + text-decoration: none; + color: inherit; +} + +.m_RoomView_auxPanel_stateViews_span[data-severity=warning] { + font-weight: bold; + color: orange; +} + +.m_RoomView_auxPanel_stateViews_span[data-severity=alert] { + font-weight: bold; + color: red; +} + +.m_RoomView_auxPanel_stateViews_span[data-severity=normal] { + font-weight: normal; +} + +.m_RoomView_auxPanel_stateViews_span[data-severity=notice] { + font-weight: normal; + color: $settings-grey-fg-color; +} + +.m_RoomView_auxPanel_stateViews_delim { + padding: 0 5px; + color: $settings-grey-fg-color; +} \ No newline at end of file diff --git a/src/components/views/rooms/AuxPanel.js b/src/components/views/rooms/AuxPanel.js index 64c0478d41..32abb41ce2 100644 --- a/src/components/views/rooms/AuxPanel.js +++ b/src/components/views/rooms/AuxPanel.js @@ -24,6 +24,7 @@ import ObjectUtils from '../../../ObjectUtils'; import AppsDrawer from './AppsDrawer'; import { _t } from '../../../languageHandler'; import classNames from 'classnames'; +import RateLimitedFunc from '../../../ratelimitedfunc'; module.exports = React.createClass({ @@ -60,6 +61,18 @@ module.exports = React.createClass({ hideAppsDrawer: false, }, + componentDidMount: function() { + const cli = MatrixClientPeg.get(); + cli.on("RoomState.events", this._rateLimitedUpdate); + }, + + componentWillUnmount: function() { + const cli = MatrixClientPeg.get(); + if (cli) { + cli.removeListener("RoomState.events", this._rateLimitedUpdate); + } + }, + shouldComponentUpdate: function(nextProps, nextState) { return (!ObjectUtils.shallowEqual(this.props, nextProps) || !ObjectUtils.shallowEqual(this.state, nextState)); @@ -82,6 +95,11 @@ module.exports = React.createClass({ ev.preventDefault(); }, + _rateLimitedUpdate: new RateLimitedFunc(function() { + /* eslint-disable babel/no-invalid-this */ + this.forceUpdate(); + }, 500), + render: function() { const CallView = sdk.getComponent("voip.CallView"); const TintableSvg = sdk.getComponent("elements.TintableSvg"); @@ -145,6 +163,60 @@ module.exports = React.createClass({ hide={this.props.hideAppsDrawer} />; + let stateViews = null; + if (this.props.room) { + const stateEvs = this.props.room.currentState.getStateEvents('re.jki.counter'); + + let counters = []; + + stateEvs.forEach((ev, idx) => { + const title = ev.getContent().title; + const value = ev.getContent().value; + const link = ev.getContent().link; + const severity = ev.getContent().severity || "normal"; + const stateKey = ev.getStateKey(); + + if (title && value && severity) { + let span = { title }: { value } + + if (link) { + span = ( + + { span } + + ); + } + + span = ( + + {span} + + ); + + counters.push(span); + counters.push( + + ); + } + }); + + if (counters.length > 0) { + counters.pop(); // remove last deliminator + stateViews = ( +
+ { counters } +
+ ); + } + } + const classes = classNames({ "mx_RoomView_auxPanel": true, "mx_RoomView_auxPanel_fullHeight": this.props.fullHeight, @@ -156,6 +228,7 @@ module.exports = React.createClass({ return (
+ { stateViews } { appsDrawer } { fileDropTarget } { callView } From 4c204e88be2364468c0b1fa27ca0a60d1065c129 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Mon, 24 Dec 2018 15:09:10 +0000 Subject: [PATCH 2/6] Add feature flag for counters --- src/components/views/rooms/AuxPanel.js | 3 ++- src/i18n/strings/en_EN.json | 3 ++- src/settings/Settings.js | 6 ++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/AuxPanel.js b/src/components/views/rooms/AuxPanel.js index 32abb41ce2..dd11ee8ad0 100644 --- a/src/components/views/rooms/AuxPanel.js +++ b/src/components/views/rooms/AuxPanel.js @@ -25,6 +25,7 @@ import AppsDrawer from './AppsDrawer'; import { _t } from '../../../languageHandler'; import classNames from 'classnames'; import RateLimitedFunc from '../../../ratelimitedfunc'; +import SettingsStore from "../../../settings/SettingsStore"; module.exports = React.createClass({ @@ -164,7 +165,7 @@ module.exports = React.createClass({ />; let stateViews = null; - if (this.props.room) { + if (this.props.room && SettingsStore.isFeatureEnabled("feature_state_counters")) { const stateEvs = this.props.room.currentState.getStateEvents('re.jki.counter'); let counters = []; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 85cb8c9868..a6b04ec338 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1404,5 +1404,6 @@ "Go to Settings": "Go to Settings", "Failed to set direct chat tag": "Failed to set direct chat tag", "Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room", - "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room" + "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room", + "Render simple counters in room header": "Render simple counters in room header" } diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 14f4bdc6dd..ec7dadc341 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -102,6 +102,12 @@ export const SETTINGS = { supportedLevels: LEVELS_FEATURE, default: false, }, + "feature_state_counters": { + isFeature: true, + displayName: _td("Render simple counters in room header"), + supportedLevels: LEVELS_FEATURE, + default: false, + }, "MessageComposerInput.dontSuggestEmoji": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, displayName: _td('Disable Emoji suggestions while typing'), From 8a6e7382aec4d7d976c18b5c0fe6ff4c6093c847 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Mon, 24 Dec 2018 15:11:05 +0000 Subject: [PATCH 3/6] Missing newline --- res/css/views/rooms/_AuxPanel.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/rooms/_AuxPanel.scss b/res/css/views/rooms/_AuxPanel.scss index 690a5e5b55..808ac2c6c7 100644 --- a/res/css/views/rooms/_AuxPanel.scss +++ b/res/css/views/rooms/_AuxPanel.scss @@ -45,4 +45,4 @@ limitations under the License. .m_RoomView_auxPanel_stateViews_delim { padding: 0 5px; color: $settings-grey-fg-color; -} \ No newline at end of file +} From 9a5f17d0b17638cb272a251502409365fde9fdcd Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Mon, 7 Jan 2019 15:21:00 +0000 Subject: [PATCH 4/6] Change CSS to match experimental --- res/css/views/rooms/_AuxPanel.scss | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/res/css/views/rooms/_AuxPanel.scss b/res/css/views/rooms/_AuxPanel.scss index 808ac2c6c7..34ef5e01d4 100644 --- a/res/css/views/rooms/_AuxPanel.scss +++ b/res/css/views/rooms/_AuxPanel.scss @@ -15,7 +15,9 @@ limitations under the License. */ .m_RoomView_auxPanel_stateViews { - padding-top: 3px; + padding: 5px; + padding-left: 19px; + border-bottom: 1px solid #e5e5e5; } .m_RoomView_auxPanel_stateViews_span a { From 07c2010cce92fcc7c3726b1b150bf8096560f116 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Tue, 8 Jan 2019 11:14:31 +0000 Subject: [PATCH 5/6] Use state rather than forceUpdate --- src/components/views/rooms/AuxPanel.js | 54 ++++++++++++++++++++------ 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/src/components/views/rooms/AuxPanel.js b/src/components/views/rooms/AuxPanel.js index dd11ee8ad0..48317411c9 100644 --- a/src/components/views/rooms/AuxPanel.js +++ b/src/components/views/rooms/AuxPanel.js @@ -62,6 +62,10 @@ module.exports = React.createClass({ hideAppsDrawer: false, }, + getInitialState: function() { + return { counters: this._computeCounters() }; + }, + componentDidMount: function() { const cli = MatrixClientPeg.get(); cli.on("RoomState.events", this._rateLimitedUpdate); @@ -97,10 +101,40 @@ module.exports = React.createClass({ }, _rateLimitedUpdate: new RateLimitedFunc(function() { - /* eslint-disable babel/no-invalid-this */ - this.forceUpdate(); + this.setState({counters: this._computeCounters()}) }, 500), + _computeCounters: function() { + let counters = []; + + if (this.props.room && SettingsStore.isFeatureEnabled("feature_state_counters")) { + const stateEvs = this.props.room.currentState.getStateEvents('re.jki.counter'); + stateEvs.sort((a, b) => { + return a.getStateKey() < b.getStateKey(); + }); + + stateEvs.forEach((ev, idx) => { + const title = ev.getContent().title; + const value = ev.getContent().value; + const link = ev.getContent().link; + const severity = ev.getContent().severity || "normal"; + const stateKey = ev.getStateKey(); + + if (title && value && severity) { + counters.push({ + "title": title, + "value": value, + "link": link, + "severity": severity, + "stateKey": stateKey + }) + } + }); + } + + return counters; + }, + render: function() { const CallView = sdk.getComponent("voip.CallView"); const TintableSvg = sdk.getComponent("elements.TintableSvg"); @@ -165,17 +199,15 @@ module.exports = React.createClass({ />; let stateViews = null; - if (this.props.room && SettingsStore.isFeatureEnabled("feature_state_counters")) { - const stateEvs = this.props.room.currentState.getStateEvents('re.jki.counter'); - + if (this.state.counters && SettingsStore.isFeatureEnabled("feature_state_counters")) { let counters = []; - stateEvs.forEach((ev, idx) => { - const title = ev.getContent().title; - const value = ev.getContent().value; - const link = ev.getContent().link; - const severity = ev.getContent().severity || "normal"; - const stateKey = ev.getStateKey(); + this.state.counters.forEach((counter, idx) => { + const title = counter.title; + const value = counter.value; + const link = counter.link; + const severity = counter.severity; + const stateKey = counter.stateKey; if (title && value && severity) { let span = { title }: { value } From fa6b33d629752f566d4ffaf2e552a6193c9a1bca Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 10 Jan 2019 16:54:08 +0000 Subject: [PATCH 6/6] Only update component state when feature is enabled --- src/components/views/rooms/AuxPanel.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/AuxPanel.js b/src/components/views/rooms/AuxPanel.js index 48317411c9..5370b4d8b5 100644 --- a/src/components/views/rooms/AuxPanel.js +++ b/src/components/views/rooms/AuxPanel.js @@ -101,7 +101,9 @@ module.exports = React.createClass({ }, _rateLimitedUpdate: new RateLimitedFunc(function() { - this.setState({counters: this._computeCounters()}) + if (SettingsStore.isFeatureEnabled("feature_state_counters")) { + this.setState({counters: this._computeCounters()}); + } }, 500), _computeCounters: function() {