Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Fix config override of other settings levels #12593

Merged
merged 19 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
86e1914
Make config override other settings levels and add tests
langleyd Jun 10, 2024
c65c6ef
fix documentation
langleyd Jun 10, 2024
845a2c3
lint
langleyd Jun 10, 2024
c7bda77
Use a const for finalLevel.
langleyd Jun 10, 2024
c63522a
respect the explicit parameter
langleyd Jun 10, 2024
871c0b6
Merge branch 'develop' into langleyd/fix_config_override_setting_value
langleyd Jun 10, 2024
1147afb
Use supportedLevelsAreOrdered for config overrides rather than a sepa…
langleyd Jun 10, 2024
eeb2795
Fix typos
langleyd Jun 11, 2024
53bc93d
Merge branch 'develop' into langleyd/fix_config_override_setting_value
langleyd Jun 11, 2024
c4e8931
Fix mock in UserSetttingsDialog-test
langleyd Jun 11, 2024
0f7cf3c
Merge branch 'langleyd/fix_config_override_setting_value' of https://…
langleyd Jun 11, 2024
ee18a7d
Merge branch 'develop' into langleyd/fix_config_override_setting_value
langleyd Jun 11, 2024
bedf253
Special case disabling of setting tos use config overrides.
langleyd Jun 13, 2024
d90c36c
Merge branch 'langleyd/fix_config_override_setting_value' of https://…
langleyd Jun 13, 2024
6fc476b
Merge branch 'develop' into langleyd/fix_config_override_setting_value
langleyd Jun 13, 2024
d8955de
remove logs
langleyd Jun 14, 2024
49c65cd
Merge branch 'langleyd/fix_config_override_setting_value' of https://…
langleyd Jun 14, 2024
0fa1b98
Merge branch 'develop' into langleyd/fix_config_override_setting_value
langleyd Jun 14, 2024
2350c01
Merge branch 'develop' into langleyd/fix_config_override_setting_value
langleyd Jun 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 27 additions & 29 deletions src/settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,13 @@ export interface IBaseSetting<T extends SettingValueType = SettingValueType> {
isFeature?: false | undefined;

/**
* If true, then the presence of this setting in `config.json` will disable the option in the UI.
* If true, then the presence of this setting in `config.json` will cause the config level to take precedence over settings at other levels and will disable the option in the UI.
*
* In other words, we prevent the user overriding the setting if an explicit value is given in `config.json`.
* XXX: note that users who have already set a non-default value before `config.json` is update will continue
* to use that value (and, indeed, won't be able to change it!): https://github.com/element-hq/element-web/issues/26877
*
* Obviously, this only really makes sense if `supportedLevels` includes {@link SettingLevel.CONFIG}.
*/
configDisablesSetting?: true;
configOverridesSetting?: true;

// Display names are strongly recommended for clarity.
// Display name can also be an object for different levels.
Expand Down Expand Up @@ -268,7 +266,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_msc3531_hide_messages_pending_moderation": {
isFeature: true,
labsGroup: LabGroup.Moderation,
configDisablesSetting: true,
configOverridesSetting: true,
// Requires a reload since this setting is cached in EventUtils
controller: new ReloadOnChangeController(),
displayName: _td("labs|msc3531_hide_messages_pending_moderation"),
Expand All @@ -278,7 +276,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_report_to_moderators": {
isFeature: true,
labsGroup: LabGroup.Moderation,
configDisablesSetting: true,
configOverridesSetting: true,
displayName: _td("labs|report_to_moderators"),
description: _td("labs|report_to_moderators_description"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
Expand All @@ -287,23 +285,23 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_latex_maths": {
isFeature: true,
labsGroup: LabGroup.Messaging,
configDisablesSetting: true,
configOverridesSetting: true,
displayName: _td("labs|latex_maths"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
default: false,
},
"feature_pinning": {
isFeature: true,
labsGroup: LabGroup.Messaging,
configDisablesSetting: true,
configOverridesSetting: true,
displayName: _td("labs|pinning"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
default: false,
},
"feature_wysiwyg_composer": {
isFeature: true,
labsGroup: LabGroup.Messaging,
configDisablesSetting: true,
configOverridesSetting: true,
displayName: _td("labs|wysiwyg_composer"),
description: _td("labs|feature_wysiwyg_composer_description"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
Expand All @@ -312,7 +310,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_mjolnir": {
isFeature: true,
labsGroup: LabGroup.Moderation,
configDisablesSetting: true,
configOverridesSetting: true,
displayName: _td("labs|mjolnir"),
description: _td("labs|currently_experimental"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
Expand All @@ -321,15 +319,15 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_custom_themes": {
isFeature: true,
labsGroup: LabGroup.Themes,
configDisablesSetting: true,
configOverridesSetting: true,
displayName: _td("labs|custom_themes"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
default: false,
},
"feature_dehydration": {
isFeature: true,
labsGroup: LabGroup.Encryption,
configDisablesSetting: true,
configOverridesSetting: true,
displayName: _td("labs|dehydration"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
default: false,
Expand All @@ -350,23 +348,23 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_html_topic": {
isFeature: true,
labsGroup: LabGroup.Rooms,
configDisablesSetting: true,
configOverridesSetting: true,
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("labs|html_topic"),
default: false,
},
"feature_bridge_state": {
isFeature: true,
labsGroup: LabGroup.Rooms,
configDisablesSetting: true,
configOverridesSetting: true,
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("labs|bridge_state"),
default: false,
},
"feature_jump_to_date": {
isFeature: true,
labsGroup: LabGroup.Messaging,
configDisablesSetting: true,
configOverridesSetting: true,
displayName: _td("labs|jump_to_date"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
default: false,
Expand Down Expand Up @@ -398,7 +396,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_sliding_sync": {
isFeature: true,
labsGroup: LabGroup.Developer,
configDisablesSetting: true,
configOverridesSetting: true,
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("labs|sliding_sync"),
description: _td("labs|sliding_sync_description"),
Expand All @@ -414,7 +412,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_element_call_video_rooms": {
isFeature: true,
labsGroup: LabGroup.VoiceAndVideo,
configDisablesSetting: true,
configOverridesSetting: true,
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("labs|element_call_video_rooms"),
controller: new ReloadOnChangeController(),
Expand All @@ -423,7 +421,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_group_calls": {
isFeature: true,
labsGroup: LabGroup.VoiceAndVideo,
configDisablesSetting: true,
configOverridesSetting: true,
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("labs|group_calls"),
controller: new ReloadOnChangeController(),
Expand All @@ -432,15 +430,15 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_disable_call_per_sender_encryption": {
isFeature: true,
labsGroup: LabGroup.VoiceAndVideo,
configDisablesSetting: true,
configOverridesSetting: true,
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("labs|feature_disable_call_per_sender_encryption"),
default: false,
},
"feature_allow_screen_share_only_mode": {
isFeature: true,
labsGroup: LabGroup.VoiceAndVideo,
configDisablesSetting: true,
configOverridesSetting: true,
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
description: _td("labs|under_active_development"),
displayName: _td("labs|allow_screen_share_only_mode"),
Expand All @@ -450,7 +448,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_location_share_live": {
isFeature: true,
labsGroup: LabGroup.Messaging,
configDisablesSetting: true,
configOverridesSetting: true,
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("labs|location_share_live"),
description: _td("labs|location_share_live_description"),
Expand All @@ -460,7 +458,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_dynamic_room_predecessors": {
isFeature: true,
labsGroup: LabGroup.Rooms,
configDisablesSetting: true,
configOverridesSetting: true,
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("labs|dynamic_room_predecessors"),
description: _td("labs|dynamic_room_predecessors_description"),
Expand All @@ -470,7 +468,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
[Features.VoiceBroadcast]: {
isFeature: true,
labsGroup: LabGroup.Messaging,
configDisablesSetting: true,
configOverridesSetting: true,
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("labs|voice_broadcast"),
default: false,
Expand All @@ -483,7 +481,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
[Features.OidcNativeFlow]: {
isFeature: true,
labsGroup: LabGroup.Developer,
configDisablesSetting: true,
configOverridesSetting: true,
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("labs|oidc_native_flow"),
description: _td("labs|oidc_native_flow_description"),
Expand All @@ -493,7 +491,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
// use the rust matrix-sdk-crypto-wasm for crypto.
isFeature: true,
labsGroup: LabGroup.Developer,
// unlike most features, `configDisablesSetting` is false here.
// unlike most features, `configOverridesSetting` is false here.
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("labs|rust_crypto"),
description: () => {
Expand Down Expand Up @@ -527,7 +525,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_render_reaction_images": {
isFeature: true,
labsGroup: LabGroup.Messaging,
configDisablesSetting: true,
configOverridesSetting: true,
displayName: _td("labs|render_reaction_images"),
description: _td("labs|render_reaction_images_description"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
Expand Down Expand Up @@ -609,15 +607,15 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_ask_to_join": {
isFeature: true,
labsGroup: LabGroup.Rooms,
configDisablesSetting: true,
configOverridesSetting: true,
default: false,
displayName: _td("labs|ask_to_join"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
},
"feature_new_room_decoration_ui": {
isFeature: true,
labsGroup: LabGroup.Rooms,
configDisablesSetting: true,
configOverridesSetting: true,
displayName: _td("labs|new_room_decoration_ui"),
description: _td("labs|under_active_development"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
Expand All @@ -627,7 +625,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
"feature_notifications": {
isFeature: true,
labsGroup: LabGroup.Messaging,
configDisablesSetting: true,
configOverridesSetting: true,
displayName: _td("labs|notifications"),
description: _td("labs|unrealiable_e2e"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
Expand Down
51 changes: 41 additions & 10 deletions src/settings/SettingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,13 @@
* Gets a setting's value at a particular level, ignoring all levels that are more specific.
* @param {SettingLevel|"config"|"default"} level The
* level to look at.
*
* This takes into account the value of {@link IBaseSetting#configOverridesSetting} of the `SettingController`.
* If {@link IBaseSetting#configOverridesSetting} is true, and the config level contains a valid value,
* this value will be read from config level rather than level passed.
* However the `explicit` paramter is respected, in that if true the value will only be read from the level specified.
* In this case it is therefore the responsibilty of the calling code to ensure the config level setting is respected.
*
* @param {string} settingName The name of the setting to read.
* @param {String} roomId The room ID to read the setting value in, may be null.
* @param {boolean} explicit If true, this method will not consider other levels, just the one
Expand All @@ -370,6 +377,13 @@
explicit = false,
excludeDefault = false,
): any {
// For some config settings (mostly: non-beta features), a value in config.json overrides the local setting
// (ie: we force them as enabled or disabled). In this case we should read the value from the config.
const finalLevel: SettingLevel =
!explicit && level !== SettingLevel.CONFIG && this.doesConfigOverrideSetting(settingName, roomId)

Check failure on line 383 in src/settings/SettingsStore.ts

View workflow job for this annotation

GitHub Actions / Jest (2)

PreferencesUserSettingsTab › send read receipts › with server support › can be enabled

TypeError: Cannot read properties of undefined (reading 'doesConfigOverrideSetting') at doesConfigOverrideSetting (src/settings/SettingsStore.ts:383:64) at Function.copyOfGetValueAt [as getValueAt] (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:69:24) at new getValueAt (src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx:102:46) at constructClassInstance (node_modules/react-dom/cjs/react-dom.development.js:12716:18) at updateClassComponent (node_modules/react-dom/cjs/react-dom.development.js:17425:5) at beginWork (node_modules/react-dom/cjs/react-dom.development.js:19073:16) at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:3945:14) at HTMLUnknownElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25) at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3) at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9) at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17) at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34) at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:3994:16) at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:4056:31) at beginWork$1 (node_modules/react-dom/cjs/react-dom.development.js:23964:7) at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:22779:12) at workLoopSync (node_modules/react-dom/cjs/react-dom.development.js:22707:5) at renderRootSync (node_modules/react-dom/cjs/react-dom.development.js:22670:7) at performSyncWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:22293:18) at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom.development.js:21881:7) at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:25482:3) at node_modules/react-dom/cjs/react-dom.development.js:26021:7 at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:22431:12) at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:26020:5) at Object.render (node_modules/react-dom/cjs/react-dom.development.js:26103:10) at node_modules/@testing-library/react/dist/pure.js:101:25 at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom.development.js:22380:12) at act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:1042:14) at render (node_modules/@testing-library/react/dist/pure.js:97:26) at renderTab (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:33:22) at renderTab (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:52:33) at Object.getToggle (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:87:32)

Check failure on line 383 in src/settings/SettingsStore.ts

View workflow job for this annotation

GitHub Actions / Jest (2)

PreferencesUserSettingsTab › send read receipts › with server support › can be disabled

TypeError: Cannot read properties of undefined (reading 'doesConfigOverrideSetting') at doesConfigOverrideSetting (src/settings/SettingsStore.ts:383:64) at copyOfGetValueAt (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:69:24) at Function.copyOfGetValueAt [as getValueAt] (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:69:24) at new getValueAt (src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx:102:46) at constructClassInstance (node_modules/react-dom/cjs/react-dom.development.js:12716:18) at updateClassComponent (node_modules/react-dom/cjs/react-dom.development.js:17425:5) at beginWork (node_modules/react-dom/cjs/react-dom.development.js:19073:16) at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:3945:14) at HTMLUnknownElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25) at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3) at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9) at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17) at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34) at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:3994:16) at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:4056:31) at beginWork$1 (node_modules/react-dom/cjs/react-dom.development.js:23964:7) at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:22779:12) at workLoopSync (node_modules/react-dom/cjs/react-dom.development.js:22707:5) at renderRootSync (node_modules/react-dom/cjs/react-dom.development.js:22670:7) at performSyncWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:22293:18) at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom.development.js:21881:7) at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:25482:3) at node_modules/react-dom/cjs/react-dom.development.js:26021:7 at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:22431:12) at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:26020:5) at Object.render (node_modules/react-dom/cjs/react-dom.development.js:26103:10) at node_modules/@testing-library/react/dist/pure.js:101:25 at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom.development.js:22380:12) at act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:1042:14) at render (node_modules/@testing-library/react/dist/pure.js:97:26) at renderTab (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:33:22) at renderTab (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:52:33) at Object.getToggle (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:96:32)

Check failure on line 383 in src/settings/SettingsStore.ts

View workflow job for this annotation

GitHub Actions / Jest (2)

PreferencesUserSettingsTab › send read receipts › without server support › is forcibly enabled

TypeError: Cannot read properties of undefined (reading 'doesConfigOverrideSetting') at doesConfigOverrideSetting (src/settings/SettingsStore.ts:383:64) at copyOfGetValueAt (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:69:24) at Function.copyOfGetValueAt [as getValueAt] (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:69:24) at new getValueAt (src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx:102:46) at constructClassInstance (node_modules/react-dom/cjs/react-dom.development.js:12716:18) at updateClassComponent (node_modules/react-dom/cjs/react-dom.development.js:17425:5) at beginWork (node_modules/react-dom/cjs/react-dom.development.js:19073:16) at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:3945:14) at HTMLUnknownElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25) at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3) at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9) at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17) at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34) at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:3994:16) at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:4056:31) at beginWork$1 (node_modules/react-dom/cjs/react-dom.development.js:23964:7) at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:22779:12) at workLoopSync (node_modules/react-dom/cjs/react-dom.development.js:22707:5) at renderRootSync (node_modules/react-dom/cjs/react-dom.development.js:22670:7) at performSyncWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:22293:18) at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom.development.js:21881:7) at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:25482:3) at node_modules/react-dom/cjs/react-dom.development.js:26021:7 at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:22431:12) at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:26020:5) at Object.render (node_modules/react-dom/cjs/react-dom.development.js:26103:10) at node_modules/@testing-library/react/dist/pure.js:101:25 at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom.development.js:22380:12) at act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:1042:14) at render (node_modules/@testing-library/react/dist/pure.js:97:26) at renderTab (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:33:22) at renderTab (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:52:33) at Object.getToggle (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:110:32)

Check failure on line 383 in src/settings/SettingsStore.ts

View workflow job for this annotation

GitHub Actions / Jest (2)

PreferencesUserSettingsTab › send read receipts › without server support › cannot be disabled

TypeError: Cannot read properties of undefined (reading 'doesConfigOverrideSetting') at doesConfigOverrideSetting (src/settings/SettingsStore.ts:383:64) at copyOfGetValueAt (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:69:24) at copyOfGetValueAt (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:69:24) at Function.copyOfGetValueAt [as getValueAt] (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:69:24) at new getValueAt (src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx:102:46) at constructClassInstance (node_modules/react-dom/cjs/react-dom.development.js:12716:18) at updateClassComponent (node_modules/react-dom/cjs/react-dom.development.js:17425:5) at beginWork (node_modules/react-dom/cjs/react-dom.development.js:19073:16) at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:3945:14) at HTMLUnknownElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25) at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3) at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9) at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17) at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34) at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:3994:16) at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:4056:31) at beginWork$1 (node_modules/react-dom/cjs/react-dom.development.js:23964:7) at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:22779:12) at workLoopSync (node_modules/react-dom/cjs/react-dom.development.js:22707:5) at renderRootSync (node_modules/react-dom/cjs/react-dom.development.js:22670:7) at performSyncWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:22293:18) at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom.development.js:21881:7) at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:25482:3) at node_modules/react-dom/cjs/react-dom.development.js:26021:7 at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:22431:12) at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:26020:5) at Object.render (node_modules/react-dom/cjs/react-dom.development.js:26103:10) at node_modules/@testing-library/react/dist/pure.js:101:25 at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom.development.js:22380:12) at act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:1042:14) at render (node_modules/@testing-library/react/dist/pure.js:97:26) at renderTab (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:33:22) at renderTab (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:52:33) at Object.getToggle (test/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx:119:32)

Check failure on line 383 in src/settings/SettingsStore.ts

View workflow job for this annotation

GitHub Actions / Jest (2)

MatrixClientPeg › .start › Rust staged rollout › Should not migrate existing login if rollout is 0

TypeError: Cannot read properties of undefined (reading 'doesConfigOverrideSetting') at doesConfigOverrideSetting (src/settings/SettingsStore.ts:383:64) at Function.originalGetValueAt (test/MatrixClientPeg-test.ts:306:32) at getValueAt (src/settings/SettingsStore.ts:352:30) at Function.originalGetValue (test/MatrixClientPeg-test.ts:293:32) at MatrixClientPegClass.getValue [as assign] (src/MatrixClientPeg.ts:301:28) at MatrixClientPegClass.start (src/MatrixClientPeg.ts:412:22) at Object.<anonymous> (test/MatrixClientPeg-test.ts:326:17)

Check failure on line 383 in src/settings/SettingsStore.ts

View workflow job for this annotation

GitHub Actions / Jest (2)

MatrixClientPeg › .start › Rust staged rollout › Should migrate existing login if rollout is 100

TypeError: Cannot read properties of undefined (reading 'doesConfigOverrideSetting') at doesConfigOverrideSetting (src/settings/SettingsStore.ts:383:64) at Function.originalGetValueAt (test/MatrixClientPeg-test.ts:306:32) at getValueAt (src/settings/SettingsStore.ts:352:30) at Function.originalGetValue (test/MatrixClientPeg-test.ts:293:32) at MatrixClientPegClass.getValue [as assign] (src/MatrixClientPeg.ts:301:28) at MatrixClientPegClass.start (src/MatrixClientPeg.ts:412:22) at Object.<anonymous> (test/MatrixClientPeg-test.ts:336:17)

Check failure on line 383 in src/settings/SettingsStore.ts

View workflow job for this annotation

GitHub Actions / Jest (2)

MatrixClientPeg › .start › Rust staged rollout › Should migrate existing login if user is in rollout bucket

TypeError: Cannot read properties of undefined (reading 'doesConfigOverrideSetting') at doesConfigOverrideSetting (src/settings/SettingsStore.ts:383:64) at Function.originalGetValueAt (test/MatrixClientPeg-test.ts:306:32) at getValueAt (src/settings/SettingsStore.ts:352:30) at Function.originalGetValue (test/MatrixClientPeg-test.ts:293:32) at MatrixClientPegClass.getValue [as assign] (src/MatrixClientPeg.ts:301:28) at MatrixClientPegClass.start (src/MatrixClientPeg.ts:412:22) at Object.<anonymous> (test/MatrixClientPeg-test.ts:350:17)

Check failure on line 383 in src/settings/SettingsStore.ts

View workflow job for this annotation

GitHub Actions / Jest (2)

MatrixClientPeg › .start › Rust staged rollout › Should not migrate existing login if rollout is malformed

TypeError: Cannot read properties of undefined (reading 'doesConfigOverrideSetting') at doesConfigOverrideSetting (src/settings/SettingsStore.ts:383:64) at Function.originalGetValueAt (test/MatrixClientPeg-test.ts:306:32) at getValueAt (src/settings/SettingsStore.ts:352:30) at Function.originalGetValue (test/MatrixClientPeg-test.ts:293:32) at MatrixClientPegClass.getValue [as assign] (src/MatrixClientPeg.ts:301:28) at MatrixClientPegClass.start (src/MatrixClientPeg.ts:412:22) at Object.<anonymous> (test/MatrixClientPeg-test.ts:363:17)

Check failure on line 383 in src/settings/SettingsStore.ts

View workflow job for this annotation

GitHub Actions / Jest (2)

MatrixClientPeg › .start › Rust staged rollout › Default is to not migrate

TypeError: Cannot read properties of undefined (reading 'doesConfigOverrideSetting') at doesConfigOverrideSetting (src/settings/SettingsStore.ts:383:64) at Function.originalGetValueAt (test/MatrixClientPeg-test.ts:306:32) at getValueAt (src/settings/SettingsStore.ts:352:30) at Function.originalGetValue (test/MatrixClientPeg-test.ts:293:32) at MatrixClientPegClass.getValue [as assign] (src/MatrixClientPeg.ts:301:28) at MatrixClientPegClass.start (src/MatrixClientPeg.ts:412:22) at Object.<anonymous> (test/MatrixClientPeg-test.ts:374:17)

Check failure on line 383 in src/settings/SettingsStore.ts

View workflow job for this annotation

GitHub Actions / Jest (2)

MatrixClientPeg › .start › Rust staged rollout › Should not migrate if feature_rust_crypto is false

TypeError: Cannot read properties of undefined (reading 'doesConfigOverrideSetting') at doesConfigOverrideSetting (src/settings/SettingsStore.ts:383:64) at Function.originalGetValueAt (test/MatrixClientPeg-test.ts:306:32) at getValueAt (src/settings/SettingsStore.ts:352:30) at Function.originalGetValue (test/MatrixClientPeg-test.ts:293:32) at MatrixClientPegClass.getValue [as assign] (src/MatrixClientPeg.ts:301:28) at MatrixClientPegClass.start (src/MatrixClientPeg.ts:412:22) at Object.<anonymous> (test/MatrixClientPeg-test.ts:385:17)

Check failure on line 383 in src/settings/SettingsStore.ts

View workflow job for this annotation

GitHub Actions / Jest (1)

<LabsUserSettingsTab /> › Rust crypto setting › Not enabled in config › can be turned on if not already

TypeError: Cannot read properties of undefined (reading 'doesConfigOverrideSetting') at doesConfigOverrideSetting (src/settings/SettingsStore.ts:383:64) at Function.copyOfGetValueAt [as getValueAt] (test/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx:86:28) at SettingsFlag.getValueAt [as getSettingValue] (src/components/views/elements/SettingsFlag.tsx:65:32) at new getSettingValue (src/components/views/elements/SettingsFlag.tsx:52:25) at constructClassInstance (node_modules/react-dom/cjs/react-dom.development.js:12716:18) at updateClassComponent (node_modules/react-dom/cjs/react-dom.development.js:17425:5) at beginWork (node_modules/react-dom/cjs/react-dom.development.js:19073:16) at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:3945:14) at HTMLUnknownElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25) at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3) at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9) at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17) at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34) at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:3994:16) at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:4056:31) at beginWork$1 (node_modules/react-dom/cjs/react-dom.development.js:23964:7) at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:22779:12) at workLoopSync (node_modules/react-dom/cjs/react-dom.development.js:22707:5) at renderRootSync (node_modules/react-dom/cjs/react-dom.development.js:22670:7) at performSyncWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:22293:18) at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom.development.js:21881:7) at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:25482:3) at node_modules/react-dom/cjs/react-dom.development.js:26021:7 at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:22431:12) at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:26020:5) at Object.render (node_modules/react-dom/cjs/react-dom.development.js:26103:10) at node_modules/@testing-library/react/dist/pure.js:101:25 at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom.development.js:22380:12) at act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:1042:14) at render (node_modules/@testing-library/react/dist/pure.js:97:26) at Object.<anonymous> (test/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx:99:40)

Check failure on line 383 in src/settings/SettingsStore.ts

View workflow job for this annotation

GitHub Actions / Jest (1)

<LabsUserSettingsTab /> › Rust crypto setting › Not enabled in config › cannot be turned off once enabled

TypeError: Cannot read properties of undefined (reading 'doesConfigOverrideSetting') at doesConfigOverrideSetting (src/settings/SettingsStore.ts:383:64) at Function.copyOfGetValueAt [as getValueAt] (test/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx:86:28) at SettingsFlag.getValueAt [as getSettingValue] (src/components/views/elements/SettingsFlag.tsx:65:32) at new getSettingValue (src/components/views/elements/SettingsFlag.tsx:52:25) at constructClassInstance (node_modules/react-dom/cjs/react-dom.development.js:12716:18) at updateClassComponent (node_modules/react-dom/cjs/react-dom.development.js:17425:5) at beginWork (node_modules/react-dom/cjs/react-dom.development.js:19073:16) at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:3945:14) at HTMLUnknownElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25) at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3) at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9) at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17) at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34) at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:3994:16) at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:4056:31) at beginWork$1 (node_modules/react-dom/cjs/react-dom.development.js:23964:7) at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:22779:12) at workLoopSync (node_modules/react-dom/cjs/react-dom.development.js:22707:5) at renderRootSync (node_modules/react-dom/cjs/react-dom.development.js:22670:7) at performSyncWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:22293:18) at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom.development.js:21881:7) at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:25482:3) at node_modules/react-dom/cjs/react-dom.development.js:26021:7 at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:22431:12) at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:26020:5) at Object.render (node_modules/react-dom/cjs/react-dom.development.js:26103:10) at node_modules/@testing-library/react/dist/pure.js:101:25 at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom.development.js:22380:12) at act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:1042:14) at render (node_modules/@testing-library/react/dist/pure.js:97:26) at Object.<anonymous> (test/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx:111:40)
? SettingLevel.CONFIG
: level;

// Verify that the setting is actually a setting
const setting = SETTINGS[settingName];
if (!setting) {
Expand All @@ -379,8 +393,8 @@
const levelOrder = getLevelOrder(setting);
if (!levelOrder.includes(SettingLevel.DEFAULT)) levelOrder.push(SettingLevel.DEFAULT); // always include default

const minIndex = levelOrder.indexOf(level);
if (minIndex === -1) throw new Error(`Level "${level}" for setting "${settingName}" is not prioritized`);
const minIndex = levelOrder.indexOf(finalLevel);
if (minIndex === -1) throw new Error(`Level "${finalLevel}" for setting "${settingName}" is not prioritized`);

const handlers = SettingsStore.getHandlers(settingName);

Expand All @@ -392,12 +406,12 @@
}

if (explicit) {
const handler = handlers[level];
const handler = handlers[finalLevel];
if (!handler) {
return SettingsStore.getFinalValue(setting, level, roomId, null, null);
return SettingsStore.getFinalValue(setting, finalLevel, roomId, null, null);
}
const value = handler.getValue(settingName, roomId);
return SettingsStore.getFinalValue(setting, level, roomId, value, level);
return SettingsStore.getFinalValue(setting, finalLevel, roomId, value, finalLevel);
}

for (let i = minIndex; i < levelOrder.length; i++) {
Expand All @@ -407,10 +421,10 @@

const value = handler.getValue(settingName, roomId);
if (value === null || value === undefined) continue;
return SettingsStore.getFinalValue(setting, level, roomId, value, levelOrder[i]);
return SettingsStore.getFinalValue(setting, finalLevel, roomId, value, levelOrder[i]);
}

return SettingsStore.getFinalValue(setting, level, roomId, null, null);
return SettingsStore.getFinalValue(setting, finalLevel, roomId, null, null);
}

/**
Expand Down Expand Up @@ -505,7 +519,7 @@
* set for a particular room, otherwise it should be supplied.
*
* This takes into account both the value of {@link SettingController#settingDisabled} of the
* `SettingController`, if any; and, for settings where {@link IBaseSetting#configDisablesSetting} is true,
* `SettingController`, if any; and, for settings where {@link IBaseSetting#configOverridesSetting} is true,
* whether the setting has been given a value in `config.json`.
*
* Typically, if the user cannot set the setting, it should be hidden, to declutter the UI;
Expand All @@ -529,8 +543,11 @@
}

// For some config settings (mostly: non-beta features), a value in config.json overrides the local setting
// (ie: we force them as enabled or disabled).
if (SETTINGS[settingName]?.configDisablesSetting) {
// (ie: we force them as enabled or disabled). In this case we such not let the user change the setting.
if (this.doesConfigOverrideSetting(settingName, roomId)) {
return false;
}
if (SETTINGS[settingName]?.configOverridesSetting) {
const configVal = SettingsStore.getValueAt(SettingLevel.CONFIG, settingName, roomId, true, true);
if (configVal === true || configVal === false) return false;
}
Expand All @@ -540,6 +557,20 @@
return handler.canSetValue(settingName, roomId);
}

/**
* Determines if the given setting's config should override other levels
* @param settingName
* @param roomId
* @returns
*/
private static doesConfigOverrideSetting(settingName: string, roomId: string | null): boolean {
if (SETTINGS[settingName]?.configOverridesSetting) {
const configVal = SettingsStore.getValueAt(SettingLevel.CONFIG, settingName, roomId, true, true);
if (configVal === true || configVal === false) return true;
}
return false;
}

/**
* Determines if the given level is supported on this device.
* @param {SettingLevel} level The level
Expand Down
Loading
Loading