diff --git a/res/css/_components.scss b/res/css/_components.scss index bdcf27ac16..17737aca14 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -92,6 +92,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..34ef5e01d4 --- /dev/null +++ b/res/css/views/rooms/_AuxPanel.scss @@ -0,0 +1,50 @@ +/* +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: 5px; + padding-left: 19px; + border-bottom: 1px solid #e5e5e5; +} + +.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; +} diff --git a/src/components/views/rooms/AuxPanel.js b/src/components/views/rooms/AuxPanel.js index 64c0478d41..5370b4d8b5 100644 --- a/src/components/views/rooms/AuxPanel.js +++ b/src/components/views/rooms/AuxPanel.js @@ -24,6 +24,8 @@ import ObjectUtils from '../../../ObjectUtils'; 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({ @@ -60,6 +62,22 @@ module.exports = React.createClass({ hideAppsDrawer: false, }, + getInitialState: function() { + return { counters: this._computeCounters() }; + }, + + 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 +100,43 @@ module.exports = React.createClass({ ev.preventDefault(); }, + _rateLimitedUpdate: new RateLimitedFunc(function() { + if (SettingsStore.isFeatureEnabled("feature_state_counters")) { + 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"); @@ -145,6 +200,58 @@ module.exports = React.createClass({ hide={this.props.hideAppsDrawer} />; + let stateViews = null; + if (this.state.counters && SettingsStore.isFeatureEnabled("feature_state_counters")) { + let counters = []; + + 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 } + + if (link) { + span = ( + + { span } + + ); + } + + span = ( + + {span} + + ); + + counters.push(span); + counters.push( + ─ + ); + } + }); + + if (counters.length > 0) { + counters.pop(); // remove last deliminator + stateViews = ( +