matrix-react-sdk
Version:
SDK for matrix.org using React
681 lines (663 loc) • 121 kB
JavaScript
"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