UNPKG

matrix-react-sdk

Version:
864 lines (703 loc) 122 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireDefault(require("react")); var sdk = _interopRequireWildcard(require("../../../index")); var _languageHandler = require("../../../languageHandler"); var _MatrixClientPeg = require("../../../MatrixClientPeg"); var _SettingsStore = _interopRequireDefault(require("../../../settings/SettingsStore")); var _Modal = _interopRequireDefault(require("../../../Modal")); var _notifications = require("../../../notifications"); var _SdkConfig = _interopRequireDefault(require("../../../SdkConfig")); var _LabelledToggleSwitch = _interopRequireDefault(require("../elements/LabelledToggleSwitch")); var _AccessibleButton = _interopRequireDefault(require("../elements/AccessibleButton")); var _SettingLevel = require("../../../settings/SettingLevel"); var _UIFeature = require("../../../settings/UIFeature"); var _replaceableComponent = require("../../../utils/replaceableComponent"); var _dec, _class, _class2, _temp; // TODO: this "view" component still has far too much application logic in it, // which should be factored out to other files. // TODO: this component also does a lot of direct poking into this.state, which // is VERY NAUGHTY. /** * Rules that Vector used to set in order to override the actions of default rules. * These are used to port peoples existing overrides to match the current API. * These can be removed and forgotten once everyone has moved to the new client. */ const LEGACY_RULES = { "im.vector.rule.contains_display_name": ".m.rule.contains_display_name", "im.vector.rule.room_one_to_one": ".m.rule.room_one_to_one", "im.vector.rule.room_message": ".m.rule.message", "im.vector.rule.invite_for_me": ".m.rule.invite_for_me", "im.vector.rule.call": ".m.rule.call", "im.vector.rule.notices": ".m.rule.suppress_notices" }; function portLegacyActions(actions) { const decoded = _notifications.NotificationUtils.decodeActions(actions); if (decoded !== null) { return _notifications.NotificationUtils.encodeActions(decoded); } else { // We don't recognise one of the actions here, so we don't try to // canonicalise them. return actions; } } let Notifications = (_dec = (0, _replaceableComponent.replaceableComponent)("views.settings.Notifications"), _dec(_class = (_temp = _class2 = class Notifications extends _react.default.Component { constructor(...args) { super(...args); (0, _defineProperty2.default)(this, "state", { phase: Notifications.phases.LOADING, masterPushRule: undefined, // The master rule ('.m.rule.master') vectorPushRules: [], // HS default push rules displayed in Vector UI vectorContentRules: { // Keyword push rules displayed in Vector UI vectorState: _notifications.PushRuleVectorState.ON, rules: [] }, externalPushRules: [], // Push rules (except content rule) that have been defined outside Vector UI externalContentRules: [], // Keyword push rules that have been defined outside Vector UI threepids: [] // used for email notifications }); (0, _defineProperty2.default)(this, "onEnableNotificationsChange", checked => { const self = this; this.setState({ phase: Notifications.phases.LOADING }); _MatrixClientPeg.MatrixClientPeg.get().setPushRuleEnabled('global', self.state.masterPushRule.kind, self.state.masterPushRule.rule_id, !checked).then(function () { self._refreshFromServer(); }); }); (0, _defineProperty2.default)(this, "onEnableDesktopNotificationsChange", checked => { _SettingsStore.default.setValue("notificationsEnabled", null, _SettingLevel.SettingLevel.DEVICE, checked).finally(() => { this.forceUpdate(); }); }); (0, _defineProperty2.default)(this, "onEnableDesktopNotificationBodyChange", checked => { _SettingsStore.default.setValue("notificationBodyEnabled", null, _SettingLevel.SettingLevel.DEVICE, checked).finally(() => { this.forceUpdate(); }); }); (0, _defineProperty2.default)(this, "onEnableAudioNotificationsChange", checked => { _SettingsStore.default.setValue("audioNotificationsEnabled", null, _SettingLevel.SettingLevel.DEVICE, checked).finally(() => { this.forceUpdate(); }); }); (0, _defineProperty2.default)(this, "onEnableEmailNotificationsChange", (address, checked) => { let emailPusherPromise; if (checked) { const data = {}; data['brand'] = _SdkConfig.default.get().brand; emailPusherPromise = _MatrixClientPeg.MatrixClientPeg.get().setPusher({ kind: 'email', app_id: 'm.email', pushkey: address, app_display_name: 'Email Notifications', device_display_name: address, lang: navigator.language, data: data, append: true // We always append for email pushers since we don't want to stop other accounts notifying to the same email address }); } else { const emailPusher = this.getEmailPusher(this.state.pushers, address); emailPusher.kind = null; emailPusherPromise = _MatrixClientPeg.MatrixClientPeg.get().setPusher(emailPusher); } emailPusherPromise.then(() => { this._refreshFromServer(); }, error => { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); _Modal.default.createTrackedDialog('Error saving email notification preferences', '', ErrorDialog, { title: (0, _languageHandler._t)('Error saving email notification preferences'), description: (0, _languageHandler._t)('An error occurred whilst saving your email notification preferences.') }); }); }); (0, _defineProperty2.default)(this, "onNotifStateButtonClicked", event => { // FIXME: use .bind() rather than className metadata here surely const vectorRuleId = event.target.className.split("-")[0]; const newPushRuleVectorState = event.target.className.split("-")[1]; if ("_keywords" === vectorRuleId) { this._setKeywordsPushRuleVectorState(newPushRuleVectorState); } else { const rule = this.getRule(vectorRuleId); if (rule) { this._setPushRuleVectorState(rule, newPushRuleVectorState); } } }); (0, _defineProperty2.default)(this, "onKeywordsClicked", event => { // Compute the keywords list to display let keywords = []; for (const i in this.state.vectorContentRules.rules) { const rule = this.state.vectorContentRules.rules[i]; keywords.push(rule.pattern); } if (keywords.length) { // As keeping the order of per-word push rules hs side is a bit tricky to code, // display the keywords in alphabetical order to the user keywords.sort(); keywords = keywords.join(", "); } else { keywords = ""; } const TextInputDialog = sdk.getComponent("dialogs.TextInputDialog"); _Modal.default.createTrackedDialog('Keywords Dialog', '', TextInputDialog, { title: (0, _languageHandler._t)('Keywords'), description: (0, _languageHandler._t)('Enter keywords separated by a comma:'), button: (0, _languageHandler._t)('OK'), value: keywords, onFinished: (shouldLeave, newValue) => { if (shouldLeave && newValue !== keywords) { let newKeywords = newValue.split(','); for (const i in newKeywords) { newKeywords[i] = newKeywords[i].trim(); } // Remove duplicates and empty newKeywords = newKeywords.reduce(function (array, keyword) { if (keyword !== "" && array.indexOf(keyword) < 0) { array.push(keyword); } return array; }, []); this._setKeywords(newKeywords); } } }); }); (0, _defineProperty2.default)(this, "_refreshFromServer", () => { const self = this; const pushRulesPromise = _MatrixClientPeg.MatrixClientPeg.get().getPushRules().then(self._portRulesToNewAPI).then(function (rulesets) { /// XXX seriously? wtf is this? _MatrixClientPeg.MatrixClientPeg.get().pushRules = rulesets; // Get homeserver default rules and triage them by categories const ruleCategories = { // The master rule (all notifications disabling) '.m.rule.master': 'master', // The default push rules displayed by Vector UI '.m.rule.contains_display_name': 'vector', '.m.rule.contains_user_name': 'vector', '.m.rule.roomnotif': 'vector', '.m.rule.room_one_to_one': 'vector', '.m.rule.encrypted_room_one_to_one': 'vector', '.m.rule.message': 'vector', '.m.rule.encrypted': 'vector', '.m.rule.invite_for_me': 'vector', //'.m.rule.member_event': 'vector', '.m.rule.call': 'vector', '.m.rule.suppress_notices': 'vector', '.m.rule.tombstone': 'vector' // Others go to others }; // HS default rules const defaultRules = { master: [], vector: {}, others: [] }; for (const kind in rulesets.global) { for (let i = 0; i < Object.keys(rulesets.global[kind]).length; ++i) { const r = rulesets.global[kind][i]; const cat = ruleCategories[r.rule_id]; r.kind = kind; if (r.rule_id[0] === '.') { if (cat === 'vector') { defaultRules.vector[r.rule_id] = r; } else if (cat === 'master') { defaultRules.master.push(r); } else { defaultRules['others'].push(r); } } } } // Get the master rule if any defined by the hs if (defaultRules.master.length > 0) { self.state.masterPushRule = defaultRules.master[0]; } // parse the keyword rules into our state const contentRules = _notifications.ContentRules.parseContentRules(rulesets); self.state.vectorContentRules = { vectorState: contentRules.vectorState, rules: contentRules.rules }; self.state.externalContentRules = contentRules.externalRules; // Build the rules displayed in the Vector UI matrix table self.state.vectorPushRules = []; self.state.externalPushRules = []; const vectorRuleIds = ['.m.rule.contains_display_name', '.m.rule.contains_user_name', '.m.rule.roomnotif', '_keywords', '.m.rule.room_one_to_one', '.m.rule.encrypted_room_one_to_one', '.m.rule.message', '.m.rule.encrypted', '.m.rule.invite_for_me', //'im.vector.rule.member_event', '.m.rule.call', '.m.rule.suppress_notices', '.m.rule.tombstone']; for (const i in vectorRuleIds) { const vectorRuleId = vectorRuleIds[i]; if (vectorRuleId === '_keywords') { // keywords needs a special handling // For Vector UI, this is a single global push rule but translated in Matrix, // it corresponds to all content push rules (stored in self.state.vectorContentRule) self.state.vectorPushRules.push({ "vectorRuleId": "_keywords", "description": /*#__PURE__*/_react.default.createElement("span", null, (0, _languageHandler._t)('Messages containing <span>keywords</span>', {}, { 'span': sub => /*#__PURE__*/_react.default.createElement("span", { className: "mx_UserNotifSettings_keywords", onClick: self.onKeywordsClicked }, sub) })), "vectorState": self.state.vectorContentRules.vectorState }); } else { const ruleDefinition = _notifications.VectorPushRulesDefinitions[vectorRuleId]; const rule = defaultRules.vector[vectorRuleId]; const vectorState = ruleDefinition.ruleToVectorState(rule); //console.log("Refreshing vectorPushRules for " + vectorRuleId +", "+ ruleDefinition.description +", " + rule +", " + vectorState); self.state.vectorPushRules.push({ "vectorRuleId": vectorRuleId, "description": (0, _languageHandler._t)(ruleDefinition.description), // Text from VectorPushRulesDefinitions.js "rule": rule, "vectorState": vectorState }); // if there was a rule which we couldn't parse, add it to the external list if (rule && !vectorState) { rule.description = ruleDefinition.description; self.state.externalPushRules.push(rule); } } } // Build the rules not managed by Vector UI const otherRulesDescriptions = { '.m.rule.message': (0, _languageHandler._t)('Notify for all other messages/rooms'), '.m.rule.fallback': (0, _languageHandler._t)('Notify me for anything else') }; for (const i in defaultRules.others) { const rule = defaultRules.others[i]; const ruleDescription = otherRulesDescriptions[rule.rule_id]; // Show enabled default rules that was modified by the user if (ruleDescription && rule.enabled && !rule.default) { rule.description = ruleDescription; self.state.externalPushRules.push(rule); } } }); const pushersPromise = _MatrixClientPeg.MatrixClientPeg.get().getPushers().then(function (resp) { self.setState({ pushers: resp.pushers }); }); Promise.all([pushRulesPromise, pushersPromise]).then(function () { self.setState({ phase: Notifications.phases.DISPLAY }); }, function (error) { console.error(error); self.setState({ phase: Notifications.phases.ERROR }); }).finally(() => { // actually explicitly update our state having been deep-manipulating it self.setState({ masterPushRule: self.state.masterPushRule, vectorContentRules: self.state.vectorContentRules, vectorPushRules: self.state.vectorPushRules, externalContentRules: self.state.externalContentRules, externalPushRules: self.state.externalPushRules }); }); _MatrixClientPeg.MatrixClientPeg.get().getThreePids().then(r => this.setState({ threepids: r.threepids })); }); (0, _defineProperty2.default)(this, "_onClearNotifications", () => { const cli = _MatrixClientPeg.MatrixClientPeg.get(); cli.getRooms().forEach(r => { if (r.getUnreadNotificationCount() > 0) { const events = r.getLiveTimeline().getEvents(); if (events.length) cli.sendReadReceipt(events.pop()); } }); }); } componentDidMount() { this._refreshFromServer(); } /* * Returns the email pusher (pusher of type 'email') for a given * email address. Email pushers all have the same app ID, so since * pushers are unique over (app ID, pushkey), there will be at most * one such pusher. */ getEmailPusher(pushers, address) { if (pushers === undefined) { return undefined; } for (let i = 0; i < pushers.length; ++i) { if (pushers[i].kind === 'email' && pushers[i].pushkey === address) { return pushers[i]; } } return undefined; } getRule(vectorRuleId) { for (const i in this.state.vectorPushRules) { const rule = this.state.vectorPushRules[i]; if (rule.vectorRuleId === vectorRuleId) { return rule; } } } _setPushRuleVectorState(rule, newPushRuleVectorState) { if (rule && rule.vectorState !== newPushRuleVectorState) { this.setState({ phase: Notifications.phases.LOADING }); const self = this; const cli = _MatrixClientPeg.MatrixClientPeg.get(); const deferreds = []; const ruleDefinition = _notifications.VectorPushRulesDefinitions[rule.vectorRuleId]; if (rule.rule) { const actions = ruleDefinition.vectorStateToActions[newPushRuleVectorState]; if (!actions) { // The new state corresponds to disabling the rule. deferreds.push(cli.setPushRuleEnabled('global', rule.rule.kind, rule.rule.rule_id, false)); } else { // The new state corresponds to enabling the rule and setting specific actions deferreds.push(this._updatePushRuleActions(rule.rule, actions, true)); } } Promise.all(deferreds).then(function () { self._refreshFromServer(); }, function (error) { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Failed to change settings: " + error); _Modal.default.createTrackedDialog('Failed to change settings', '', ErrorDialog, { title: (0, _languageHandler._t)('Failed to change settings'), description: error && error.message ? error.message : (0, _languageHandler._t)('Operation failed'), onFinished: self._refreshFromServer }); }); } } _setKeywordsPushRuleVectorState(newPushRuleVectorState) { // Is there really a change? if (this.state.vectorContentRules.vectorState === newPushRuleVectorState || this.state.vectorContentRules.rules.length === 0) { return; } const self = this; const cli = _MatrixClientPeg.MatrixClientPeg.get(); this.setState({ phase: Notifications.phases.LOADING }); // Update all rules in self.state.vectorContentRules const deferreds = []; for (const i in this.state.vectorContentRules.rules) { const rule = this.state.vectorContentRules.rules[i]; let enabled; let actions; switch (newPushRuleVectorState) { case _notifications.PushRuleVectorState.ON: if (rule.actions.length !== 1) { actions = _notifications.PushRuleVectorState.actionsFor(_notifications.PushRuleVectorState.ON); } if (this.state.vectorContentRules.vectorState === _notifications.PushRuleVectorState.OFF) { enabled = true; } break; case _notifications.PushRuleVectorState.LOUD: if (rule.actions.length !== 3) { actions = _notifications.PushRuleVectorState.actionsFor(_notifications.PushRuleVectorState.LOUD); } if (this.state.vectorContentRules.vectorState === _notifications.PushRuleVectorState.OFF) { enabled = true; } break; case _notifications.PushRuleVectorState.OFF: enabled = false; break; } if (actions) { // Note that the workaround in _updatePushRuleActions will automatically // enable the rule deferreds.push(this._updatePushRuleActions(rule, actions, enabled)); } else if (enabled != undefined) { deferreds.push(cli.setPushRuleEnabled('global', rule.kind, rule.rule_id, enabled)); } } Promise.all(deferreds).then(function (resps) { self._refreshFromServer(); }, function (error) { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Can't update user notification settings: " + error); _Modal.default.createTrackedDialog('Can\'t update user notifcation settings', '', ErrorDialog, { title: (0, _languageHandler._t)('Can\'t update user notification settings'), description: error && error.message ? error.message : (0, _languageHandler._t)('Operation failed'), onFinished: self._refreshFromServer }); }); } _setKeywords(newKeywords) { this.setState({ phase: Notifications.phases.LOADING }); const self = this; const cli = _MatrixClientPeg.MatrixClientPeg.get(); const removeDeferreds = []; // Remove per-word push rules of keywords that are no more in the list const vectorContentRulesPatterns = []; for (const i in self.state.vectorContentRules.rules) { const rule = self.state.vectorContentRules.rules[i]; vectorContentRulesPatterns.push(rule.pattern); if (newKeywords.indexOf(rule.pattern) < 0) { removeDeferreds.push(cli.deletePushRule('global', rule.kind, rule.rule_id)); } } // If the keyword is part of `externalContentRules`, remove the rule // before recreating it in the right Vector path for (const i in self.state.externalContentRules) { const rule = self.state.externalContentRules[i]; if (newKeywords.indexOf(rule.pattern) >= 0) { removeDeferreds.push(cli.deletePushRule('global', rule.kind, rule.rule_id)); } } const onError = function (error) { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Failed to update keywords: " + error); _Modal.default.createTrackedDialog('Failed to update keywords', '', ErrorDialog, { title: (0, _languageHandler._t)('Failed to update keywords'), description: error && error.message ? error.message : (0, _languageHandler._t)('Operation failed'), onFinished: self._refreshFromServer }); }; // Then, add the new ones Promise.all(removeDeferreds).then(function (resps) { const deferreds = []; let pushRuleVectorStateKind = self.state.vectorContentRules.vectorState; if (pushRuleVectorStateKind === _notifications.PushRuleVectorState.OFF) { // When the current global keywords rule is OFF, we need to look at // the flavor of rules in 'vectorContentRules' to apply the same actions // when creating the new rule. // Thus, this new rule will join the 'vectorContentRules' set. if (self.state.vectorContentRules.rules.length) { pushRuleVectorStateKind = _notifications.PushRuleVectorState.contentRuleVectorStateKind(self.state.vectorContentRules.rules[0]); } else { // ON is default pushRuleVectorStateKind = _notifications.PushRuleVectorState.ON; } } for (const i in newKeywords) { const keyword = newKeywords[i]; if (vectorContentRulesPatterns.indexOf(keyword) < 0) { if (self.state.vectorContentRules.vectorState !== _notifications.PushRuleVectorState.OFF) { deferreds.push(cli.addPushRule('global', 'content', keyword, { actions: _notifications.PushRuleVectorState.actionsFor(pushRuleVectorStateKind), pattern: keyword })); } else { deferreds.push(self._addDisabledPushRule('global', 'content', keyword, { actions: _notifications.PushRuleVectorState.actionsFor(pushRuleVectorStateKind), pattern: keyword })); } } } Promise.all(deferreds).then(function (resps) { self._refreshFromServer(); }, onError); }, onError); } // Create a push rule but disabled _addDisabledPushRule(scope, kind, ruleId, body) { const cli = _MatrixClientPeg.MatrixClientPeg.get(); return cli.addPushRule(scope, kind, ruleId, body).then(() => cli.setPushRuleEnabled(scope, kind, ruleId, false)); } // Check if any legacy im.vector rules need to be ported to the new API // for overriding the actions of default rules. _portRulesToNewAPI(rulesets) { const needsUpdate = []; const cli = _MatrixClientPeg.MatrixClientPeg.get(); for (const kind in rulesets.global) { const ruleset = rulesets.global[kind]; for (let i = 0; i < ruleset.length; ++i) { const rule = ruleset[i]; if (rule.rule_id in LEGACY_RULES) { console.log("Porting legacy rule", rule); needsUpdate.push(function (kind, rule) { return cli.setPushRuleActions('global', kind, LEGACY_RULES[rule.rule_id], portLegacyActions(rule.actions)).then(() => cli.deletePushRule('global', kind, rule.rule_id)).catch(e => { console.warn(`Error when porting legacy rule: ${e}`); }); }(kind, rule)); } } } if (needsUpdate.length > 0) { // If some of the rules need to be ported then wait for the porting // to happen and then fetch the rules again. return Promise.all(needsUpdate).then(() => cli.getPushRules()); } else { // Otherwise return the rules that we already have. return rulesets; } } _updatePushRuleActions(rule, actions, enabled) { const cli = _MatrixClientPeg.MatrixClientPeg.get(); return cli.setPushRuleActions('global', rule.kind, rule.rule_id, actions).then(function () { // Then, if requested, enabled or disabled the rule if (undefined != enabled) { return cli.setPushRuleEnabled('global', rule.kind, rule.rule_id, enabled); } }); } renderNotifRulesTableRow(title, className, pushRuleVectorState) { return /*#__PURE__*/_react.default.createElement("tr", { key: className }, /*#__PURE__*/_react.default.createElement("th", null, title), /*#__PURE__*/_react.default.createElement("th", null, /*#__PURE__*/_react.default.createElement("input", { className: className + "-" + _notifications.PushRuleVectorState.OFF, type: "radio", checked: pushRuleVectorState === _notifications.PushRuleVectorState.OFF, onChange: this.onNotifStateButtonClicked })), /*#__PURE__*/_react.default.createElement("th", null, /*#__PURE__*/_react.default.createElement("input", { className: className + "-" + _notifications.PushRuleVectorState.ON, type: "radio", checked: pushRuleVectorState === _notifications.PushRuleVectorState.ON, onChange: this.onNotifStateButtonClicked })), /*#__PURE__*/_react.default.createElement("th", null, /*#__PURE__*/_react.default.createElement("input", { className: className + "-" + _notifications.PushRuleVectorState.LOUD, type: "radio", checked: pushRuleVectorState === _notifications.PushRuleVectorState.LOUD, onChange: this.onNotifStateButtonClicked }))); } renderNotifRulesTableRows() { const rows = []; for (const i in this.state.vectorPushRules) { const rule = this.state.vectorPushRules[i]; if (rule.rule === undefined && rule.vectorRuleId.startsWith(".m.")) { console.warn(`Skipping render of rule ${rule.vectorRuleId} due to no underlying rule`); continue; } //console.log("rendering: " + rule.description + ", " + rule.vectorRuleId + ", " + rule.vectorState); rows.push(this.renderNotifRulesTableRow(rule.description, rule.vectorRuleId, rule.vectorState)); } return rows; } hasEmailPusher(pushers, address) { if (pushers === undefined) { return false; } for (let i = 0; i < pushers.length; ++i) { if (pushers[i].kind === 'email' && pushers[i].pushkey === address) { return true; } } return false; } emailNotificationsRow(address, label) { return /*#__PURE__*/_react.default.createElement(_LabelledToggleSwitch.default, { value: this.hasEmailPusher(this.state.pushers, address), onChange: this.onEnableEmailNotificationsChange.bind(this, address), label: label, key: `emailNotif_${label}` }); } render() { let spinner; if (this.state.phase === Notifications.phases.LOADING) { const Loader = sdk.getComponent("elements.Spinner"); spinner = /*#__PURE__*/_react.default.createElement(Loader, null); } let masterPushRuleDiv; if (this.state.masterPushRule) { masterPushRuleDiv = /*#__PURE__*/_react.default.createElement(_LabelledToggleSwitch.default, { value: !this.state.masterPushRule.enabled, onChange: this.onEnableNotificationsChange, label: (0, _languageHandler._t)('Enable notifications for this account') }); } let clearNotificationsButton; if (_MatrixClientPeg.MatrixClientPeg.get().getRooms().some(r => r.getUnreadNotificationCount() > 0)) { clearNotificationsButton = /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { onClick: this._onClearNotifications, kind: "danger" }, (0, _languageHandler._t)("Clear notifications")); } // When enabled, the master rule inhibits all existing rules // So do not show all notification settings if (this.state.masterPushRule && this.state.masterPushRule.enabled) { return /*#__PURE__*/_react.default.createElement("div", null, masterPushRuleDiv, /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserNotifSettings_notifTable" }, (0, _languageHandler._t)('All notifications are currently disabled for all targets.')), clearNotificationsButton); } const emailThreepids = this.state.threepids.filter(tp => tp.medium === "email"); let emailNotificationsRows; if (emailThreepids.length > 0) { emailNotificationsRows = emailThreepids.map(threePid => this.emailNotificationsRow(threePid.address, `${(0, _languageHandler._t)('Enable email notifications')} (${threePid.address})`)); } else if (_SettingsStore.default.getValue(_UIFeature.UIFeature.ThirdPartyID)) { emailNotificationsRows = /*#__PURE__*/_react.default.createElement("div", null, (0, _languageHandler._t)('Add an email address to configure email notifications')); } // Build external push rules const externalRules = []; for (const i in this.state.externalPushRules) { const rule = this.state.externalPushRules[i]; externalRules.push( /*#__PURE__*/_react.default.createElement("li", null, (0, _languageHandler._t)(rule.description))); } // Show keywords not displayed by the vector UI as a single external push rule let externalKeywords = []; for (const i in this.state.externalContentRules) { const rule = this.state.externalContentRules[i]; externalKeywords.push(rule.pattern); } if (externalKeywords.length) { externalKeywords = externalKeywords.join(", "); externalRules.push( /*#__PURE__*/_react.default.createElement("li", null, (0, _languageHandler._t)('Notifications on the following keywords follow rules which can’t be displayed here:'), externalKeywords)); } let devicesSection; if (this.state.pushers === undefined) { devicesSection = /*#__PURE__*/_react.default.createElement("div", { className: "error" }, (0, _languageHandler._t)('Unable to fetch notification target list')); } else if (this.state.pushers.length === 0) { devicesSection = null; } else { // TODO: It would be great to be able to delete pushers from here too, // and this wouldn't be hard to add. const rows = []; for (let i = 0; i < this.state.pushers.length; ++i) { rows.push( /*#__PURE__*/_react.default.createElement("tr", { key: i }, /*#__PURE__*/_react.default.createElement("td", null, this.state.pushers[i].app_display_name), /*#__PURE__*/_react.default.createElement("td", null, this.state.pushers[i].device_display_name))); } devicesSection = /*#__PURE__*/_react.default.createElement("table", { className: "mx_UserNotifSettings_devicesTable" }, /*#__PURE__*/_react.default.createElement("tbody", null, rows)); } if (devicesSection) { devicesSection = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("h3", null, (0, _languageHandler._t)('Notification targets')), devicesSection); } let advancedSettings; if (externalRules.length) { const brand = _SdkConfig.default.get().brand; advancedSettings = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("h3", null, (0, _languageHandler._t)('Advanced notification settings')), (0, _languageHandler._t)('There are advanced notifications which are not shown here.'), /*#__PURE__*/_react.default.createElement("br", null), (0, _languageHandler._t)('You might have configured them in a client other than %(brand)s. ' + 'You cannot tune them in %(brand)s but they still apply.', { brand }), /*#__PURE__*/_react.default.createElement("ul", null, externalRules)); } return /*#__PURE__*/_react.default.createElement("div", null, masterPushRuleDiv, /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserNotifSettings_notifTable" }, spinner, /*#__PURE__*/_react.default.createElement(_LabelledToggleSwitch.default, { value: _SettingsStore.default.getValue("notificationsEnabled"), onChange: this.onEnableDesktopNotificationsChange, label: (0, _languageHandler._t)('Enable desktop notifications for this session') }), /*#__PURE__*/_react.default.createElement(_LabelledToggleSwitch.default, { value: _SettingsStore.default.getValue("notificationBodyEnabled"), onChange: this.onEnableDesktopNotificationBodyChange, label: (0, _languageHandler._t)('Show message in desktop notification') }), /*#__PURE__*/_react.default.createElement(_LabelledToggleSwitch.default, { value: _SettingsStore.default.getValue("audioNotificationsEnabled"), onChange: this.onEnableAudioNotificationsChange, label: (0, _languageHandler._t)('Enable audible notifications for this session') }), emailNotificationsRows, /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserNotifSettings_pushRulesTableWrapper" }, /*#__PURE__*/_react.default.createElement("table", { className: "mx_UserNotifSettings_pushRulesTable" }, /*#__PURE__*/_react.default.createElement("thead", null, /*#__PURE__*/_react.default.createElement("tr", null, /*#__PURE__*/_react.default.createElement("th", { width: "55%" }), /*#__PURE__*/_react.default.createElement("th", { width: "15%" }, (0, _languageHandler._t)('Off')), /*#__PURE__*/_react.default.createElement("th", { width: "15%" }, (0, _languageHandler._t)('On')), /*#__PURE__*/_react.default.createElement("th", { width: "15%" }, (0, _languageHandler._t)('Noisy')))), /*#__PURE__*/_react.default.createElement("tbody", null, this.renderNotifRulesTableRows()))), advancedSettings, devicesSection, clearNotificationsButton)); } }, (0, _defineProperty2.default)(_class2, "phases", { LOADING: "LOADING", // The component is loading or sending data to the hs DISPLAY: "DISPLAY", // The component is ready and display data ERROR: "ERROR" // There was an error }), _temp)) || _class); exports.default = Notifications; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL3NldHRpbmdzL05vdGlmaWNhdGlvbnMuanMiXSwibmFtZXMiOlsiTEVHQUNZX1JVTEVTIiwicG9ydExlZ2FjeUFjdGlvbnMiLCJhY3Rpb25zIiwiZGVjb2RlZCIsIk5vdGlmaWNhdGlvblV0aWxzIiwiZGVjb2RlQWN0aW9ucyIsImVuY29kZUFjdGlvbnMiLCJOb3RpZmljYXRpb25zIiwiUmVhY3QiLCJDb21wb25lbnQiLCJwaGFzZSIsInBoYXNlcyIsIkxPQURJTkciLCJtYXN0ZXJQdXNoUnVsZSIsInVuZGVmaW5lZCIsInZlY3RvclB1c2hSdWxlcyIsInZlY3RvckNvbnRlbnRSdWxlcyIsInZlY3RvclN0YXRlIiwiUHVzaFJ1bGVWZWN0b3JTdGF0ZSIsIk9OIiwicnVsZXMiLCJleHRlcm5hbFB1c2hSdWxlcyIsImV4dGVybmFsQ29udGVudFJ1bGVzIiwidGhyZWVwaWRzIiwiY2hlY2tlZCIsInNlbGYiLCJzZXRTdGF0ZSIsIk1hdHJpeENsaWVudFBlZyIsImdldCIsInNldFB1c2hSdWxlRW5hYmxlZCIsInN0YXRlIiwia2luZCIsInJ1bGVfaWQiLCJ0aGVuIiwiX3JlZnJlc2hGcm9tU2VydmVyIiwiU2V0dGluZ3NTdG9yZSIsInNldFZhbHVlIiwiU2V0dGluZ0xldmVsIiwiREVWSUNFIiwiZmluYWxseSIsImZvcmNlVXBkYXRlIiwiYWRkcmVzcyIsImVtYWlsUHVzaGVyUHJvbWlzZSIsImRhdGEiLCJTZGtDb25maWciLCJicmFuZCIsInNldFB1c2hlciIsImFwcF9pZCIsInB1c2hrZXkiLCJhcHBfZGlzcGxheV9uYW1lIiwiZGV2aWNlX2Rpc3BsYXlfbmFtZSIsImxhbmciLCJuYXZpZ2F0b3IiLCJsYW5ndWFnZSIsImFwcGVuZCIsImVtYWlsUHVzaGVyIiwiZ2V0RW1haWxQdXNoZXIiLCJwdXNoZXJzIiwiZXJyb3IiLCJFcnJvckRpYWxvZyIsInNkayIsImdldENvbXBvbmVudCIsIk1vZGFsIiwiY3JlYXRlVHJhY2tlZERpYWxvZyIsInRpdGxlIiwiZGVzY3JpcHRpb24iLCJldmVudCIsInZlY3RvclJ1bGVJZCIsInRhcmdldCIsImNsYXNzTmFtZSIsInNwbGl0IiwibmV3UHVzaFJ1bGVWZWN0b3JTdGF0ZSIsIl9zZXRLZXl3b3Jkc1B1c2hSdWxlVmVjdG9yU3RhdGUiLCJydWxlIiwiZ2V0UnVsZSIsIl9zZXRQdXNoUnVsZVZlY3RvclN0YXRlIiwia2V5d29yZHMiLCJpIiwicHVzaCIsInBhdHRlcm4iLCJsZW5ndGgiLCJzb3J0Iiwiam9pbiIsIlRleHRJbnB1dERpYWxvZyIsImJ1dHRvbiIsInZhbHVlIiwib25GaW5pc2hlZCIsInNob3VsZExlYXZlIiwibmV3VmFsdWUiLCJuZXdLZXl3b3JkcyIsInRyaW0iLCJyZWR1Y2UiLCJhcnJheSIsImtleXdvcmQiLCJpbmRleE9mIiwiX3NldEtleXdvcmRzIiwicHVzaFJ1bGVzUHJvbWlzZSIsImdldFB1c2hSdWxlcyIsIl9wb3J0UnVsZXNUb05ld0FQSSIsInJ1bGVzZXRzIiwicHVzaFJ1bGVzIiwicnVsZUNhdGVnb3JpZXMiLCJkZWZhdWx0UnVsZXMiLCJtYXN0ZXIiLCJ2ZWN0b3IiLCJvdGhlcnMiLCJnbG9iYWwiLCJPYmplY3QiLCJrZXlzIiwiciIsImNhdCIsImNvbnRlbnRSdWxlcyIsIkNvbnRlbnRSdWxlcyIsInBhcnNlQ29udGVudFJ1bGVzIiwiZXh0ZXJuYWxSdWxlcyIsInZlY3RvclJ1bGVJZHMiLCJzdWIiLCJvbktleXdvcmRzQ2xpY2tlZCIsInJ1bGVEZWZpbml0aW9uIiwiVmVjdG9yUHVzaFJ1bGVzRGVmaW5pdGlvbnMiLCJydWxlVG9WZWN0b3JTdGF0ZSIsIm90aGVyUnVsZXNEZXNjcmlwdGlvbnMiLCJydWxlRGVzY3JpcHRpb24iLCJlbmFibGVkIiwiZGVmYXVsdCIsInB1c2hlcnNQcm9taXNlIiwiZ2V0UHVzaGVycyIsInJlc3AiLCJQcm9taXNlIiwiYWxsIiwiRElTUExBWSIsImNvbnNvbGUiLCJFUlJPUiIsImdldFRocmVlUGlkcyIsImNsaSIsImdldFJvb21zIiwiZm9yRWFjaCIsImdldFVucmVhZE5vdGlmaWNhdGlvbkNvdW50IiwiZXZlbnRzIiwiZ2V0TGl2ZVRpbWVsaW5lIiwiZ2V0RXZlbnRzIiwic2VuZFJlYWRSZWNlaXB0IiwicG9wIiwiY29tcG9uZW50RGlkTW91bnQiLCJkZWZlcnJlZHMiLCJ2ZWN0b3JTdGF0ZVRvQWN0aW9ucyIsIl91cGRhdGVQdXNoUnVsZUFjdGlvbnMiLCJtZXNzYWdlIiwiYWN0aW9uc0ZvciIsIk9GRiIsIkxPVUQiLCJyZXNwcyIsInJlbW92ZURlZmVycmVkcyIsInZlY3RvckNvbnRlbnRSdWxlc1BhdHRlcm5zIiwiZGVsZXRlUHVzaFJ1bGUiLCJvbkVycm9yIiwicHVzaFJ1bGVWZWN0b3JTdGF0ZUtpbmQiLCJjb250ZW50UnVsZVZlY3RvclN0YXRlS2luZCIsImFkZFB1c2hSdWxlIiwiX2FkZERpc2FibGVkUHVzaFJ1bGUiLCJzY29wZSIsInJ1bGVJZCIsImJvZHkiLCJuZWVkc1VwZGF0ZSIsInJ1bGVzZXQiLCJsb2ciLCJzZXRQdXNoUnVsZUFjdGlvbnMiLCJjYXRjaCIsImUiLCJ3YXJuIiwicmVuZGVyTm90aWZSdWxlc1RhYmxlUm93IiwicHVzaFJ1bGVWZWN0b3JTdGF0ZSIsIm9uTm90aWZTdGF0ZUJ1dHRvbkNsaWNrZWQiLCJyZW5kZXJOb3RpZlJ1bGVzVGFibGVSb3dzIiwicm93cyIsInN0YXJ0c1dpdGgiLCJoYXNFbWFpbFB1c2hlciIsImVtYWlsTm90aWZpY2F0aW9uc1JvdyIsImxhYmVsIiwib25FbmFibGVFbWFpbE5vdGlmaWNhdGlvbnNDaGFuZ2UiLCJiaW5kIiwicmVuZGVyIiwic3Bpbm5lciIsIkxvYWRlciIsIm1hc3RlclB1c2hSdWxlRGl2Iiwib25FbmFibGVOb3RpZmljYXRpb25zQ2hhbmdlIiwiY2xlYXJOb3RpZmljYXRpb25zQnV0dG9uIiwic29tZSIsIl9vbkNsZWFyTm90aWZpY2F0aW9ucyIsImVtYWlsVGhyZWVwaWRzIiwiZmlsdGVyIiwidHAiLCJtZWRpdW0iLCJlbWFpbE5vdGlmaWNhdGlvbnNSb3dzIiwibWFwIiwidGhyZWVQaWQiLCJnZXRWYWx1ZSIsIlVJRmVhdHVyZSIsIlRoaXJkUGFydHlJRCIsImV4dGVybmFsS2V5d29yZHMiLCJkZXZpY2VzU2VjdGlvbiIsImFkdmFuY2VkU2V0dGluZ3MiLCJvbkVuYWJsZURlc2t0b3BOb3RpZmljYXRpb25zQ2hhbmdlIiwib25FbmFibGVEZXNrdG9wTm90aWZpY2F0aW9uQm9keUNoYW5nZSIsIm9uRW5hYmxlQXVkaW9Ob3RpZmljYXRpb25zQ2hhbmdlIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7O0FBaUJBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQU1BOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOzs7O0FBRUE7QUFDQTtBQUVBO0FBQ0E7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU1BLFlBQVksR0FBRztBQUNqQiwwQ0FBd0MsK0JBRHZCO0FBRWpCLG9DQUFrQyx5QkFGakI7QUFHakIsaUNBQStCLGlCQUhkO0FBSWpCLGtDQUFnQyx1QkFKZjtBQUtqQix5QkFBdUIsY0FMTjtBQU1qQiw0QkFBMEI7QUFOVCxDQUFyQjs7QUFTQSxTQUFTQyxpQkFBVCxDQUEyQkMsT0FBM0IsRUFBb0M7QUFDaEMsUUFBTUMsT0FBTyxHQUFHQyxpQ0FBa0JDLGFBQWxCLENBQWdDSCxPQUFoQyxDQUFoQjs7QUFDQSxNQUFJQyxPQUFPLEtBQUssSUFBaEIsRUFBc0I7QUFDbEIsV0FBT0MsaUNBQWtCRSxhQUFsQixDQUFnQ0gsT0FBaEMsQ0FBUDtBQUNILEdBRkQsTUFFTztBQUNIO0FBQ0E7QUFDQSxXQUFPRCxPQUFQO0FBQ0g7QUFDSjs7SUFHb0JLLGEsV0FEcEIsZ0RBQXFCLDhCQUFyQixDLG1DQUFELE1BQ3FCQSxhQURyQixTQUMyQ0MsZUFBTUMsU0FEakQsQ0FDMkQ7QUFBQTtBQUFBO0FBQUEsaURBTy9DO0FBQ0pDLE1BQUFBLEtBQUssRUFBRUgsYUFBYSxDQUFDSSxNQUFkLENB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