UNPKG

matrix-react-sdk

Version:
681 lines (663 loc) 121 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireDefault(require("react")); var _matrix = require("matrix-js-sdk/src/matrix"); var _logger = require("matrix-js-sdk/src/logger"); var _Spinner = _interopRequireDefault(require("../elements/Spinner")); var _MatrixClientPeg = require("../../../MatrixClientPeg"); var _notifications = require("../../../notifications"); var _languageHandler = require("../../../languageHandler"); var _LabelledToggleSwitch = _interopRequireDefault(require("../elements/LabelledToggleSwitch")); var _SettingsStore = _interopRequireDefault(require("../../../settings/SettingsStore")); var _StyledRadioButton = _interopRequireDefault(require("../elements/StyledRadioButton")); var _SettingLevel = require("../../../settings/SettingLevel"); var _Modal = _interopRequireDefault(require("../../../Modal")); var _ErrorDialog = _interopRequireDefault(require("../dialogs/ErrorDialog")); var _SdkConfig = _interopRequireDefault(require("../../../SdkConfig")); var _AccessibleButton = _interopRequireDefault(require("../elements/AccessibleButton")); var _TagComposer = _interopRequireDefault(require("../elements/TagComposer")); var _objects = require("../../../utils/objects"); var _arrays = require("../../../utils/arrays"); var _notifications2 = require("../../../utils/notifications"); var _updatePushRuleActions = require("../../../utils/pushRules/updatePushRuleActions"); var _Caption = require("../typography/Caption"); var _SettingsSubsectionHeading = require("./shared/SettingsSubsectionHeading"); var _SettingsSubsection = _interopRequireDefault(require("./shared/SettingsSubsection")); var _Unread = require("../../../Unread"); var _SettingsFlag = _interopRequireDefault(require("../elements/SettingsFlag")); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /* Copyright 2024 New Vector Ltd. Copyright 2016-2022 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ // TODO: this "view" component still has far too much application logic in it, // which should be factored out to other files. var Phase = /*#__PURE__*/function (Phase) { Phase["Loading"] = "loading"; Phase["Ready"] = "ready"; Phase["Persisting"] = "persisting"; Phase["Error"] = "error"; Phase["SavingError"] = "savingError"; return Phase; }(Phase || {}); var RuleClass = /*#__PURE__*/function (RuleClass) { RuleClass["Master"] = "master"; RuleClass["VectorGlobal"] = "vector_global"; RuleClass["VectorMentions"] = "vector_mentions"; RuleClass["VectorOther"] = "vector_other"; RuleClass["Other"] = "other"; return RuleClass; }(RuleClass || {}); // unknown rules, essentially const KEYWORD_RULE_ID = "_keywords"; // used as a placeholder "Rule ID" throughout this component const KEYWORD_RULE_CATEGORY = RuleClass.VectorMentions; // This array doesn't care about categories: it's just used for a simple sort const RULE_DISPLAY_ORDER = [ // Global _matrix.RuleId.DM, _matrix.RuleId.EncryptedDM, _matrix.RuleId.Message, _matrix.RuleId.EncryptedMessage, // Mentions _matrix.RuleId.ContainsDisplayName, _matrix.RuleId.ContainsUserName, _matrix.RuleId.AtRoomNotification, // Other _matrix.RuleId.InviteToSelf, _matrix.RuleId.IncomingCall, _matrix.RuleId.SuppressNotices, _matrix.RuleId.Tombstone]; const findInDefaultRules = (ruleId, defaultRules) => { for (const category in defaultRules) { const rule = defaultRules[category].find(rule => rule.rule_id === ruleId); if (rule) { return rule; } } }; // Vector notification states ordered by loudness in ascending order const OrderedVectorStates = [_notifications.VectorState.Off, _notifications.VectorState.On, _notifications.VectorState.Loud]; /** * Find the 'loudest' vector state assigned to a rule * and it's synced rules * If rules have fallen out of sync, * the loudest rule can determine the display value * @param defaultRules * @param rule - parent rule * @param definition - definition of parent rule * @returns VectorState - the maximum/loudest state for the parent and synced rules */ const maximumVectorState = (defaultRules, rule, definition) => { if (!definition.syncedRuleIds?.length) { return undefined; } const vectorState = definition.syncedRuleIds.reduce((maxVectorState, ruleId) => { // already set to maximum if (maxVectorState === _notifications.VectorState.Loud) { return maxVectorState; } const syncedRule = findInDefaultRules(ruleId, defaultRules); if (syncedRule) { const syncedRuleVectorState = definition.ruleToVectorState(syncedRule); // if syncedRule is 'louder' than current maximum // set maximum to louder vectorState if (syncedRuleVectorState && OrderedVectorStates.indexOf(syncedRuleVectorState) > OrderedVectorStates.indexOf(maxVectorState)) { return syncedRuleVectorState; } } return maxVectorState; }, definition.ruleToVectorState(rule)); return vectorState; }; const NotificationActivitySettings = () => { return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_SettingsFlag.default, { name: "Notifications.showbold", level: _SettingLevel.SettingLevel.DEVICE }), /*#__PURE__*/_react.default.createElement(_SettingsFlag.default, { name: "Notifications.tac_only_notifications", level: _SettingLevel.SettingLevel.DEVICE })); }; /** * The old, deprecated notifications tab view, only displayed if the user has the labs flag disabled. */ class Notifications extends _react.default.PureComponent { constructor(props) { super(props); (0, _defineProperty2.default)(this, "settingWatchers", void 0); (0, _defineProperty2.default)(this, "onMasterRuleChanged", async checked => { this.setState({ phase: Phase.Persisting }); const masterRule = this.state.masterPushRule; try { await _MatrixClientPeg.MatrixClientPeg.safeGet().setPushRuleEnabled("global", masterRule.kind, masterRule.rule_id, !checked); await this.refreshFromServer(); } catch (e) { this.setState({ phase: Phase.Error }); _logger.logger.error("Error updating master push rule:", e); this.showSaveError(); } }); (0, _defineProperty2.default)(this, "setSavingError", ruleId => { this.setState(({ ruleIdsWithError }) => ({ phase: Phase.SavingError, ruleIdsWithError: _objectSpread(_objectSpread({}, ruleIdsWithError), {}, { [ruleId]: true }) })); }); (0, _defineProperty2.default)(this, "updateDeviceNotifications", async checked => { await _SettingsStore.default.setValue("deviceNotificationsEnabled", null, _SettingLevel.SettingLevel.DEVICE, checked); }); (0, _defineProperty2.default)(this, "onEmailNotificationsChanged", async (email, checked) => { this.setState({ phase: Phase.Persisting }); try { if (checked) { await _MatrixClientPeg.MatrixClientPeg.safeGet().setPusher({ kind: "email", app_id: "m.email", pushkey: email, app_display_name: "Email Notifications", device_display_name: email, lang: navigator.language, data: { brand: _SdkConfig.default.get().brand }, // We always append for email pushers since we don't want to stop other // accounts notifying to the same email address append: true }); } else { const pusher = this.state.pushers?.find(p => p.kind === "email" && p.pushkey === email); if (pusher) { await _MatrixClientPeg.MatrixClientPeg.safeGet().removePusher(pusher.pushkey, pusher.app_id); } } await this.refreshFromServer(); } catch (e) { this.setState({ phase: Phase.Error }); _logger.logger.error("Error updating email pusher:", e); this.showSaveError(); } }); (0, _defineProperty2.default)(this, "onDesktopNotificationsChanged", async checked => { await _SettingsStore.default.setValue("notificationsEnabled", null, _SettingLevel.SettingLevel.DEVICE, checked); }); (0, _defineProperty2.default)(this, "onDesktopShowBodyChanged", async checked => { await _SettingsStore.default.setValue("notificationBodyEnabled", null, _SettingLevel.SettingLevel.DEVICE, checked); }); (0, _defineProperty2.default)(this, "onAudioNotificationsChanged", async checked => { await _SettingsStore.default.setValue("audioNotificationsEnabled", null, _SettingLevel.SettingLevel.DEVICE, checked); }); (0, _defineProperty2.default)(this, "onRadioChecked", async (rule, checkedState) => { this.setState(({ ruleIdsWithError }) => ({ phase: Phase.Persisting, ruleIdsWithError: _objectSpread(_objectSpread({}, ruleIdsWithError), {}, { [rule.ruleId]: false }) })); try { const cli = _MatrixClientPeg.MatrixClientPeg.safeGet(); if (rule.ruleId === KEYWORD_RULE_ID) { // should not encounter this if (!this.state.vectorKeywordRuleInfo) { throw new Error("Notification data is incomplete."); } // Update all the keywords for (const rule of this.state.vectorKeywordRuleInfo.rules) { let enabled; let actions; if (checkedState === _notifications.VectorState.On) { if (rule.actions.length !== 1) { // XXX: Magic number actions = _notifications.PushRuleVectorState.actionsFor(checkedState); } if (this.state.vectorKeywordRuleInfo.vectorState === _notifications.VectorState.Off) { enabled = true; } } else if (checkedState === _notifications.VectorState.Loud) { if (rule.actions.length !== 3) { // XXX: Magic number actions = _notifications.PushRuleVectorState.actionsFor(checkedState); } if (this.state.vectorKeywordRuleInfo.vectorState === _notifications.VectorState.Off) { enabled = true; } } else { enabled = false; } if (actions) { await cli.setPushRuleActions("global", rule.kind, rule.rule_id, actions); } if (enabled !== undefined) { await cli.setPushRuleEnabled("global", rule.kind, rule.rule_id, enabled); } } } else { const definition = _notifications.VectorPushRulesDefinitions[rule.ruleId]; const actions = definition.vectorStateToActions[checkedState]; // we should not encounter this // satisfies types if (!rule.rule) { throw new Error("Cannot update rule: push rule data is incomplete."); } await (0, _updatePushRuleActions.updatePushRuleActions)(cli, rule.rule.rule_id, rule.rule.kind, actions); await (0, _updatePushRuleActions.updateExistingPushRulesWithActions)(cli, definition.syncedRuleIds, actions); } await this.refreshFromServer(); } catch (e) { this.setSavingError(rule.ruleId); _logger.logger.error("Error updating push rule:", e); } }); (0, _defineProperty2.default)(this, "onClearNotificationsClicked", async () => { try { this.setState({ clearingNotifications: true }); const client = _MatrixClientPeg.MatrixClientPeg.safeGet(); await (0, _notifications2.clearAllNotifications)(client); } finally { this.setState({ clearingNotifications: false }); } }); (0, _defineProperty2.default)(this, "onKeywordAdd", keyword => { // should not encounter this if (!this.state.vectorKeywordRuleInfo) { throw new Error("Notification data is incomplete."); } const originalRules = (0, _objects.objectClone)(this.state.vectorKeywordRuleInfo.rules); // We add the keyword immediately as a sort of local echo effect this.setState({ phase: Phase.Persisting, vectorKeywordRuleInfo: _objectSpread(_objectSpread({}, this.state.vectorKeywordRuleInfo), {}, { rules: [...this.state.vectorKeywordRuleInfo.rules, // XXX: Horrible assumption that we don't need the remaining fields { pattern: keyword }] }) }, async () => { await this.setKeywords(this.state.vectorKeywordRuleInfo.rules.map(r => r.pattern), originalRules); }); }); (0, _defineProperty2.default)(this, "onKeywordRemove", keyword => { // should not encounter this if (!this.state.vectorKeywordRuleInfo) { throw new Error("Notification data is incomplete."); } const originalRules = (0, _objects.objectClone)(this.state.vectorKeywordRuleInfo.rules); // We remove the keyword immediately as a sort of local echo effect this.setState({ phase: Phase.Persisting, vectorKeywordRuleInfo: _objectSpread(_objectSpread({}, this.state.vectorKeywordRuleInfo), {}, { rules: this.state.vectorKeywordRuleInfo.rules.filter(r => r.pattern !== keyword) }) }, async () => { await this.setKeywords(this.state.vectorKeywordRuleInfo.rules.map(r => r.pattern), originalRules); }); }); this.state = { phase: Phase.Loading, deviceNotificationsEnabled: _SettingsStore.default.getValue("deviceNotificationsEnabled") ?? true, desktopNotifications: _SettingsStore.default.getValue("notificationsEnabled"), desktopShowBody: _SettingsStore.default.getValue("notificationBodyEnabled"), audioNotifications: _SettingsStore.default.getValue("audioNotificationsEnabled"), clearingNotifications: false, ruleIdsWithError: {} }; this.settingWatchers = [_SettingsStore.default.watchSetting("notificationsEnabled", null, (...[,,,, value]) => this.setState({ desktopNotifications: value })), _SettingsStore.default.watchSetting("deviceNotificationsEnabled", null, (...[,,,, value]) => { this.setState({ deviceNotificationsEnabled: value }); }), _SettingsStore.default.watchSetting("notificationBodyEnabled", null, (...[,,,, value]) => this.setState({ desktopShowBody: value })), _SettingsStore.default.watchSetting("audioNotificationsEnabled", null, (...[,,,, value]) => this.setState({ audioNotifications: value }))]; } get isInhibited() { // Caution: The master rule's enabled state is inverted from expectation. When // the master rule is *enabled* it means all other rules are *disabled* (or // inhibited). Conversely, when the master rule is *disabled* then all other rules // are *enabled* (or operate fine). return !!this.state.masterPushRule?.enabled; } componentDidMount() { // noinspection JSIgnoredPromiseFromCall this.refreshFromServer(); this.refreshFromAccountData(); } componentWillUnmount() { this.settingWatchers.forEach(watcher => _SettingsStore.default.unwatchSetting(watcher)); } componentDidUpdate(prevProps, prevState) { if (this.state.deviceNotificationsEnabled !== prevState.deviceNotificationsEnabled) { this.persistLocalNotificationSettings(this.state.deviceNotificationsEnabled); } } async refreshFromServer() { try { const newState = (await Promise.all([this.refreshRules(), this.refreshPushers(), this.refreshThreepids()])).reduce((p, c) => Object.assign(c, p), {}); this.setState(_objectSpread(_objectSpread({}, newState), {}, { phase: Phase.Ready })); } catch (e) { _logger.logger.error("Error setting up notifications for settings: ", e); this.setState({ phase: Phase.Error }); } } async refreshFromAccountData() { const cli = _MatrixClientPeg.MatrixClientPeg.safeGet(); const settingsEvent = cli.getAccountData((0, _notifications2.getLocalNotificationAccountDataEventType)(cli.deviceId)); if (settingsEvent) { const notificationsEnabled = !settingsEvent.getContent().is_silenced; await this.updateDeviceNotifications(notificationsEnabled); } } persistLocalNotificationSettings(enabled) { const cli = _MatrixClientPeg.MatrixClientPeg.safeGet(); return cli.setAccountData((0, _notifications2.getLocalNotificationAccountDataEventType)(cli.deviceId), { is_silenced: !enabled }); } async refreshRules() { const ruleSets = await _MatrixClientPeg.MatrixClientPeg.safeGet().getPushRules(); const categories = { [_matrix.RuleId.Master]: RuleClass.Master, [_matrix.RuleId.DM]: RuleClass.VectorGlobal, [_matrix.RuleId.EncryptedDM]: RuleClass.VectorGlobal, [_matrix.RuleId.Message]: RuleClass.VectorGlobal, [_matrix.RuleId.EncryptedMessage]: RuleClass.VectorGlobal, [_matrix.RuleId.ContainsDisplayName]: RuleClass.VectorMentions, [_matrix.RuleId.ContainsUserName]: RuleClass.VectorMentions, [_matrix.RuleId.AtRoomNotification]: RuleClass.VectorMentions, [_matrix.RuleId.InviteToSelf]: RuleClass.VectorOther, [_matrix.RuleId.IncomingCall]: RuleClass.VectorOther, [_matrix.RuleId.SuppressNotices]: RuleClass.VectorOther, [_matrix.RuleId.Tombstone]: RuleClass.VectorOther // Everything maps to a generic "other" (unknown rule) }; const defaultRules = { [RuleClass.Master]: [], [RuleClass.VectorGlobal]: [], [RuleClass.VectorMentions]: [], [RuleClass.VectorOther]: [], [RuleClass.Other]: [] }; for (const k in ruleSets.global) { // noinspection JSUnfilteredForInLoop const kind = k; for (const r of ruleSets.global[kind]) { const rule = Object.assign(r, { kind }); const category = categories[rule.rule_id] ?? RuleClass.Other; if (rule.rule_id[0] === ".") { defaultRules[category].push(rule); } } } const preparedNewState = {}; if (defaultRules.master.length > 0) { preparedNewState.masterPushRule = defaultRules.master[0]; } else { // XXX: Can this even happen? How do we safely recover? throw new Error("Failed to locate a master push rule"); } // Parse keyword rules preparedNewState.vectorKeywordRuleInfo = _notifications.ContentRules.parseContentRules(ruleSets); // Prepare rendering for all of our known rules preparedNewState.vectorPushRules = {}; const vectorCategories = [RuleClass.VectorGlobal, RuleClass.VectorMentions, RuleClass.VectorOther]; for (const category of vectorCategories) { preparedNewState.vectorPushRules[category] = []; for (const rule of defaultRules[category]) { const definition = _notifications.VectorPushRulesDefinitions[rule.rule_id]; const vectorState = definition.ruleToVectorState(rule); preparedNewState.vectorPushRules[category].push({ ruleId: rule.rule_id, rule, vectorState, syncedVectorState: maximumVectorState(defaultRules, rule, definition), description: (0, _languageHandler._t)(definition.description) }); } // Quickly sort the rules for display purposes preparedNewState.vectorPushRules[category].sort((a, b) => { let idxA = RULE_DISPLAY_ORDER.indexOf(a.ruleId); let idxB = RULE_DISPLAY_ORDER.indexOf(b.ruleId); // Assume unknown things go at the end if (idxA < 0) idxA = RULE_DISPLAY_ORDER.length; if (idxB < 0) idxB = RULE_DISPLAY_ORDER.length; return idxA - idxB; }); if (category === KEYWORD_RULE_CATEGORY) { preparedNewState.vectorPushRules[category].push({ ruleId: KEYWORD_RULE_ID, description: (0, _languageHandler._t)("settings|notifications|messages_containing_keywords"), vectorState: preparedNewState.vectorKeywordRuleInfo.vectorState }); } } return preparedNewState; } refreshPushers() { return _MatrixClientPeg.MatrixClientPeg.safeGet().getPushers(); } refreshThreepids() { return _MatrixClientPeg.MatrixClientPeg.safeGet().getThreePids(); } showSaveError() { _Modal.default.createDialog(_ErrorDialog.default, { title: (0, _languageHandler._t)("settings|notifications|error_saving"), description: (0, _languageHandler._t)("settings|notifications|error_saving_detail") }); } async setKeywords(unsafeKeywords, originalRules) { try { // De-duplicate and remove empties const keywords = (0, _arrays.filterBoolean)(Array.from(new Set(unsafeKeywords))); const oldKeywords = (0, _arrays.filterBoolean)(Array.from(new Set(originalRules.map(r => r.pattern)))); // Note: Technically because of the UI interaction (at the time of writing), the diff // will only ever be +/-1 so we don't really have to worry about efficiently handling // tons of keyword changes. const diff = (0, _arrays.arrayDiff)(oldKeywords, keywords); for (const word of diff.removed) { for (const rule of originalRules.filter(r => r.pattern === word)) { await _MatrixClientPeg.MatrixClientPeg.safeGet().deletePushRule("global", rule.kind, rule.rule_id); } } let ruleVectorState = this.state.vectorKeywordRuleInfo.vectorState; if (ruleVectorState === _notifications.VectorState.Off) { // When the current global keywords rule is OFF, we need to look at // the flavor of existing rules to apply the same actions // when creating the new rule. const existingRuleVectorState = originalRules.length ? _notifications.PushRuleVectorState.contentRuleVectorStateKind(originalRules[0]) : undefined; // set to same state as existing rule, or default to On ruleVectorState = existingRuleVectorState ?? _notifications.VectorState.On; //default } const kind = _matrix.PushRuleKind.ContentSpecific; for (const word of diff.added) { await _MatrixClientPeg.MatrixClientPeg.safeGet().addPushRule("global", kind, word, { actions: _notifications.PushRuleVectorState.actionsFor(ruleVectorState), pattern: word }); if (ruleVectorState === _notifications.VectorState.Off) { await _MatrixClientPeg.MatrixClientPeg.safeGet().setPushRuleEnabled("global", kind, word, false); } } await this.refreshFromServer(); } catch (e) { this.setState({ phase: Phase.Error }); _logger.logger.error("Error updating keyword push rules:", e); this.showSaveError(); } } renderTopSection() { const masterSwitch = /*#__PURE__*/_react.default.createElement(_LabelledToggleSwitch.default, { "data-testid": "notif-master-switch", value: !this.isInhibited, label: (0, _languageHandler._t)("settings|notifications|enable_notifications_account"), caption: (0, _languageHandler._t)("settings|notifications|enable_notifications_account_detail"), onChange: this.onMasterRuleChanged, disabled: this.state.phase === Phase.Persisting }); // If all the rules are inhibited, don't show anything. if (this.isInhibited) { return masterSwitch; } const emailSwitches = (this.state.threepids || []).filter(t => t.medium === _matrix.ThreepidMedium.Email).map(e => /*#__PURE__*/_react.default.createElement(_LabelledToggleSwitch.default, { "data-testid": "notif-email-switch", key: e.address, value: !!this.state.pushers?.some(p => p.kind === "email" && p.pushkey === e.address), label: (0, _languageHandler._t)("settings|notifications|enable_email_notifications", { email: e.address }), onChange: this.onEmailNotificationsChanged.bind(this, e.address), disabled: this.state.phase === Phase.Persisting })); return /*#__PURE__*/_react.default.createElement(_SettingsSubsection.default, null, masterSwitch, /*#__PURE__*/_react.default.createElement(_LabelledToggleSwitch.default, { "data-testid": "notif-device-switch", value: this.state.deviceNotificationsEnabled, label: (0, _languageHandler._t)("settings|notifications|enable_notifications_device"), onChange: checked => this.updateDeviceNotifications(checked), disabled: this.state.phase === Phase.Persisting }), this.state.deviceNotificationsEnabled && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_LabelledToggleSwitch.default, { "data-testid": "notif-setting-notificationsEnabled", value: this.state.desktopNotifications, onChange: this.onDesktopNotificationsChanged, label: (0, _languageHandler._t)("settings|notifications|enable_desktop_notifications_session"), disabled: this.state.phase === Phase.Persisting }), /*#__PURE__*/_react.default.createElement(_LabelledToggleSwitch.default, { "data-testid": "notif-setting-notificationBodyEnabled", value: this.state.desktopShowBody, onChange: this.onDesktopShowBodyChanged, label: (0, _languageHandler._t)("settings|notifications|show_message_desktop_notification"), disabled: this.state.phase === Phase.Persisting }), /*#__PURE__*/_react.default.createElement(_LabelledToggleSwitch.default, { "data-testid": "notif-setting-audioNotificationsEnabled", value: this.state.audioNotifications, onChange: this.onAudioNotificationsChanged, label: (0, _languageHandler._t)("settings|notifications|enable_audible_notifications_session"), disabled: this.state.phase === Phase.Persisting })), emailSwitches); } renderCategory(category) { if (this.isInhibited) { return null; // nothing to show for the section } let keywordComposer; if (category === RuleClass.VectorMentions) { const tags = (0, _arrays.filterBoolean)(this.state.vectorKeywordRuleInfo?.rules.map(r => r.pattern) || []); keywordComposer = /*#__PURE__*/_react.default.createElement(_TagComposer.default, { tags: tags, onAdd: this.onKeywordAdd, onRemove: this.onKeywordRemove, disabled: this.state.phase === Phase.Persisting, label: (0, _languageHandler._t)("notifications|keyword"), placeholder: (0, _languageHandler._t)("notifications|keyword_new") }); } const VectorStateToLabel = { [_notifications.VectorState.On]: (0, _languageHandler._t)("common|on"), [_notifications.VectorState.Off]: (0, _languageHandler._t)("common|off"), [_notifications.VectorState.Loud]: (0, _languageHandler._t)("settings|notifications|noisy") }; const makeRadio = (r, s) => /*#__PURE__*/_react.default.createElement(_StyledRadioButton.default, { key: r.ruleId + s, name: r.ruleId, checked: (r.syncedVectorState ?? r.vectorState) === s, onChange: this.onRadioChecked.bind(this, r, s), disabled: this.state.phase === Phase.Persisting, "aria-label": VectorStateToLabel[s] }); const fieldsetRows = this.state.vectorPushRules?.[category]?.map(r => /*#__PURE__*/_react.default.createElement("fieldset", { key: category + r.ruleId, "data-testid": category + r.ruleId, className: "mx_UserNotifSettings_gridRowContainer" }, /*#__PURE__*/_react.default.createElement("legend", { className: "mx_UserNotifSettings_gridRowLabel" }, r.description), makeRadio(r, _notifications.VectorState.Off), makeRadio(r, _notifications.VectorState.On), makeRadio(r, _notifications.VectorState.Loud), this.state.ruleIdsWithError[r.ruleId] && /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserNotifSettings_gridRowError" }, /*#__PURE__*/_react.default.createElement(_Caption.Caption, { isError: true }, (0, _languageHandler._t)("settings|notifications|error_updating"))))); let sectionName; switch (category) { case RuleClass.VectorGlobal: sectionName = (0, _languageHandler._t)("notifications|class_global"); break; case RuleClass.VectorMentions: sectionName = (0, _languageHandler._t)("notifications|mentions_keywords"); break; case RuleClass.VectorOther: sectionName = (0, _languageHandler._t)("notifications|class_other"); break; default: throw new Error("Developer error: Unnamed notifications section: " + category); } return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("div", { "data-testid": `notif-section-${category}`, className: "mx_UserNotifSettings_grid" }, /*#__PURE__*/_react.default.createElement(_SettingsSubsectionHeading.SettingsSubsectionHeading, { heading: sectionName }), /*#__PURE__*/_react.default.createElement("span", { className: "mx_UserNotifSettings_gridColumnLabel" }, VectorStateToLabel[_notifications.VectorState.Off]), /*#__PURE__*/_react.default.createElement("span", { className: "mx_UserNotifSettings_gridColumnLabel" }, VectorStateToLabel[_notifications.VectorState.On]), /*#__PURE__*/_react.default.createElement("span", { className: "mx_UserNotifSettings_gridColumnLabel" }, VectorStateToLabel[_notifications.VectorState.Loud]), fieldsetRows), keywordComposer); } renderTargets() { if (this.isInhibited) return null; // no targets if there's no notifications const rows = this.state.pushers?.map(p => /*#__PURE__*/_react.default.createElement("tr", { key: p.kind + p.pushkey }, /*#__PURE__*/_react.default.createElement("td", null, p.app_display_name), /*#__PURE__*/_react.default.createElement("td", null, p.device_display_name))); if (!rows?.length) return null; // no targets to show return /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserNotifSettings_floatingSection" }, /*#__PURE__*/_react.default.createElement("div", null, (0, _languageHandler._t)("settings|notifications|push_targets")), /*#__PURE__*/_react.default.createElement("table", null, /*#__PURE__*/_react.default.createElement("tbody", null, rows))); } render() { if (this.state.phase === Phase.Loading) { // Ends up default centered return /*#__PURE__*/_react.default.createElement(_Spinner.default, null); } else if (this.state.phase === Phase.Error) { return /*#__PURE__*/_react.default.createElement("p", { "data-testid": "error-message" }, (0, _languageHandler._t)("settings|notifications|error_loading")); } let clearNotifsButton; if (_MatrixClientPeg.MatrixClientPeg.safeGet().getRooms().some(r => (0, _Unread.doesRoomHaveUnreadMessages)(r, true))) { clearNotifsButton = /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { onClick: this.onClearNotificationsClicked, disabled: this.state.clearingNotifications, kind: "danger", className: "mx_UserNotifSettings_clearNotifsButton", "data-testid": "clear-notifications" }, (0, _languageHandler._t)("notifications|mark_all_read")); } return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, this.renderTopSection(), this.renderCategory(RuleClass.VectorGlobal), this.renderCategory(RuleClass.VectorMentions), this.renderCategory(RuleClass.VectorOther), this.renderTargets(), /*#__PURE__*/_react.default.createElement(NotificationActivitySettings, null), clearNotifsButton); } } exports.default = Notifications; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9tYXRyaXgiLCJfbG9nZ2VyIiwiX1NwaW5uZXIiLCJfTWF0cml4Q2xpZW50UGVnIiwiX25vdGlmaWNhdGlvbnMiLCJfbGFuZ3VhZ2VIYW5kbGVyIiwiX0xhYmVsbGVkVG9nZ2xlU3dpdGNoIiwiX1NldHRpbmdzU3RvcmUiLCJfU3R5bGVkUmFkaW9CdXR0b24iLCJfU2V0dGluZ0xldmVsIiwiX01vZGFsIiwiX0Vycm9yRGlhbG9nIiwiX1Nka0NvbmZpZyIsIl9BY2Nlc3NpYmxlQnV0dG9uIiwiX1RhZ0NvbXBvc2VyIiwiX29iamVjdHMiLCJfYXJyYXlzIiwiX25vdGlmaWNhdGlvbnMyIiwiX3VwZGF0ZVB1c2hSdWxlQWN0aW9ucyIsIl9DYXB0aW9uIiwiX1NldHRpbmdzU3Vic2VjdGlvbkhlYWRpbmciLCJfU2V0dGluZ3NTdWJzZWN0aW9uIiwiX1VucmVhZCIsIl9TZXR0aW5nc0ZsYWciLCJvd25LZXlzIiwiZSIsInIiLCJ0IiwiT2JqZWN0Iiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsIm8iLCJmaWx0ZXIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImxlbmd0aCIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkyIiwiZGVmYXVsdCIsImdldE93blByb3BlcnR5RGVzY3JpcHRvcnMiLCJkZWZpbmVQcm9wZXJ0aWVzIiwiZGVmaW5lUHJvcGVydHkiLCJQaGFzZSIsIlJ1bGVDbGFzcyIsIktFWVdPUkRfUlVMRV9JRCIsIktFWVdPUkRfUlVMRV9DQVRFR09SWSIsIlZlY3Rvck1lbnRpb25zIiwiUlVMRV9ESVNQTEFZX09SREVSIiwiUnVsZUlkIiwiRE0iLCJFbmNyeXB0ZWRETSIsIk1lc3NhZ2UiLCJFbmNyeXB0ZWRNZXNzYWdlIiwiQ29udGFpbnNEaXNwbGF5TmFtZSIsIkNvbnRhaW5zVXNlck5hbWUiLCJBdFJvb21Ob3RpZmljYXRpb24iLCJJbnZpdGVUb1NlbGYiLCJJbmNvbWluZ0NhbGwiLCJTdXBwcmVzc05vdGljZXMiLCJUb21ic3RvbmUiLCJmaW5kSW5EZWZhdWx0UnVsZXMiLCJydWxlSWQiLCJkZWZhdWx0UnVsZXMiLCJjYXRlZ29yeSIsInJ1bGUiLCJmaW5kIiwicnVsZV9pZCIsIk9yZGVyZWRWZWN0b3JTdGF0ZXMiLCJWZWN0b3JTdGF0ZSIsIk9mZiIsIk9uIiwiTG91ZCIsIm1heGltdW1WZWN0b3JTdGF0ZSIsImRlZmluaXRpb24iLCJzeW5jZWRSdWxlSWRzIiwidW5kZWZpbmVkIiwidmVjdG9yU3RhdGUiLCJyZWR1Y2UiLCJtYXhWZWN0b3JTdGF0ZSIsInN5bmNlZFJ1bGUiLCJzeW5jZWRSdWxlVmVjdG9yU3RhdGUiLCJydWxlVG9WZWN0b3JTdGF0ZSIsImluZGV4T2YiLCJOb3RpZmljYXRpb25BY3Rpdml0eVNldHRpbmdzIiwiY3JlYXRlRWxlbWVudCIsIm5hbWUiLCJsZXZlbCIsIlNldHRpbmdMZXZlbCIsIkRFVklDRSIsIk5vdGlmaWNhdGlvbnMiLCJSZWFjdCIsIlB1cmVDb21wb25lbnQiLCJjb25zdHJ1Y3RvciIsInByb3BzIiwiY2hlY2tlZCIsInNldFN0YXRlIiwicGhhc2UiLCJQZXJzaXN0aW5nIiwibWFzdGVyUnVsZSIsInN0YXRlIiwibWFzdGVyUHVzaFJ1bGUiLCJNYXRyaXhDbGllbnRQZWciLCJzYWZlR2V0Iiwic2V0UHVzaFJ1bGVFbmFibGVkIiwia2luZCIsInJlZnJlc2hGcm9tU2VydmVyIiwiRXJyb3IiLCJsb2dnZXIiLCJlcnJvciIsInNob3dTYXZlRXJyb3IiLCJydWxlSWRzV2l0aEVycm9yIiwiU2F2aW5nRXJyb3IiLCJTZXR0aW5nc1N0b3JlIiwic2V0VmFsdWUiLCJlbWFpbCIsInNldFB1c2hlciIsImFwcF9pZCIsInB1c2hrZXkiLCJhcHBfZGlzcGxheV9uYW1lIiwiZGV2aWNlX2Rpc3BsYXlfbmFtZSIsImxhbmciLCJuYXZpZ2F0b3IiLCJsYW5ndWFnZSIsImRhdGEiLCJicmFuZCIsIlNka0NvbmZpZyIsImdldCIsImFwcGVuZCIsInB1c2hlciIsInB1c2hlcnMiLCJwIiwicmVtb3ZlUHVzaGVyIiwiY2hlY2tlZFN0YXRlIiwiY2xpIiwidmVjdG9yS2V5d29yZFJ1bGVJbmZvIiwicnVsZXMiLCJlbmFibGVkIiwiYWN0aW9ucyIsIlB1c2hSdWxlVmVjdG9yU3RhdGUiLCJhY3Rpb25zRm9yIiwic2V0UHVzaFJ1bGVBY3Rpb25zIiwiVmVjdG9yUHVzaFJ1bGVzRGVmaW5pdGlvbnMiLCJ2ZWN0b3JTdGF0ZVRvQWN0aW9ucyIsInVwZGF0ZVB1c2hSdWxlQWN0aW9ucyIsInVwZGF0ZUV4aXN0aW5nUHVzaFJ1bGVzV2l0aEFjdGlvbnMiLCJzZXRTYXZpbmdFcnJvciIsImNsZWFyaW5nTm90aWZpY2F0aW9ucyIsImNsaWVudCIsImNsZWFyQWxsTm90aWZpY2F0aW9ucyIsImtleXdvcmQiLCJvcmlnaW5hbFJ1bGVzIiwib2JqZWN0Q2xvbmUiLCJwYXR0ZXJuIiwic2V0S2V5d29yZHMiLCJtYXAiLCJMb2FkaW5nIiwiZGV2aWNlTm90aWZpY2F0aW9uc0VuYWJsZWQiLCJnZXRWYWx1ZSIsImRlc2t0b3BOb3RpZmljYXRpb25zIiwiZGVza3RvcFNob3dCb2R5IiwiYXVkaW9Ob3RpZmljYXRpb25zIiwic2V0dGluZ1dhdGNoZXJzIiwid2F0Y2hTZXR0aW5nIiwidmFsdWUiLCJpc0luaGliaXRlZCIsImNvbXBvbmVudERpZE1vdW50IiwicmVmcmVzaEZyb21BY2NvdW50RGF0YSIsImNvbXBvbmVudFdpbGxVbm1vdW50Iiwid2F0Y2hlciIsInVud2F0Y2hTZXR0aW5nIiwiY29tcG9uZW50RGlkVXBkYXRlIiwicHJldlByb3BzIiwicHJldlN0YXRlIiwicGVyc2lzdExvY2FsTm90aWZpY2F0aW9uU2V0dGluZ3MiLCJuZXdTdGF0ZSIsIlByb21pc2UiLCJhbGwiLCJyZWZyZXNoUnVsZXMiLCJyZWZyZXNoUHVzaGVycyIsInJlZnJlc2hUaHJlZXBpZHMiLCJjIiwiYXNzaWduIiwiUmVhZHkiLCJzZXR0aW5nc0V2ZW50IiwiZ2V0QWNjb3VudERhdGEiLCJnZXRMb2NhbE5vdGlmaWNhdGlvbkFjY291bnREYXRhRXZlbnRUeXBlIiwiZGV2aWNlSWQiLCJub3RpZmljYXRpb25zRW5hYmxlZCIsImdldENvbnRlbnQiLCJpc19zaWxlbmNlZCIsInVwZGF0ZURldmljZU5vdGlmaWNhdGlvbnMiLCJzZXRBY2NvdW50RGF0YSIsInJ1bGVTZXRzIiwiZ2V0UHVzaFJ1bGVzIiwiY2F0ZWdvcmllcyIsIk1hc3RlciIsIlZlY3Rvckdsb2JhbCIsIlZlY3Rvck90aGVyIiwiT3RoZXIiLCJrIiwiZ2xvYmFsIiwicHJlcGFyZWROZXdTdGF0ZSIsIm1hc3RlciIsIkNvbnRlbnRSdWxlcyIsInBhcnNlQ29udGVudFJ1bGVzIiwidmVjdG9yUHVzaFJ1bGVzIiwidmVjdG9yQ2F0ZWdvcmllcyIsInN5bmNlZFZlY3RvclN0YXRlIiwiZGVzY3JpcHRpb24iLCJfdCIsInNvcnQiLCJhIiwiYiIsImlkeEEiLCJpZHhCIiwiZ2V0UHVzaGVycyIsImdldFRocmVlUGlkcyIsIk1vZGFsIiwiY3JlYXRlRGlhbG9nIiwiRXJyb3JEaWFsb2ciLCJ0aXRsZSIsInVuc2FmZUtleXdvcmRzIiwia2V5d29yZHMiLCJmaWx0ZXJCb29sZWFuIiwiQXJyYXkiLCJmcm9tIiwiU2V0Iiwib2xkS2V5d29yZHMiLCJkaWZmIiwiYXJyYXlEaWZmIiwid29yZCIsInJlbW92ZWQiLCJkZWxldGVQdXNoUnVsZSIsInJ1bGVWZWN0b3JTdGF0ZSIsImV4aXN0aW5nUnVsZVZlY3RvclN0YXRlIiwiY29udGVudFJ1bGVWZWN0b3JTdGF0ZUtpbmQiLCJQdXNoUnVsZUtpbmQiLCJDb250ZW50U3BlY2lmaWMiLCJhZGRlZCIsImFkZFB1c2hSdWxlIiwicmVuZGVyVG9wU2VjdGlvbiIsIm1hc3RlclN3aXRjaCIsImxhYmVsIiwiY2FwdGlvbiIsIm9uQ2hhbmdlIiwib25NYXN0ZXJSdWxlQ2hhbmdlZCIsImRpc2FibGVkIiwiZW1haWxTd2l0Y2hlcyIsInRocmVlcGlkcyIsIm1lZGl1bSIsIlRocmVlcGlkTWVkaXVtIiwiRW1haWwiLCJrZXkiLCJhZGRyZXNzIiwic29tZSIsIm9uRW1haWxOb3RpZmljYXRpb25zQ2hhbmdlZCIsImJpbmQiLCJGcmFnbWVudCIsIm9uRGVza3RvcE5vdGlmaWNhdGlvbnNDaGFuZ2VkIiwib25EZXNrdG9wU2hvd0JvZHlDaGFuZ2VkIiwib25BdWRpb05vdGlmaWNhdGlvbnNDaGFuZ2VkIiwicmVuZGVyQ2F0ZWdvcnkiLCJrZXl3b3JkQ29tcG9zZXIiLCJ0YWdzIiwib25BZGQiLCJvbktleXdvcmRBZGQiLCJvblJlbW92ZSIsIm9uS2V5d29yZFJlbW92ZSIsInBsYWNlaG9sZGVyIiwiVmVjdG9yU3RhdGVUb0xhYmVsIiwibWFrZVJhZGlvIiwicyIsIm9uUmFkaW9DaGVja2VkIiwiZmllbGRzZXRSb3dzIiwiY2xhc3NOYW1lIiwiQ2FwdGlvbiIsImlzRXJyb3IiLCJzZWN0aW9uTmFtZSIsIlNldHRpbmdzU3Vic2VjdGlvbkhlYWRpbmciLCJoZWFkaW5nIiwicmVuZGVyVGFyZ2V0cyIsInJvd3MiLCJyZW5kZXIiLCJjbGVhck5vdGlmc0J1dHRvbiIsImdldFJvb21zIiwiZG9lc1Jvb21IYXZlVW5yZWFkTWVzc2FnZXMiLCJvbkNsaWNrIiwib25DbGVhck5vdGlmaWNhdGlvbnNDbGlja2VkIiwiZXhwb3J0cyJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL3NldHRpbmdzL05vdGlmaWNhdGlvbnMudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDE2LTIwMjIgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IFJlYWN0LCB7IFJlYWN0Tm9kZSB9IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IHtcbiAgICBJQW5ub3RhdGVkUHVzaFJ1bGUsXG4gICAgSVB1c2hlcixcbiAgICBQdXNoUnVsZUFjdGlvbixcbiAgICBQdXNoUnVsZUtpbmQsXG4gICAgUnVsZUlkLFxuICAgIElUaHJlZXBpZCxcbiAgICBUaHJlZXBpZE1lZGl1bSxcbiAgICBMb2NhbE5vdGlmaWNhdGlvblNldHRpbmdzLFxufSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbWF0cml4XCI7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbG9nZ2VyXCI7XG5cbmltcG9ydCBTcGlubmVyIGZyb20gXCIuLi9lbGVtZW50cy9TcGlubmVyXCI7XG5pbXBvcnQgeyBNYXRyaXhDbGllbnRQZWcgfSBmcm9tIFwiLi4vLi4vLi4vTWF0cml4Q2xpZW50UGVnXCI7XG5pbXBvcnQge1xuICAgIENvbnRlbnRSdWxlcyxcbiAgICBJQ29udGVudFJ1bGVzLFxuICAgIFB1c2hSdWxlVmVjdG9yU3RhdGUsXG4gICAgVmVjdG9yUHVzaFJ1bGVzRGVmaW5pdGlvbnMsXG4gICAgVmVjdG9yU3RhdGUsXG59IGZyb20gXCIuLi8uLi8uLi9ub3RpZmljYXRpb25zXCI7XG5pbXBvcnQgdHlwZSB7IFZlY3RvclB1c2hSdWxlRGVmaW5pdGlvbiB9IGZyb20gXCIuLi8uLi8uLi9ub3RpZmljYXRpb25zXCI7XG5pbXBvcnQgeyBfdCwgVHJhbnNsYXRlZFN0cmluZyB9IGZyb20gXCIuLi8uLi8uLi9sYW5ndWFnZUhhbmRsZXJcIjtcbmltcG9ydCBMYWJlbGxlZFRvZ2dsZVN3aXRjaCBmcm9tIFwiLi4vZWxlbWVudHMvTGFiZWxsZWRUb2dnbGVTd2l0Y2hcIjtcbmltcG9ydCBTZXR0aW5nc1N0b3JlIGZyb20gXCIuLi8uLi8uLi9zZXR0aW5ncy9TZXR0aW5nc1N0b3JlXCI7XG5pbXBvcnQgU3R5bGVkUmFkaW9CdXR0b24gZnJvbSBcIi4uL2VsZW1lbnRzL1N0eWxlZFJhZGlvQnV0dG9uXCI7XG5pbXBvcnQgeyBTZXR0aW5nTGV2ZWwgfSBmcm9tIFwiLi4vLi4vLi4vc2V0dGluZ3MvU2V0dGluZ0xldmVsXCI7XG5pbXBvcnQgTW9kYWwgZnJvbSBcIi4uLy4uLy4uL01vZGFsXCI7XG5pbXBvcnQgRXJyb3JEaWFsb2cgZnJvbSBcIi4uL2RpYWxvZ3MvRXJyb3JEaWFsb2dcIjtcbmltcG9ydCBTZGtDb25maWcgZnJvbSBcIi4uLy4uLy4uL1Nka0NvbmZpZ1wiO1xuaW1wb3J0IEFjY2Vzc2libGVCdXR0b24gZnJvbSBcIi4uL2VsZW1lbnRzL0FjY2Vzc2libGVCdXR0b25cIjtcbmltcG9ydCBUYWdDb21wb3NlciBmcm9tIFwiLi4vZWxlbWVudHMvVGFnQ29tcG9zZXJcIjtcbmltcG9ydCB7IG9iamVjdENsb25lIH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL29iamVjdHNcIjtcbmltcG9ydCB7IGFycmF5RGlmZiwgZmlsdGVyQm9vbGVhbiB9IGZyb20gXCIuLi8uLi8uLi91dGlscy9hcnJheXNcIjtcbmltcG9ydCB7IGNsZWFyQWxsTm90aWZpY2F0aW9ucywgZ2V0TG9jYWxOb3RpZmljYXRpb25BY2NvdW50RGF0YUV2ZW50VHlwZSB9IGZyb20gXCIuLi8uLi8uLi91dGlscy9ub3RpZmljYXRpb25zXCI7XG5pbXBvcnQge1xuICAgIHVwZGF0ZUV4aXN0aW5nUHVzaFJ1bGVzV2l0aEFjdGlvbnMsXG4gICAgdXBkYXRlUHVzaFJ1bGVBY3Rpb25zLFxufSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvcHVzaFJ1bGVzL3VwZGF0ZVB1c2hSdWxlQWN0aW9uc1wiO1xuaW1wb3J0IHsgQ2FwdGlvbiB9IGZyb20gXCIuLi90eXBvZ3JhcGh5L0NhcHRpb25cIjtcbmltcG9ydCB7IFNldHRpbmdzU3Vic2VjdGlvbkhlYWRpbmcgfSBmcm9tIFwiLi9zaGFyZWQvU2V0dGluZ3NTdWJzZWN0aW9uSGVhZGluZ1wiO1xuaW1wb3J0IFNldHRpbmdzU3Vic2VjdGlvbiBmcm9tIFwiLi9zaGFyZWQvU2V0dGluZ3NTdWJzZWN0aW9uXCI7XG5pbXBvcnQgeyBkb2VzUm9vbUhhdmVVbnJlYWRNZXNzYWdlcyB9IGZyb20gXCIuLi8uLi8uLi9VbnJlYWRcIjtcbmltcG9ydCBTZXR0aW5nc0ZsYWcgZnJvbSBcIi4uL2VsZW1lbnRzL1NldHRpbmdzRmxhZ1wiO1xuXG4vLyBUT0RPOiB0aGlzIFwidmlld1wiIGNvbXBvbmVudCBzdGlsbCBoYXMgZmFyIHRvbyBtdWNoIGFwcGxpY2F0aW9uIGxvZ2ljIGluIGl0LFxuLy8gd2hpY2ggc2hvdWxkIGJlIGZhY3RvcmVkIG91dCB0byBvdGhlciBmaWxlcy5cblxuZW51bSBQaGFzZSB7XG4gICAgTG9hZGluZyA9IFwibG9hZGluZ1wiLFxuICAgIFJlYWR5ID0gXCJyZWFkeVwiLFxuICAgIFBlcnNpc3RpbmcgPSBcInBlcnNpc3RpbmdcIiwgLy8gdGVjaG5pY2FsbHkgYSBtZXRhLXN0YXRlIGZvciBSZWFkeSwgYnV0IHdoYXRldmVyXG4gICAgLy8gdW5yZWNvdmVyYWJsZSBlcnJvciAtIGVnIGNhbid0IGxvYWQgcHVzaCBydWxlc1xuICAgIEVycm9yID0gXCJlcnJvclwiLFxuICAgIC8vIGVycm9yIHNhdmluZyBpbmRpdmlkdWFsIHJ1bGVcbiAgICBTYXZpbmdFcnJvciA9IFwic2F2aW5nRXJyb3JcIixcbn1cblxuZW51bSBSdWxlQ2xhc3Mge1xuICAgIE1hc3RlciA9IFwibWFzdGVyXCIsXG5cbiAgICAvLyBUaGUgdmVjdG9yIHNlY3Rpb25zIG1hcCBhcHByb3hpbWF0ZWx5IHRvIFVJIHNlY3Rpb25zXG4gICAgVmVjdG9yR2xvYmFsID0gXCJ2ZWN0b3JfZ2xvYmFsXCIsXG4gICAgVmVjdG9yTWVudGlvbnMgPSBcInZlY3Rvcl9tZW50aW9uc1wiLFxuICAgIFZlY3Rvck90aGVyID0gXCJ2ZWN0b3Jfb3RoZXJcIixcbiAgICBPdGhlciA9IFwib3RoZXJcIiwgLy8gdW5rbm93biBydWxlcywgZXNzZW50aWFsbHlcbn1cblxuY29uc3QgS0VZV09SRF9SVUxFX0lEID0gXCJfa2V5d29yZHNcIjsgLy8gdXNlZCBhcyBhIHBsYWNlaG9sZGVyIFwiUnVsZSBJRFwiIHRocm91Z2hvdXQgdGhpcyBjb21wb25lbnRcbmNvbnN0IEtFWVdPUkRfUlVMRV9DQVRFR09SWSA9IFJ1bGVDbGFzcy5WZWN0b3JNZW50aW9ucztcblxuLy8gVGhpcyBhcnJheSBkb2Vzbid0IGNhcmUgYWJvdXQgY2F0ZWdvcmllczogaXQncyBqdXN0IHVzZWQgZm9yIGEgc2ltcGxlIHNvcnRcbmNvbnN0IFJVTEVfRElTUExBWV9PUkRFUjogc3RyaW5nW10gPSBbXG4gICAgLy8gR2xvYmFsXG4gICAgUnVsZUlkLkRNLFxuICAgIFJ1bGVJZC5FbmNyeXB0ZWRETSxcbiAgICBSdWxlSWQuTWVzc2FnZSxcbiAgICBSdWxlSWQuRW5jcnlwdGVkTWVzc2FnZSxcblxuICAgIC8vIE1lbnRpb25zXG4gICAgUnVsZUlkLkNvbnRhaW5zRGlzcGxheU5hbWUsXG4gICAgUnVsZUlkLkNvbnRhaW5zVXNlck5hbWUsXG4gICAgUnVsZUlkLkF0Um9vbU5vdGlmaWNhdGlvbixcblxuICAgIC8vIE90aGVyXG4gICAgUnVsZUlkLkludml0ZVRvU2VsZixcbiAgICBSdWxlSWQuSW5jb21pbmdDYWxsLFxuICAgIFJ1bGVJZC5TdXBwcmVzc05vdGljZXMsXG4gICAgUnVsZUlkLlRvbWJzdG9uZSxcbl07XG5cbmludGVyZmFjZSBJVmVjdG9yUHVzaFJ1bGUge1xuICAgIHJ1bGVJZDogUnVsZUlkIHwgdHlwZW9mIEtFWVdPUkRfUlVMRV9JRCB8IHN0cmluZztcbiAgICBydWxlPzogSUFubm90YXRlZFB1c2hSdWxlO1xuICAgIGRlc2NyaXB0aW9uOiBUcmFuc2xhdGVkU3RyaW5nIHwgc3RyaW5nO1xuICAgIHZlY3RvclN0YXRlOiBWZWN0b3JTdGF0ZTtcbiAgICAvLyBsb3VkZXN0IHZlY3RvclN0YXRlIG9mIGEgcnVsZSBhbmQgaXRzIHN5bmNlZCBydWxlc1xuICAgIC8vIHVuZGVmaW5lZCB3aGVuIHJ1bGUgaGFzIG5vIHN5bmNlZCBydWxlc1xuICAgIHN5bmNlZFZlY3RvclN0YXRlPzogVmVjdG9yU3RhdGU7XG59XG5cbmludGVyZmFjZSBJUHJvcHMge31cblxuaW50ZXJmYWNlIElTdGF0ZSB7XG4gICAgcGhhc2U6IFBoYXNlO1xuXG4gICAgLy8gT3B0aW9uYWwgc3R1ZmYgaXMgcmVxdWlyZWQgd2hlbiBgcGhhc2UgPT09IFJlYWR5YFxuICAgIG1hc3RlclB1c2hSdWxlPzogSUFubm90YXRlZFB1c2hSdWxlO1xuICAgIHZlY3RvcktleXdvcmRSdWxlSW5mbz86IElDb250ZW50UnVsZXM7XG4gICAgdmVjdG9yUHVzaFJ1bGVzPzoge1xuICAgICAgICBbY2F0ZWdvcnkgaW4gUnVsZUNsYXNzXT86IElWZWN0b3JQdXNoUnVsZVtdO1xuICAgIH07XG4gICAgcHVzaGVycz86IElQdXNoZXJbXTtcbiAgICB0aHJlZXBpZHM/OiBJVGhyZWVwaWRbXTtcblxuICAgIGRldmljZU5vdGlmaWNhdGlvbnNFbmFibGVkOiBib29sZWFuO1xuICAgIGRlc2t0b3BOb3RpZmljYXRpb25zOiBib29sZWFuO1xuICAgIGRlc2t0b3BTaG93Qm9keTogYm9vbGVhbjtcbiAgICBhdWRpb05vdGlmaWNhdGlvbnM6IGJvb2xlYW47XG5cbiAgICBjbGVhcmluZ05vdGlmaWNhdGlvbnM6IGJvb2xlYW47XG5cbiAgICBydWxlSWRzV2l0aEVycm9yOiBSZWNvcmQ8UnVsZUlkIHwgc3RyaW5nLCBib29sZWFuPjtcbn1cbmNvbnN0IGZpbmRJbkRlZmF1bHRSdWxlcyA9IChcbiAgICBydWxlSWQ6IFJ1bGVJZCB8IHN0cmluZyxcbiAgICBkZWZhdWx0UnVsZXM6IHtcbiAgICAgICAgW2sgaW4gUnVsZUNsYXNzXTogSUFubm90YXRlZFB1c2hSdWxlW107XG4gICAgfSxcbik6IElBbm5vdGF0ZWRQdXNoUnVsZSB8IHVuZGVmaW5lZCA9PiB7XG4gICAgZm9yIChjb25zdCBjYXRlZ29yeSBpbiBkZWZhdWx0UnVsZXMpIHtcbiAgICAgICAgY29uc3QgcnVsZTogSUFubm90YXRlZFB1c2hSdWxlIHwgdW5kZWZpbmVkID0gZGVmYXVsdFJ1bGVzW2NhdGVnb3J5IGFzIFJ1bGVDbGFzc10uZmluZChcbiAgICAgICAgICAgIChydWxlKSA9PiBydWxlLnJ1bGVfaWQgPT09IHJ1bGVJZCxcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKHJ1bGUpIHtcbiAgICAgICAgICAgIHJldHVybiBydWxlO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuLy8gVmVjdG9yIG5vdGlmaWNhdGlvbiBzdGF0ZXMgb3JkZXJlZCBieSBsb3VkbmVzcyBpbiBhc2NlbmRpbmcgb3JkZXJcbmNvbnN0IE9yZGVyZWRWZWN0b3JTdGF0ZXMgPSBbVmVjdG9yU3RhdGUuT2ZmLCBWZWN0b3JTdGF0ZS5PbiwgVmVjdG9yU3RhdGUuTG91ZF07XG5cbi8qKlxuICogRmluZCB0aGUgJ2xvdWRlc3QnIHZlY3RvciBzdGF0ZSBhc3NpZ25lZCB0byBhIHJ1bGVcbiAqIGFuZCBpdCdzIHN5bmNlZCBydWxlc1xuICogSWYgcnVsZXMgaGF2ZSBmYWxsZW4gb3V0IG9mIHN5bmMsXG4gKiB0aGUgbG91ZGVzdCBydWxlIGNhbiBkZXRlcm1pbmUgdGhlIGRpc3BsYXkgdmFsdWVcbiAqIEBwYXJhbSBkZWZhdWx0UnVsZXNcbiAqIEBwYXJhbSBydWxlIC0gcGFyZW50IHJ1bGVcbiAqIEBwYXJhbSBkZWZpbml0aW9uIC0gZGVmaW5pdGlvbiBvZiBwYXJlbnQgcnVsZVxuICogQHJldHVybnMgVmVjdG9yU3RhdGUgLSB0aGUgbWF4aW11bS9sb3VkZXN0IHN0YXRlIGZvciB0aGUgcGFyZW50IGFuZCBzeW5jZWQgcnVsZXNcbiAqL1xuY29uc3QgbWF4aW11bVZlY3RvclN0YXRlID0gKFxuICAgIGRlZmF1bHRSdWxlczoge1xuICAgICAgICBbayBpbiBSdWxlQ2xhc3NdOiBJQW5ub3RhdGVkUHVzaFJ1bGVbXTtcbiAgICB9LFxuICAgIHJ1bGU6IElBbm5vdGF0ZWRQdXNoUnVsZSxcbiAgICBkZWZpbml0aW9uOiBWZWN0b3JQdXNoUnVsZURlZmluaXRpb24sXG4pOiBWZWN0b3JTdGF0ZSB8IHVuZGVmaW5lZCA9PiB7XG4gICAgaWYgKCFkZWZpbml0aW9uLnN5bmNlZFJ1bGVJZHM/Lmxlbmd0aCkge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBjb25zdCB2ZWN0b3JTdGF0ZSA9IGRlZmluaXRpb24uc3luY2VkUnVsZUlkcy5yZWR1Y2U8VmVjdG9yU3RhdGU+KChtYXhWZWN0b3JTdGF0ZSwgcnVsZUlkKSA9PiB7XG4gICAgICAgIC8vIGFscmVhZHkgc2V0IHRvIG1heGltdW1cbiAgICAgICAgaWYgKG1heFZlY3RvclN0YXRlID09PSBWZWN0b3JTdGF0ZS5Mb3VkKSB7XG4gICAgICAgICAgICByZXR1cm4gbWF4VmVjdG9yU3RhdGU7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qgc3luY2VkUnVsZSA9IGZpbmRJbkRlZmF1bHRSdWxlcyhydWxlSWQsIGRlZmF1bHRSdWxlcyk7XG4gICAgICAgIGlmIChzeW5jZWRSdWxlKSB7XG4gICAgICAgICAgICBjb25zdCBzeW5jZWRSdWxlVmVjdG9yU3RhdGUgPSBkZWZpbml0aW9uLnJ1bGVUb1ZlY3RvclN0YXRlKHN5bmNlZFJ1bGUpO1xuICAgICAgICAgICAgLy8gaWYgc3luY2VkUnVsZSBpcyAnbG91ZGVyJyB0aGFuIGN1cnJlbnQgbWF4aW11bVxuICAgICAgICAgICAgLy8gc2V0IG1heGltdW0gdG8gbG91ZGVyIHZlY3RvclN0YXRlXG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgc3luY2VkUnVsZVZlY3RvclN0YXRlICYmXG4gICAgICAgICAgICAgICAgT3JkZXJlZFZlY3RvclN0YXRlcy5pbmRleE9mKHN5bmNlZFJ1bGVWZWN0b3JTdGF0ZSkgPiBPcmRlcmVkVmVjdG9yU3RhdGVzLmluZGV4T2YobWF4VmVjdG9yU3RhdGUpXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc3luY2VkUnVsZVZlY3RvclN0YXRlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBtYXhWZWN0b3JTdGF0ZTtcbiAgICB9LCBkZWZpbml0aW9uLnJ1bGVUb1ZlY3RvclN0YXRlKHJ1bGUpISk7XG5cbiAgICByZXR1cm4gdmVjdG9yU3RhdGU7XG59O1xuXG5jb25zdCBOb3RpZmljYXRpb25BY3Rpdml0eVNldHRpbmdzID0gKCk6IEpTWC5FbGVtZW50ID0+IHtcbiAgICByZXR1cm4gKFxuICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgPFNldHRpbmdzRmxhZyBuYW1lPVwiTm90aWZpY2F0aW9ucy5zaG93Ym9sZFwiIGxldmVsPXtTZXR0aW5nTGV2ZWwuREVWSUNFfSAvPlxuICAgICAgICAgICAgPFNldHRpbmdzRmxhZyBuYW1lPVwiTm90aWZpY2F0aW9ucy50YWNfb25seV9ub3RpZmljYXRpb25zXCIgbGV2ZWw9e1NldHRpbmdMZXZlbC5ERVZJQ0V9IC8+XG4gICAgICAgIDwvZGl2PlxuICAgICk7XG59O1xuXG4vKipcbiAqIFRoZSBvbGQsIGRlcHJlY2F0ZWQgbm90aWZpY2F0aW9ucyB0YWIgdmlldywgb25seSBkaXNwbGF5ZWQgaWYgdGhlIHVzZXIgaGFzIHRoZSBsYWJzIGZsYWcgZGlzYWJsZWQuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE5vdGlmaWNhdGlvbnMgZXh0ZW5kcyBSZWFjdC5QdXJlQ29tcG9uZW50PElQcm9wcywgSVN0YXRlPiB7XG4gICAgcHJpdmF0ZSBzZXR0aW5nV2F0Y2hlcnM6IHN0cmluZ1tdO1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKHByb3BzOiBJUHJvcHMpIHtcbiAgICAgICAgc3VwZXIocHJvcHMpO1xuXG4gICAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgICAgICBwaGFzZTogUGhhc2UuTG9hZGluZyxcbiAgICAgICAgICAgIGRldmljZU5vdGlmaWNhdGlvbnNFbmFibGVkOiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiZGV2aWNlTm90aWZpY2F0aW9uc0VuYWJsZWRcIikgPz8gdHJ1ZSxcbiAgICAgICAgICAgIGRlc2t0b3BOb3RpZmljYXRpb25zOiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwibm90aWZpY2F0aW9uc0VuYWJsZWRcIiksXG4gICAgICAgICAgICBkZXNrdG9wU2hvd0JvZHk6IFNldHRpbmdzU3RvcmUuZ2V0VmFsdWUoXCJub3RpZmljYXRpb25Cb2R5RW5hYmxlZFwiKSxcbiAgICAgICAgICAgIGF1ZGlvTm90aWZpY2F0aW9uczogU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcImF1ZGlvTm90aWZpY2F0aW9uc0VuYWJsZWRcIiksXG4gICAgICAgICAgICBjbGVhcmluZ05vdGlmaWNhdGlvbnM6IGZhbHNlLFxuICAgICAgICAgICAgcnVsZUlkc1dpdGhFcnJvcjoge30sXG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy5zZXR0aW5nV2F0Y2hlcnMgPSBbXG4gICAgICAgICAgICBTZXR0aW5nc1N0b3JlLndhdGNoU2V0dGluZyhcIm5vdGlmaWNhdGlvbnNFbmFibGVkXCIsIG51bGwsICguLi5bLCAsICwgLCB2YWx1ZV0pID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGRlc2t0b3BOb3RpZmljYXRpb25zOiB2YWx1ZSBhcyBib29sZWFuIH0pLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIFNldHRpbmdzU3RvcmUud2F0Y2hTZXR0aW5nKFwiZGV2aWNlTm90aWZpY2F0aW9uc0VuYWJsZWRcIiwgbnVsbCwgKC4uLlssICwgLCAsIHZhbHVlXSkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoeyBkZXZpY2VOb3RpZmljYXRpb25zRW5hYmxlZDogdmFsdWUgYXMgYm9vbGVhbiB9KTtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgU2V0dGluZ3NTdG9yZS53YXRjaFNldHRpbmcoXCJub3RpZmljYXRpb25Cb2R5RW5hYmxlZFwiLCBudWxsLCAoLi4uWywgLCAsICwgdmFsdWVdKSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoeyBkZXNrdG9wU2hvd0JvZHk6IHZhbHVlIGFzIGJvb2xlYW4gfSksXG4gICAgICAgICAgICApLFxuICAgICAgICAgICAgU2V0dGluZ3NTdG9yZS53YXRjaFNldHRpbmcoXCJhdWRpb05vdGlmaWNhdGlvbnNFbmFibGVkXCIsIG51bGwsICguLi5bLCAsICwgLCB2YWx1ZV0pID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGF1ZGlvTm90aWZpY2F0aW9uczogdmFsdWUgYXMgYm9vbGVhbiB9KSxcbiAgICAgICAgICAgICksXG4gICAgICAgIF07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXQgaXNJbmh