diff --git a/playwright/e2e/left-panel/room-list-panel/room-list.spec.ts b/playwright/e2e/left-panel/room-list-panel/room-list.spec.ts
index 4d09f228d0..5cc78eca69 100644
--- a/playwright/e2e/left-panel/room-list-panel/room-list.spec.ts
+++ b/playwright/e2e/left-panel/room-list-panel/room-list.spec.ts
@@ -428,7 +428,9 @@ test.describe("Room list", () => {
await app.settings.closeDialog();
await app.settings.openUserSettings("Notifications");
- await page.getByText("Show all activity in the room list (dots or number of unread messages)").click();
+ await page
+ .getByRole("switch", { name: "Show all activity in the room list (dots or number of unread messages)" })
+ .check();
await app.settings.closeDialog();
// Switch to the other room to avoid the notification to be cleared
diff --git a/playwright/e2e/room-directory/room-directory.spec.ts b/playwright/e2e/room-directory/room-directory.spec.ts
index 8f90ef4b7e..741fde3505 100644
--- a/playwright/e2e/room-directory/room-directory.spec.ts
+++ b/playwright/e2e/room-directory/room-directory.spec.ts
@@ -38,12 +38,11 @@ test.describe("Room Directory", () => {
// Publish into the public rooms directory
const publishedAddresses = page.locator(".mx_SettingsFieldset", { hasText: "Published Addresses" });
await expect(publishedAddresses.locator("#canonicalAlias")).toHaveValue(`#gaming:${user.homeServer}`);
- const checkbox = publishedAddresses
- .locator(".mx_SettingsFlag", {
- hasText: `Publish this room to the public in ${user.homeServer}'s room directory?`,
- })
- .getByRole("switch");
- await checkbox.check();
+ const checkbox = publishedAddresses.getByRole("switch", {
+ name: `Publish this room to the public in ${user.homeServer}'s room directory?`,
+ });
+ // .click() rather than .check() as checking happens after publish
+ await checkbox.click();
await expect(checkbox).toBeChecked();
await app.closeDialog();
diff --git a/playwright/e2e/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts b/playwright/e2e/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts
index 53f9c37dd0..df41ef4b70 100644
--- a/playwright/e2e/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts
+++ b/playwright/e2e/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts
@@ -50,8 +50,8 @@ test.describe("Appearance user settings tab", () => {
// Click "Show advanced" link button
await tab.getByRole("button", { name: "Show advanced" }).click();
- await tab.getByLabel("Use bundled emoji font").click();
- await tab.getByLabel("Use a system font").click();
+ await tab.getByRole("switch", { name: "Use bundled emoji font" }).click();
+ await tab.getByRole("switch", { name: "Use a system font" }).click();
// Assert that the font-family value was removed
await expect(page.locator("body")).toHaveCSS("font-family", '""');
diff --git a/playwright/e2e/settings/appearance-user-settings-tab/index.ts b/playwright/e2e/settings/appearance-user-settings-tab/index.ts
index e6eccac15a..15f2f47888 100644
--- a/playwright/e2e/settings/appearance-user-settings-tab/index.ts
+++ b/playwright/e2e/settings/appearance-user-settings-tab/index.ts
@@ -84,7 +84,7 @@ class Helpers {
/**
* Return the system theme toggle
*/
- getMatchSystemThemeCheckbox() {
+ getMatchSystemThemeSwitch() {
return this.getThemePanel().getByRole("switch", { name: "Match system theme" });
}
@@ -216,9 +216,9 @@ class Helpers {
}
/**
- * Return the compact layout checkbox
+ * Return the compact layout switch
*/
- getCompactLayoutCheckbox() {
+ getCompactLayoutSwitch() {
return this.getMessageLayoutPanel().getByRole("switch", { name: "Show compact text and messages" });
}
diff --git a/playwright/e2e/settings/appearance-user-settings-tab/message-layout-panel.spec.ts b/playwright/e2e/settings/appearance-user-settings-tab/message-layout-panel.spec.ts
index ce0d614d90..3c05487723 100644
--- a/playwright/e2e/settings/appearance-user-settings-tab/message-layout-panel.spec.ts
+++ b/playwright/e2e/settings/appearance-user-settings-tab/message-layout-panel.spec.ts
@@ -40,9 +40,9 @@ test.describe("Appearance user settings tab", () => {
);
test("should enable compact layout when the modern layout is selected", async ({ page, app, user, util }) => {
- await expect(util.getCompactLayoutCheckbox()).not.toBeChecked();
+ await expect(util.getCompactLayoutSwitch()).not.toBeChecked();
- await util.getCompactLayoutCheckbox().click();
+ await util.getCompactLayoutSwitch().click();
await util.assertCompactLayout();
});
@@ -52,11 +52,11 @@ test.describe("Appearance user settings tab", () => {
user,
util,
}) => {
- await expect(util.getCompactLayoutCheckbox()).not.toBeDisabled();
+ await expect(util.getCompactLayoutSwitch()).not.toBeDisabled();
// Select the bubble layout, which should disable the compact layout checkbox
await util.getBubbleLayout().click();
- await expect(util.getCompactLayoutCheckbox()).toBeDisabled();
+ await expect(util.getCompactLayoutSwitch()).toBeDisabled();
});
});
});
diff --git a/playwright/e2e/settings/appearance-user-settings-tab/theme-choice-panel.spec.ts b/playwright/e2e/settings/appearance-user-settings-tab/theme-choice-panel.spec.ts
index 1fad16948d..7198e1fd82 100644
--- a/playwright/e2e/settings/appearance-user-settings-tab/theme-choice-panel.spec.ts
+++ b/playwright/e2e/settings/appearance-user-settings-tab/theme-choice-panel.spec.ts
@@ -25,7 +25,7 @@ test.describe("Appearance user settings tab", () => {
{ tag: "@screenshot" },
async ({ page, app, util }) => {
// Assert that 'Match system theme' is not checked
- await expect(util.getMatchSystemThemeCheckbox()).not.toBeChecked();
+ await expect(util.getMatchSystemThemeSwitch()).not.toBeChecked();
// Assert that the light theme is selected
await expect(util.getLightTheme()).toBeChecked();
@@ -41,7 +41,7 @@ test.describe("Appearance user settings tab", () => {
"should disable the themes when the system theme is clicked",
{ tag: "@screenshot" },
async ({ page, app, util }) => {
- await util.getMatchSystemThemeCheckbox().click();
+ await util.getMatchSystemThemeSwitch().click();
// Assert that the themes are disabled
await expect(util.getLightTheme()).toBeDisabled();
diff --git a/playwright/e2e/sliding-sync/sliding-sync.spec.ts b/playwright/e2e/sliding-sync/sliding-sync.spec.ts
index e2669e0883..b31deadace 100644
--- a/playwright/e2e/sliding-sync/sliding-sync.spec.ts
+++ b/playwright/e2e/sliding-sync/sliding-sync.spec.ts
@@ -184,11 +184,9 @@ test.describe("Sliding Sync", () => {
test("should update user settings promptly", async ({ page, app }) => {
await app.settings.openUserSettings("Preferences");
- const locator = page.locator(".mx_SettingsFlag").filter({ hasText: "Show timestamps in 12 hour format" });
+ const locator = page.getByRole("switch", { name: "Show timestamps in 12 hour format" });
await expect(locator).toBeVisible();
- await expect(locator.locator(".mx_ToggleSwitch_on")).not.toBeAttached();
- await locator.locator(".mx_ToggleSwitch_ball").click();
- await expect(locator.locator(".mx_ToggleSwitch_on")).toBeAttached();
+ await locator.check();
});
test("should send subscribe_rooms on room switch if room not already subscribed", async ({ page, app }) => {
diff --git a/playwright/snapshots/devtools/devtools.spec.ts/devtools-dialog-linux.png b/playwright/snapshots/devtools/devtools.spec.ts/devtools-dialog-linux.png
index d412500841..7f802aca0e 100644
Binary files a/playwright/snapshots/devtools/devtools.spec.ts/devtools-dialog-linux.png and b/playwright/snapshots/devtools/devtools.spec.ts/devtools-dialog-linux.png differ
diff --git a/playwright/snapshots/devtools/upgraderoom.spec.ts/upgrade-room-linux.png b/playwright/snapshots/devtools/upgraderoom.spec.ts/upgrade-room-linux.png
index 4a27b52da0..e4f9bf4b13 100644
Binary files a/playwright/snapshots/devtools/upgraderoom.spec.ts/upgrade-room-linux.png and b/playwright/snapshots/devtools/upgraderoom.spec.ts/upgrade-room-linux.png differ
diff --git a/playwright/snapshots/invite/decline-and-block-invite-dialog.spec.ts/decline-and-block-invite-empty-linux.png b/playwright/snapshots/invite/decline-and-block-invite-dialog.spec.ts/decline-and-block-invite-empty-linux.png
index 4726c446d3..cb3f9f8618 100644
Binary files a/playwright/snapshots/invite/decline-and-block-invite-dialog.spec.ts/decline-and-block-invite-empty-linux.png and b/playwright/snapshots/invite/decline-and-block-invite-dialog.spec.ts/decline-and-block-invite-empty-linux.png differ
diff --git a/playwright/snapshots/location/location.spec.ts/location-live-share-dialog-linux.png b/playwright/snapshots/location/location.spec.ts/location-live-share-dialog-linux.png
index a2dce30b15..13ba504919 100644
Binary files a/playwright/snapshots/location/location.spec.ts/location-live-share-dialog-linux.png and b/playwright/snapshots/location/location.spec.ts/location-live-share-dialog-linux.png differ
diff --git a/playwright/snapshots/right-panel/right-panel.spec.ts/room-report-dialog-linux.png b/playwright/snapshots/right-panel/right-panel.spec.ts/room-report-dialog-linux.png
index 627071591c..573d63416d 100644
Binary files a/playwright/snapshots/right-panel/right-panel.spec.ts/room-report-dialog-linux.png and b/playwright/snapshots/right-panel/right-panel.spec.ts/room-report-dialog-linux.png differ
diff --git a/playwright/snapshots/room/create-room.spec.ts/create-room-linux.png b/playwright/snapshots/room/create-room.spec.ts/create-room-linux.png
index a16373c8dc..85ad3a4b7b 100644
Binary files a/playwright/snapshots/room/create-room.spec.ts/create-room-linux.png and b/playwright/snapshots/room/create-room.spec.ts/create-room-linux.png differ
diff --git a/playwright/snapshots/room/create-room.spec.ts/create-room-no-public-linux.png b/playwright/snapshots/room/create-room.spec.ts/create-room-no-public-linux.png
index 84494f46bf..ac9f1fbd00 100644
Binary files a/playwright/snapshots/room/create-room.spec.ts/create-room-no-public-linux.png and b/playwright/snapshots/room/create-room.spec.ts/create-room-no-public-linux.png differ
diff --git a/playwright/snapshots/room/create-room.spec.ts/create-video-room-linux.png b/playwright/snapshots/room/create-room.spec.ts/create-video-room-linux.png
index 628ae1159c..31236db103 100644
Binary files a/playwright/snapshots/room/create-room.spec.ts/create-video-room-linux.png and b/playwright/snapshots/room/create-room.spec.ts/create-video-room-linux.png differ
diff --git a/playwright/snapshots/room/invites.spec.ts/Invites-reject-dialog-linux.png b/playwright/snapshots/room/invites.spec.ts/Invites-reject-dialog-linux.png
index 22ef895d1a..ce50be25a2 100644
Binary files a/playwright/snapshots/room/invites.spec.ts/Invites-reject-dialog-linux.png and b/playwright/snapshots/room/invites.spec.ts/Invites-reject-dialog-linux.png differ
diff --git a/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/appearance-tab-linux.png b/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/appearance-tab-linux.png
index 67e047eb50..5a9190aa6b 100644
Binary files a/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/appearance-tab-linux.png and b/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/appearance-tab-linux.png differ
diff --git a/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/window-12px-linux.png b/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/window-12px-linux.png
index 528aaee7c4..c86f95ee29 100644
Binary files a/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/window-12px-linux.png and b/playwright/snapshots/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts/window-12px-linux.png differ
diff --git a/playwright/snapshots/settings/general-room-settings-tab.spec.ts/General-room-settings-tab-should-be-rendered-properly-1-linux.png b/playwright/snapshots/settings/general-room-settings-tab.spec.ts/General-room-settings-tab-should-be-rendered-properly-1-linux.png
index a4f6d3f13d..9671f97e42 100644
Binary files a/playwright/snapshots/settings/general-room-settings-tab.spec.ts/General-room-settings-tab-should-be-rendered-properly-1-linux.png and b/playwright/snapshots/settings/general-room-settings-tab.spec.ts/General-room-settings-tab-should-be-rendered-properly-1-linux.png differ
diff --git a/playwright/snapshots/settings/notifications/notifications-settings-2-tab.spec.ts/standard-notifications-2-settings-linux.png b/playwright/snapshots/settings/notifications/notifications-settings-2-tab.spec.ts/standard-notifications-2-settings-linux.png
index bf9ed51729..5bd96ef009 100644
Binary files a/playwright/snapshots/settings/notifications/notifications-settings-2-tab.spec.ts/standard-notifications-2-settings-linux.png and b/playwright/snapshots/settings/notifications/notifications-settings-2-tab.spec.ts/standard-notifications-2-settings-linux.png differ
diff --git a/playwright/snapshots/settings/notifications/notifications-settings-tab.spec.ts/standard-notification-settings-linux.png b/playwright/snapshots/settings/notifications/notifications-settings-tab.spec.ts/standard-notification-settings-linux.png
index 6182c73b75..9452120bfb 100644
Binary files a/playwright/snapshots/settings/notifications/notifications-settings-tab.spec.ts/standard-notification-settings-linux.png and b/playwright/snapshots/settings/notifications/notifications-settings-tab.spec.ts/standard-notification-settings-linux.png differ
diff --git a/playwright/snapshots/settings/preferences-user-settings-tab.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png b/playwright/snapshots/settings/preferences-user-settings-tab.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png
index b3ecf2c281..ac54127655 100644
Binary files a/playwright/snapshots/settings/preferences-user-settings-tab.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png and b/playwright/snapshots/settings/preferences-user-settings-tab.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png differ
diff --git a/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-linux.png b/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-linux.png
index c04653fc70..c3eef375df 100644
Binary files a/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-linux.png and b/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-linux.png differ
diff --git a/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-world-readable-linux.png b/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-world-readable-linux.png
index 6c192bdb53..d1aa699c18 100644
Binary files a/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-world-readable-linux.png and b/playwright/snapshots/settings/room-settings/room-security-tab.spec.ts/room-security-settings-world-readable-linux.png differ
diff --git a/playwright/snapshots/settings/room-settings/room-video-tab.spec.ts/room-video-settings-linux.png b/playwright/snapshots/settings/room-settings/room-video-tab.spec.ts/room-video-settings-linux.png
index 8f78d02350..664febf8da 100644
Binary files a/playwright/snapshots/settings/room-settings/room-video-tab.spec.ts/room-video-settings-linux.png and b/playwright/snapshots/settings/room-settings/room-video-tab.spec.ts/room-video-settings-linux.png differ
diff --git a/playwright/snapshots/settings/security-user-settings-tab.spec.ts/security-settings-tab-linux.png b/playwright/snapshots/settings/security-user-settings-tab.spec.ts/security-settings-tab-linux.png
index 9280d578f2..5ae88a2b1c 100644
Binary files a/playwright/snapshots/settings/security-user-settings-tab.spec.ts/security-settings-tab-linux.png and b/playwright/snapshots/settings/security-user-settings-tab.spec.ts/security-settings-tab-linux.png differ
diff --git a/playwright/snapshots/spaces/spaces.spec.ts/space-visibility-settings-linux.png b/playwright/snapshots/spaces/spaces.spec.ts/space-visibility-settings-linux.png
index 80f051c2d5..2408c046bd 100644
Binary files a/playwright/snapshots/spaces/spaces.spec.ts/space-visibility-settings-linux.png and b/playwright/snapshots/spaces/spaces.spec.ts/space-visibility-settings-linux.png differ
diff --git a/playwright/snapshots/widgets/permissions-dialog.spec.ts/widget-capabilites-prompt-linux.png b/playwright/snapshots/widgets/permissions-dialog.spec.ts/widget-capabilites-prompt-linux.png
index ec021ebd75..747ffb15ff 100644
Binary files a/playwright/snapshots/widgets/permissions-dialog.spec.ts/widget-capabilites-prompt-linux.png and b/playwright/snapshots/widgets/permissions-dialog.spec.ts/widget-capabilites-prompt-linux.png differ
diff --git a/res/css/components/views/settings/shared/_SettingsSubsection.pcss b/res/css/components/views/settings/shared/_SettingsSubsection.pcss
index 3b22c679c5..690da59d90 100644
--- a/res/css/components/views/settings/shared/_SettingsSubsection.pcss
+++ b/res/css/components/views/settings/shared/_SettingsSubsection.pcss
@@ -39,7 +39,7 @@ Please see LICENSE files in the repository root for full details.
.mx_SettingsSubsection_content {
width: 100%;
display: grid;
- gap: $spacing-8;
+ gap: var(--cpd-space-4x);
/* setting minwidth 0 makes columns definitely sized fixing horizontal overflow */
grid-template-columns: minmax(0, 1fr);
justify-items: flex-start;
diff --git a/res/css/views/dialogs/_CreateRoomDialog.pcss b/res/css/views/dialogs/_CreateRoomDialog.pcss
index a96b9ba472..1dff0896e9 100644
--- a/res/css/views/dialogs/_CreateRoomDialog.pcss
+++ b/res/css/views/dialogs/_CreateRoomDialog.pcss
@@ -57,16 +57,9 @@ Please see LICENSE files in the repository root for full details.
width: 100%;
}
-/* needed to make the alias field only grow as wide as needed */
-/* as opposed to full width */
.mx_CreateRoomDialog_aliasContainer {
+ /* needed to make the alias field only grow as wide as needed as opposed to full width */
display: flex;
- /* put margin on container so it can collapse with siblings */
- margin: 24px 0 10px;
-
- .mx_RoomAliasField {
- margin: 0;
- }
}
.mx_CreateRoomDialog {
@@ -102,6 +95,14 @@ Please see LICENSE files in the repository root for full details.
margin-top: 24px;
}
+ .mx_Field {
+ margin: 0;
+ }
+
+ form {
+ gap: var(--cpd-space-4x);
+ }
+
p {
margin: 0 85px 0 0;
font-size: $font-12px;
diff --git a/res/css/views/dialogs/_DevtoolsDialog.pcss b/res/css/views/dialogs/_DevtoolsDialog.pcss
index 557345ff0e..efcf4db372 100644
--- a/res/css/views/dialogs/_DevtoolsDialog.pcss
+++ b/res/css/views/dialogs/_DevtoolsDialog.pcss
@@ -22,6 +22,10 @@ Please see LICENSE files in the repository root for full details.
margin-bottom: 0;
}
}
+
+ .mx_DevTools_toggleForm {
+ gap: var(--cpd-space-2x);
+ }
}
.mx_DevTools_toolHeading {
diff --git a/res/css/views/settings/_NotificationSettings2.pcss b/res/css/views/settings/_NotificationSettings2.pcss
index 285282c89c..db439f0706 100644
--- a/res/css/views/settings/_NotificationSettings2.pcss
+++ b/res/css/views/settings/_NotificationSettings2.pcss
@@ -6,20 +6,24 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-.mx_NotificationSettings2 {
+.mx_SettingsTab .mx_NotificationSettings2 {
.mx_SettingsSection_subSections {
color: $primary-content;
gap: 32px;
display: flex;
flex-direction: column;
+
+ > form {
+ gap: 32px;
+ display: flex;
+ flex-direction: column;
+ }
}
.mx_SettingsSubsection_description {
margin-bottom: 20px;
.mx_SettingsSubsection_text {
- font-size: 1.2rem;
-
.mx_NotificationBadge {
vertical-align: baseline;
display: inline-flex;
@@ -35,14 +39,6 @@ Please see LICENSE files in the repository root for full details.
justify-content: stretch;
}
- .mx_SettingsBanner {
- margin-bottom: 32px;
- }
-
- .mx_NotificationSettings2_flags {
- gap: 4px;
- }
-
.mx_StyledRadioButton_content {
margin-left: 10px;
margin-right: 10px;
diff --git a/res/css/views/settings/tabs/_SettingsTab.pcss b/res/css/views/settings/tabs/_SettingsTab.pcss
index 99690d5657..92a392950f 100644
--- a/res/css/views/settings/tabs/_SettingsTab.pcss
+++ b/res/css/views/settings/tabs/_SettingsTab.pcss
@@ -77,10 +77,6 @@ Please see LICENSE files in the repository root for full details.
}
}
-.mx_SettingsTab_toggleWithDescription {
- margin-top: $spacing-24;
-}
-
.mx_SettingsTab_sections {
display: grid;
grid-template-columns: 1fr;
diff --git a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.pcss b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.pcss
index dd899389ef..adc55b58f6 100644
--- a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.pcss
+++ b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.pcss
@@ -8,6 +8,6 @@ Please see LICENSE files in the repository root for full details.
.mx_Field.mx_AppearanceUserSettingsTab_checkboxControlledField {
width: 256px;
- /* matches checkbox box + padding to align with checkbox label */
- margin-inline-start: calc($font-16px + 10px);
+ /* Line up with Settings field toggle button */
+ margin-inline-start: 0;
}
diff --git a/res/css/views/settings/tabs/user/_SecurityUserSettingsTab.pcss b/res/css/views/settings/tabs/user/_SecurityUserSettingsTab.pcss
index d3a5f6178f..90a4fdd5b1 100644
--- a/res/css/views/settings/tabs/user/_SecurityUserSettingsTab.pcss
+++ b/res/css/views/settings/tabs/user/_SecurityUserSettingsTab.pcss
@@ -35,3 +35,8 @@ Please see LICENSE files in the repository root for full details.
color: $alert;
}
}
+
+form.mx_SecurityUserSettingsTab_posthogSection {
+ /* Inhibit compound spacing here as it clashes with pre-compound UI */
+ display: contents !important;
+}
diff --git a/src/components/views/dialogs/CreateRoomDialog.tsx b/src/components/views/dialogs/CreateRoomDialog.tsx
index 821182aff0..7bf34aff0a 100644
--- a/src/components/views/dialogs/CreateRoomDialog.tsx
+++ b/src/components/views/dialogs/CreateRoomDialog.tsx
@@ -7,8 +7,16 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React, { type JSX, type ChangeEvent, createRef, type KeyboardEvent, type SyntheticEvent } from "react";
+import React, {
+ type JSX,
+ type ChangeEvent,
+ createRef,
+ type KeyboardEvent,
+ type SyntheticEvent,
+ type ChangeEventHandler,
+} from "react";
import { type Room, RoomType, JoinRule, Preset, Visibility } from "matrix-js-sdk/src/matrix";
+import { Form, SettingsToggleInput } from "@vector-im/compound-web";
import SdkConfig from "../../../SdkConfig";
import withValidation, { type IFieldState, type IValidationResult } from "../elements/Validation";
@@ -17,7 +25,6 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { checkUserIsAllowedToChangeEncryption, type IOpts } from "../../../createRoom";
import Field from "../elements/Field";
import RoomAliasField from "../elements/RoomAliasField";
-import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import DialogButtons from "../elements/DialogButtons";
import BaseDialog from "../dialogs/BaseDialog";
import JoinRuleDropdown from "../elements/JoinRuleDropdown";
@@ -25,7 +32,6 @@ import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { privateShouldBeEncrypted } from "../../../utils/rooms";
import SettingsStore from "../../../settings/SettingsStore";
-import LabelledCheckbox from "../elements/LabelledCheckbox";
import { UIFeature } from "../../../settings/UIFeature";
interface IProps {
@@ -226,8 +232,8 @@ export default class CreateRoomDialog extends React.Component {
this.setState({ joinRule });
};
- private onEncryptedChange = (isEncrypted: boolean): void => {
- this.setState({ isEncrypted });
+ private onEncryptedChange: ChangeEventHandler = (evt): void => {
+ this.setState({ isEncrypted: evt.target.checked });
};
private onAliasChange = (alias: string): void => {
@@ -238,8 +244,8 @@ export default class CreateRoomDialog extends React.Component {
this.setState({ detailsOpen: (ev.target as HTMLDetailsElement).open });
};
- private onNoFederateChange = (noFederate: boolean): void => {
- this.setState({ noFederate });
+ private onNoFederateChange: ChangeEventHandler = (evt): void => {
+ this.setState({ noFederate: evt.target.checked });
};
private onNameValidate = async (fieldState: IFieldState): Promise => {
@@ -248,8 +254,8 @@ export default class CreateRoomDialog extends React.Component {
return result;
};
- private onIsPublicKnockRoomChange = (isPublicKnockRoom: boolean): void => {
- this.setState({ isPublicKnockRoom });
+ private onIsPublicKnockRoomChange: ChangeEventHandler = (evt): void => {
+ this.setState({ isPublicKnockRoom: evt.target.checked });
};
private static validateRoomName = withValidation({
@@ -336,11 +342,12 @@ export default class CreateRoomDialog extends React.Component {
let visibilitySection: JSX.Element | undefined;
if (this.state.joinRule === JoinRule.Knock) {
visibilitySection = (
-
);
}
@@ -360,16 +367,14 @@ export default class CreateRoomDialog extends React.Component {
microcopy = _t("settings|security|e2ee_default_disabled_warning");
}
e2eeSection = (
-
-
- {microcopy}
-
+
);
}
@@ -399,8 +404,8 @@ export default class CreateRoomDialog extends React.Component {
title={title}
screenName="CreateRoom"
>
-
+
);
}
diff --git a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx
index f9729a695e..d0d06d12d5 100644
--- a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx
+++ b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx
@@ -7,12 +7,12 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React from "react";
+import React, { type ChangeEventHandler } from "react";
import { type Widget, type WidgetKind } from "matrix-widget-api";
import { logger } from "matrix-js-sdk/src/logger";
+import { Form, SettingsToggleInput } from "@vector-im/compound-web";
import { _t } from "../../../languageHandler";
-import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import { OIDCState } from "../../../stores/widgets/WidgetPermissionStore";
import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons";
@@ -61,8 +61,8 @@ export default class WidgetOpenIDPermissionsDialog extends React.PureComponent {
- this.setState({ rememberSelection: newVal });
+ private onRememberSelectionChange: ChangeEventHandler = (evt): void => {
+ this.setState({ rememberSelection: evt.target.checked });
};
public render(): React.ReactNode {
@@ -85,12 +85,19 @@ export default class WidgetOpenIDPermissionsDialog extends React.PureComponent
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
+
+
}
/>
diff --git a/src/components/views/dialogs/devtools/RoomState.tsx b/src/components/views/dialogs/devtools/RoomState.tsx
index 1f33fc5eea..b9863b69ff 100644
--- a/src/components/views/dialogs/devtools/RoomState.tsx
+++ b/src/components/views/dialogs/devtools/RoomState.tsx
@@ -7,9 +7,10 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React, { useContext, useEffect, useMemo, useState } from "react";
+import React, { type ChangeEventHandler, useCallback, useContext, useEffect, useMemo, useState } from "react";
import { type IContent, type MatrixEvent } from "matrix-js-sdk/src/matrix";
import classNames from "classnames";
+import { Form, SettingsToggleInput } from "@vector-im/compound-web";
import { _t, _td } from "../../../../languageHandler";
import BaseTool, { DevtoolsContext, type IDevtoolsProps } from "./BaseTool";
@@ -19,7 +20,6 @@ import FilteredList from "./FilteredList";
import Spinner from "../../elements/Spinner";
import SyntaxHighlight from "../../elements/SyntaxHighlight";
import { useAsyncMemo } from "../../../../hooks/useAsyncMemo";
-import LabelledToggleSwitch from "../../elements/LabelledToggleSwitch";
export const StateEventEditor: React.FC = ({ mxEvent, onBack }) => {
const context = useContext(DevtoolsContext);
@@ -116,6 +116,10 @@ const RoomStateExplorerEventType: React.FC = ({ eventType, onBa
const [event, setEvent] = useState(null);
const [history, setHistory] = useState(false);
const [showEmptyState, setShowEmptyState] = useState(true);
+ const onEmptyStateToggled = useCallback>(
+ (e) => setShowEmptyState(e.target.checked),
+ [setShowEmptyState],
+ );
const events = context.room.currentState.events.get(eventType)!;
@@ -157,11 +161,19 @@ const RoomStateExplorerEventType: React.FC = ({ eventType, onBa
setEvent(ev)} />
))}
-
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
+
+
);
};
diff --git a/src/components/views/dialogs/devtools/Users.tsx b/src/components/views/dialogs/devtools/Users.tsx
index 1d98117c99..889d437355 100644
--- a/src/components/views/dialogs/devtools/Users.tsx
+++ b/src/components/views/dialogs/devtools/Users.tsx
@@ -12,11 +12,11 @@
import React, { type JSX, useContext, useState } from "react";
import { type Device, type RoomMember } from "matrix-js-sdk/src/matrix";
import { type CryptoApi } from "matrix-js-sdk/src/crypto-api";
+import { Form, SettingsToggleInput } from "@vector-im/compound-web";
import { _t } from "../../../../languageHandler";
import BaseTool, { DevtoolsContext, type IDevtoolsProps } from "./BaseTool";
import FilteredList from "./FilteredList";
-import LabelledToggleSwitch from "../../elements/LabelledToggleSwitch";
import { useAsyncMemo } from "../../../../hooks/useAsyncMemo";
import CopyableText from "../../elements/CopyableText";
import E2EIcon from "../../rooms/E2EIcon";
@@ -57,11 +57,21 @@ export const UserList: React.FC> = ({ onBack }) =
setMember(member)} />
))}
-
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
+ {
+ setShowOnlyJoined(e.target.checked);
+ }}
+ checked={showOnlyJoined}
+ />
+
);
};
diff --git a/src/components/views/elements/LabelledCheckbox.tsx b/src/components/views/elements/LabelledCheckbox.tsx
index ba07ed9201..45cef43da9 100644
--- a/src/components/views/elements/LabelledCheckbox.tsx
+++ b/src/components/views/elements/LabelledCheckbox.tsx
@@ -24,11 +24,13 @@ interface IProps {
onChange(checked: boolean): void;
// Optional additional CSS class to apply to the label
className?: string;
+ // The id for the checkbox
+ id?: string;
}
-const LabelledCheckbox: React.FC = ({ value, label, byline, disabled, onChange, className }) => {
+const LabelledCheckbox: React.FC = ({ value, label, byline, disabled, onChange, className, id }) => {
return (
-
+
= ({
- label,
- caption,
- value,
- disabled,
- onChange,
- tooltip,
- toggleInFront,
- className,
- "data-testid": testId,
-}) => {
- // This is a minimal version of a SettingsFlag
- const generatedId = useId();
- const id = `mx_LabelledToggleSwitch_${generatedId}`;
- let firstPart = (
-
- {label}
- {caption && {caption} }
-
- );
- let secondPart = (
-
- );
-
- if (toggleInFront) {
- [firstPart, secondPart] = [secondPart, firstPart];
- }
-
- const classes = classNames("mx_SettingsFlag", className, {
- mx_SettingsFlag_toggleInFront: toggleInFront,
- });
- return (
-
- {firstPart}
- {secondPart}
-
- );
-};
-
-export default LabelledToggleSwitch;
diff --git a/src/components/views/elements/SettingsFlag.tsx b/src/components/views/elements/SettingsFlag.tsx
index d7fac91875..eb05301270 100644
--- a/src/components/views/elements/SettingsFlag.tsx
+++ b/src/components/views/elements/SettingsFlag.tsx
@@ -7,13 +7,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React from "react";
+import React, { type ChangeEvent } from "react";
import { secureRandomString } from "matrix-js-sdk/src/randomstring";
+import { SettingsToggleInput } from "@vector-im/compound-web";
+import { logger } from "matrix-js-sdk/src/logger";
import SettingsStore from "../../../settings/SettingsStore";
import { _t } from "../../../languageHandler";
-import ToggleSwitch from "./ToggleSwitch";
-import StyledCheckbox from "./StyledCheckbox";
import { type SettingLevel } from "../../../settings/SettingLevel";
import { type BooleanSettingKey, defaultWatchManager } from "../../../settings/Settings";
@@ -24,8 +24,6 @@ interface IProps {
roomId?: string; // for per-room settings
label?: string;
isExplicit?: boolean;
- // XXX: once design replaces all toggles make this the default
- useCheckbox?: boolean;
hideIfCannotSet?: boolean;
onChange?(checked: boolean): void;
}
@@ -74,14 +72,16 @@ export default class SettingsFlag extends React.Component {
});
};
- private onChange = async (checked: boolean): Promise => {
- await this.save(checked);
- this.setState({ value: checked });
- this.props.onChange?.(checked);
- };
-
- private checkBoxOnChange = (e: React.ChangeEvent): void => {
- this.onChange(e.target.checked);
+ private onChange = async (evt: ChangeEvent): Promise => {
+ const newValue = evt.target.checked;
+ try {
+ await this.save(newValue);
+ } catch (ex) {
+ logger.info(`Failed to save setting ${this.props.name}`, ex);
+ return;
+ }
+ this.setState({ value: newValue });
+ this.props.onChange?.(newValue);
};
private save = async (val?: boolean): Promise => {
@@ -101,45 +101,28 @@ export default class SettingsFlag extends React.Component {
const label = this.props.label ?? SettingsStore.getDisplayName(this.props.name, this.props.level);
const description = SettingsStore.getDescription(this.props.name);
const shouldWarn = SettingsStore.shouldHaveWarning(this.props.name);
-
- if (this.props.useCheckbox) {
- return (
-
- {label}
-
- );
- } else {
- return (
-
-
- {label}
- {description && (
-
- {shouldWarn
- ? _t(
- "settings|warning",
- {},
- {
- w: (sub) => (
- {sub}
- ),
- description,
- },
- )
- : description}
-
- )}
-
-
-
- );
- }
+ const helpMessage = shouldWarn
+ ? _t(
+ "settings|warning",
+ {},
+ {
+ w: (sub) => {sub} ,
+ description,
+ },
+ )
+ : description;
+ const disabledMessage = SettingsStore.disabledMessage(this.props.name);
+ return (
+
+ );
}
}
diff --git a/src/components/views/location/EnableLiveShare.tsx b/src/components/views/location/EnableLiveShare.tsx
index 18fc6025d3..baa42ae6f9 100644
--- a/src/components/views/location/EnableLiveShare.tsx
+++ b/src/components/views/location/EnableLiveShare.tsx
@@ -6,12 +6,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React, { useState } from "react";
+import React, { type ChangeEventHandler, type FormEventHandler, useCallback, useState } from "react";
+import { SettingsToggleInput, Form, Button } from "@vector-im/compound-web";
import { _t } from "../../../languageHandler";
import StyledLiveBeaconIcon from "../beacon/StyledLiveBeaconIcon";
-import AccessibleButton from "../elements/AccessibleButton";
-import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import Heading from "../typography/Heading";
interface Props {
@@ -20,6 +19,23 @@ interface Props {
export const EnableLiveShare: React.FC = ({ onSubmit }) => {
const [isEnabled, setEnabled] = useState(false);
+
+ const onEnabledChanged = useCallback>(
+ (e) => setEnabled(e.target.checked),
+ [setEnabled],
+ );
+
+ const onSubmitForm = useCallback(
+ (evt) => {
+ evt.preventDefault();
+ evt.stopPropagation();
+ if (isEnabled) {
+ onSubmit();
+ }
+ },
+ [isEnabled, onSubmit],
+ );
+
return (
@@ -27,22 +43,17 @@ export const EnableLiveShare: React.FC
= ({ onSubmit }) => {
{_t("location_sharing|live_enable_heading")}
{_t("location_sharing|live_enable_description")}
-
-
- {_t("action|ok")}
-
+
+
+
+ {_t("action|ok")}
+
+
);
};
diff --git a/src/components/views/room_settings/RoomPublishSetting.tsx b/src/components/views/room_settings/RoomPublishSetting.tsx
index 5147945c36..cac8a55e24 100644
--- a/src/components/views/room_settings/RoomPublishSetting.tsx
+++ b/src/components/views/room_settings/RoomPublishSetting.tsx
@@ -6,10 +6,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React from "react";
+import React, { type ChangeEventHandler } from "react";
import { JoinRule, Visibility } from "matrix-js-sdk/src/matrix";
+import { SettingsToggleInput } from "@vector-im/compound-web";
+import { logger } from "matrix-js-sdk/src/logger";
-import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import { _t } from "../../../languageHandler";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import DirectoryCustomisations from "../../../customisations/Directory";
@@ -24,6 +25,7 @@ interface IProps {
interface IState {
isRoomPublished: boolean;
+ busy: boolean;
}
export default class RoomPublishSetting extends React.PureComponent {
@@ -32,6 +34,7 @@ export default class RoomPublishSetting extends React.PureComponent {
- const valueBefore = this.state.isRoomPublished;
- const newValue = !valueBefore;
- this.setState({ isRoomPublished: newValue });
+ private onRoomPublishChange: ChangeEventHandler = async (evt): Promise => {
+ const newValue = evt.target.checked;
+ this.setState({ busy: true });
const client = MatrixClientPeg.safeGet();
- client
- .setRoomDirectoryVisibility(this.props.roomId, newValue ? Visibility.Public : Visibility.Private)
- .catch(() => {
- this.showError();
- // Roll back the local echo on the change
- this.setState({ isRoomPublished: valueBefore });
- });
+ try {
+ await client.setRoomDirectoryVisibility(
+ this.props.roomId,
+ newValue ? Visibility.Public : Visibility.Private,
+ );
+ this.setState({ isRoomPublished: newValue });
+ } catch (ex) {
+ logger.error("Error while setting room directory visibility", ex);
+ this.showError();
+ } finally {
+ this.setState({ busy: false });
+ }
};
public componentDidMount(): void {
@@ -69,17 +76,26 @@ export default class RoomPublishSetting extends React.PureComponent {
return (
-
+
{
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
-
+
);
};
@@ -213,9 +215,6 @@ export default class Notifications extends React.PureComponent
- this.setState({ desktopNotifications: value as boolean }),
- ),
SettingsStore.watchSetting("deviceNotificationsEnabled", null, (...[, , , , value]) => {
this.setState({ deviceNotificationsEnabled: value as boolean });
}),
- SettingsStore.watchSetting("notificationBodyEnabled", null, (...[, , , , value]) =>
- this.setState({ desktopShowBody: value as boolean }),
- ),
- SettingsStore.watchSetting("audioNotificationsEnabled", null, (...[, , , , value]) =>
- this.setState({ audioNotifications: value as boolean }),
- ),
];
// noinspection JSIgnoredPromiseFromCall
@@ -286,7 +276,7 @@ export default class Notifications extends React.PureComponent => {
+ private onMasterRuleChanged: ChangeEventHandler = async (evt): Promise => {
+ const { checked } = evt.target;
this.setState({ phase: Phase.Persisting });
const masterRule = this.state.masterPushRule!;
@@ -431,11 +422,8 @@ export default class Notifications extends React.PureComponent => {
- await SettingsStore.setValue("deviceNotificationsEnabled", null, SettingLevel.DEVICE, checked);
- };
-
- private onEmailNotificationsChanged = async (email: string, checked: boolean): Promise => {
+ private onEmailNotificationsChanged = async (email: string, evt: ChangeEvent): Promise => {
+ const { checked } = evt.target;
this.setState({ phase: Phase.Persisting });
try {
@@ -470,18 +458,6 @@ export default class Notifications extends React.PureComponent => {
- await SettingsStore.setValue("notificationsEnabled", null, SettingLevel.DEVICE, checked);
- };
-
- private onDesktopShowBodyChanged = async (checked: boolean): Promise => {
- await SettingsStore.setValue("notificationBodyEnabled", null, SettingLevel.DEVICE, checked);
- };
-
- private onAudioNotificationsChanged = async (checked: boolean): Promise => {
- await SettingsStore.setValue("audioNotificationsEnabled", null, SettingLevel.DEVICE, checked);
- };
-
private onRadioChecked = async (rule: IVectorPushRule, checkedState: VectorState): Promise => {
this.setState(({ ruleIdsWithError }) => ({
phase: Phase.Persisting,
@@ -663,11 +639,11 @@ export default class Notifications extends React.PureComponent
@@ -681,10 +657,10 @@ export default class Notifications extends React.PureComponent t.medium === ThreepidMedium.Email)
.map((e) => (
- p.kind === "email" && p.pushkey === e.address)}
+ checked={!!this.state.pushers?.some((p) => p.kind === "email" && p.pushkey === e.address)}
label={_t("settings|notifications|enable_email_notifications", { email: e.address })}
onChange={this.onEmailNotificationsChanged.bind(this, e.address)}
disabled={this.state.phase === Phase.Persisting}
@@ -695,37 +671,13 @@ export default class Notifications extends React.PureComponent
{masterSwitch}
- this.updateDeviceNotifications(checked)}
- disabled={this.state.phase === Phase.Persisting}
- />
+
{this.state.deviceNotificationsEnabled && (
<>
-
-
-
+
+
+
>
)}
diff --git a/src/components/views/settings/SetIntegrationManager.tsx b/src/components/views/settings/SetIntegrationManager.tsx
index 98066bc0a4..44507067ad 100644
--- a/src/components/views/settings/SetIntegrationManager.tsx
+++ b/src/components/views/settings/SetIntegrationManager.tsx
@@ -9,7 +9,7 @@ Please see LICENSE files in the repository root for full details.
import React from "react";
import { logger } from "matrix-js-sdk/src/logger";
import { type EmptyObject } from "matrix-js-sdk/src/matrix";
-import { Root, InlineField, Label, ToggleInput } from "@vector-im/compound-web";
+import { Form, SettingsToggleInput } from "@vector-im/compound-web";
import { _t } from "../../../languageHandler";
import { IntegrationManagers } from "../../../integrations/IntegrationManagers";
@@ -66,33 +66,31 @@ export default class SetIntegrationManager extends React.Component
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ className="mx_SetIntegrationManager"
+ data-testid="mx_SetIntegrationManager"
+ >
{_t("integration_manager|manage_title")}
- {managerName}
+
+ {managerName}
+
- {bodyText}
+ {bodyText}
{_t("integration_manager|explainer")}
-
-
- }
- >
-
- {_t("integration_manager|toggle_label")}
-
-
-
-
+
+
);
}
}
diff --git a/src/components/views/settings/notifications/NotificationPusherSettings.tsx b/src/components/views/settings/notifications/NotificationPusherSettings.tsx
index a0560dc9ca..f7b21efbd6 100644
--- a/src/components/views/settings/notifications/NotificationPusherSettings.tsx
+++ b/src/components/views/settings/notifications/NotificationPusherSettings.tsx
@@ -86,6 +86,7 @@ export function NotificationPusherSettings(): JSX.Element {
{_t("settings|notifications|email_description")}
@@ -109,7 +110,7 @@ export function NotificationPusherSettings(): JSX.Element {
{notificationTargets.length > 0 && (
-
+
{pushers
.filter((it) => it.kind !== "email")
diff --git a/src/components/views/settings/notifications/NotificationSettings2.tsx b/src/components/views/settings/notifications/NotificationSettings2.tsx
index ae5aa46d31..c316d46129 100644
--- a/src/components/views/settings/notifications/NotificationSettings2.tsx
+++ b/src/components/views/settings/notifications/NotificationSettings2.tsx
@@ -7,11 +7,11 @@ Please see LICENSE files in the repository root for full details.
*/
import React, { type JSX, useState } from "react";
+import { SettingsToggleInput } from "@vector-im/compound-web";
import NewAndImprovedIcon from "../../../../../res/img/element-icons/new-and-improved.svg";
import { useMatrixClientContext } from "../../../../contexts/MatrixClientContext";
import { useNotificationSettings } from "../../../../hooks/useNotificationSettings";
-import { useSettingValue } from "../../../../hooks/useSettings";
import { _t } from "../../../../languageHandler";
import {
DefaultNotificationSettings,
@@ -19,13 +19,11 @@ import {
} from "../../../../models/notificationsettings/NotificationSettings";
import { RoomNotifState } from "../../../../RoomNotifs";
import { SettingLevel } from "../../../../settings/SettingLevel";
-import SettingsStore from "../../../../settings/SettingsStore";
import { NotificationLevel } from "../../../../stores/notifications/NotificationLevel";
import { clearAllNotifications } from "../../../../utils/notifications";
import AccessibleButton from "../../elements/AccessibleButton";
import ExternalLink from "../../elements/ExternalLink";
import LabelledCheckbox from "../../elements/LabelledCheckbox";
-import LabelledToggleSwitch from "../../elements/LabelledToggleSwitch";
import StyledRadioGroup from "../../elements/StyledRadioGroup";
import TagComposer from "../../elements/TagComposer";
import { StatelessNotificationBadge } from "../../rooms/NotificationBadge/StatelessNotificationBadge";
@@ -71,10 +69,6 @@ function useHasUnreadNotifications(): boolean {
export default function NotificationSettings2(): JSX.Element {
const cli = useMatrixClientContext();
- const desktopNotifications = useSettingValue("notificationsEnabled");
- const desktopShowBody = useSettingValue("notificationBodyEnabled");
- const audioNotifications = useSettingValue("audioNotificationsEnabled");
-
const { model, hasPendingChanges, reconcile } = useNotificationSettings(cli);
const disabled = model === null || hasPendingChanges;
@@ -118,38 +112,25 @@ export default function NotificationSettings2(): JSX.Element {
)}
- {
+ onChange={(evt) => {
reconcile({
...model!,
- globalMute: !value,
+ globalMute: !evt.target.checked,
});
}}
/>
-
- SettingsStore.setValue("notificationsEnabled", null, SettingLevel.DEVICE, value)
- }
- />
-
+
- SettingsStore.setValue("notificationBodyEnabled", null, SettingLevel.DEVICE, value)
- }
- />
-
- SettingsStore.setValue("audioNotificationsEnabled", null, SettingLevel.DEVICE, value)
- }
+ level={SettingLevel.DEVICE}
/>
+
{
diff --git a/src/components/views/settings/shared/SettingsSubsection.tsx b/src/components/views/settings/shared/SettingsSubsection.tsx
index 6f7fdde1f0..ac4872f598 100644
--- a/src/components/views/settings/shared/SettingsSubsection.tsx
+++ b/src/components/views/settings/shared/SettingsSubsection.tsx
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import classNames from "classnames";
import React, { type HTMLAttributes } from "react";
-import { Separator } from "@vector-im/compound-web";
+import { Form, Separator } from "@vector-im/compound-web";
import { SettingsSubsectionHeading } from "./SettingsSubsectionHeading";
@@ -23,6 +23,11 @@ export interface SettingsSubsectionProps extends HTMLAttributes
* @default true
*/
legacy?: boolean;
+
+ /**
+ * Wrap in a Form Root component, for compatibility with compound components.
+ */
+ formWrap?: boolean;
}
export const SettingsSubsectionText: React.FC> = ({ children, ...rest }) => (
@@ -37,31 +42,48 @@ export const SettingsSubsection: React.FC = ({
children,
stretchContent,
legacy = true,
+ formWrap,
...rest
-}) => (
-
- {typeof heading === "string" ?
: <>{heading}>}
- {!!description && (
-
- {description}
-
- )}
- {!!children && (
-
{
+ const content = (
+
+ {typeof heading === "string" ?
: <>{heading}>}
+ {!!description && (
+
+ {description}
+
+ )}
+ {!!children && (
+
+ {children}
+
+ )}
+ {!legacy &&
}
+
+ );
+
+ if (formWrap) {
+ return (
+
{
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
>
- {children}
-
- )}
- {!legacy &&
}
-
-);
+ {content}
+
+ );
+ }
+ return content;
+};
diff --git a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx
index b50eb22a7c..4b04e4bcf3 100644
--- a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx
+++ b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx
@@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details.
import React, { type ContextType } from "react";
import { type Room } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types";
+import { Form } from "@vector-im/compound-web";
import { _t } from "../../../../../languageHandler";
import RoomProfileSettings from "../../../room_settings/RoomProfileSettings";
@@ -78,26 +79,33 @@ export default class GeneralRoomSettingsTab extends React.Component
-
-
-
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
+
+
+
-
-
-
+
+
+
-
- {urlPreviewSettings}
-
-
-
- {leaveSection}
-
+
+ {urlPreviewSettings}
+
+
+
+ {leaveSection}
+
+
);
}
diff --git a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx
index 37faaea5d8..ed72b6963c 100644
--- a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx
+++ b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React, { type JSX, type ReactNode } from "react";
+import React, { type ChangeEventHandler, type JSX, type ReactNode } from "react";
import {
GuestAccess,
HistoryVisibility,
@@ -17,11 +17,10 @@ import {
EventType,
} from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
-import { InlineSpinner } from "@vector-im/compound-web";
+import { Form, InlineSpinner, SettingsToggleInput } from "@vector-im/compound-web";
import { Icon as WarningIcon } from "../../../../../../res/img/warning.svg";
import { _t } from "../../../../../languageHandler";
-import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
import Modal from "../../../../../Modal";
import QuestionDialog from "../../../dialogs/QuestionDialog";
import StyledRadioGroup from "../../../elements/StyledRadioGroup";
@@ -184,7 +183,8 @@ export default class SecurityRoomSettingsTab extends React.Component {
+ private onGuestAccessChange: ChangeEventHandler = (evt): void => {
+ const allowed = evt.target.checked;
const guestAccess = allowed ? GuestAccess.CanJoin : GuestAccess.Forbidden;
const beforeGuestAccess = this.state.guestAccess;
if (beforeGuestAccess === guestAccess) return;
@@ -464,13 +464,14 @@ export default class SecurityRoomSettingsTab extends React.Component
-
- {_t("room_settings|security|guest_access_warning")}
);
}
@@ -503,35 +504,43 @@ export default class SecurityRoomSettingsTab extends React.Component
-
-
- {isEncryptionLoading ? (
-
- ) : (
- <>
-
- {isEncryptionForceDisabled && !isEncrypted && (
- {_t("room_settings|security|encryption_forced")}
- )}
- {encryptionSettings}
- >
- )}
-
- {this.renderJoinRule()}
- {historySection}
-
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
+
+
+ {isEncryptionLoading ? (
+
+ ) : (
+ <>
+
+ {isEncryptionForceDisabled && !isEncrypted && (
+ {_t("room_settings|security|encryption_forced")}
+ )}
+ {encryptionSettings}
+ >
+ )}
+
+ {this.renderJoinRule()}
+ {historySection}
+
+
);
}
diff --git a/src/components/views/settings/tabs/room/VoipRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/VoipRoomSettingsTab.tsx
index 177d495366..6c28105060 100644
--- a/src/components/views/settings/tabs/room/VoipRoomSettingsTab.tsx
+++ b/src/components/views/settings/tabs/room/VoipRoomSettingsTab.tsx
@@ -6,12 +6,12 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React, { useCallback, useMemo, useState } from "react";
+import React, { type ChangeEventHandler, useCallback, useMemo, useState } from "react";
import { JoinRule, EventType, type RoomState, type Room } from "matrix-js-sdk/src/matrix";
import { type RoomPowerLevelsEventContent } from "matrix-js-sdk/src/types";
+import { Form, SettingsToggleInput } from "@vector-im/compound-web";
import { _t } from "../../../../../languageHandler";
-import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
import { SettingsSubsection } from "../../shared/SettingsSubsection";
import SettingsTab from "../SettingsTab";
import { useRoomState } from "../../../../../hooks/useRoomState";
@@ -45,8 +45,9 @@ const ElementCallSwitch: React.FC = ({ room }) => {
return content.events?.[ElementCallMemberEventType.name] === 0;
});
- const onChange = useCallback(
- (enabled: boolean): void => {
+ const onChange = useCallback>(
+ (evt): void => {
+ const enabled = evt.target.checked;
setElementCallEnabled(enabled);
// Take a copy to avoid mutating the original
@@ -73,16 +74,17 @@ const ElementCallSwitch: React.FC = ({ room }) => {
const brand = SdkConfig.get("element_call").brand ?? DEFAULTS.element_call.brand;
return (
-
);
};
@@ -95,9 +97,16 @@ export const VoipRoomSettingsTab: React.FC = ({ room }) => {
return (
-
-
-
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
+
+
+
+
);
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
index 7d46cf72da..4a8cecc204 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
@@ -9,9 +9,9 @@ Please see LICENSE files in the repository root for full details.
import React, { type ChangeEvent, type ReactNode } from "react";
import { type EmptyObject } from "matrix-js-sdk/src/matrix";
+import { Form } from "@vector-im/compound-web";
import { _t } from "../../../../../languageHandler";
-import SdkConfig from "../../../../../SdkConfig";
import SettingsStore from "../../../../../settings/SettingsStore";
import SettingsFlag from "../../../elements/SettingsFlag";
import Field from "../../../elements/Field";
@@ -48,7 +48,6 @@ export default class AppearanceUserSettingsTab extends React.Component
-
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
+
this.setState({ useBundledEmojiFont: checked })}
/>
this.setState({ useSystemFont: checked })}
/>
- >
+
);
}
return (
diff --git a/src/components/views/settings/tabs/user/InviteRulesAccountSettings.tsx b/src/components/views/settings/tabs/user/InviteRulesAccountSettings.tsx
index 7c66e88046..715da57346 100644
--- a/src/components/views/settings/tabs/user/InviteRulesAccountSettings.tsx
+++ b/src/components/views/settings/tabs/user/InviteRulesAccountSettings.tsx
@@ -5,15 +5,14 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React, { type FC, useCallback, useState } from "react";
-import { Root } from "@vector-im/compound-web";
+import React, { type ChangeEvent, type FC, useCallback, useState } from "react";
+import { Form, SettingsToggleInput } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger";
import { _t } from "../../../../../languageHandler";
import { useSettingValue } from "../../../../../hooks/useSettings";
import SettingsStore from "../../../../../settings/SettingsStore";
import { SettingLevel } from "../../../../../settings/SettingLevel";
-import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
/**
* A settings component which allows the user to enable/disable invite blocking.
@@ -31,10 +30,10 @@ export const InviteRulesAccountSetting: FC = () => {
const [busy, setBusy] = useState(false);
const onChange = useCallback(
- async (allowInvites: boolean) => {
+ async (e: ChangeEvent) => {
try {
setBusy(true);
- if (allowInvites) {
+ if (e.target.checked) {
// When allowing invites, clear the block setting on both bits of account data.
await SettingsStore.setValue("blockInvites", null, SettingLevel.ACCOUNT, false);
await SettingsStore.setValue("inviteRules", null, SettingLevel.ACCOUNT, { allBlocked: false });
@@ -58,15 +57,22 @@ export const InviteRulesAccountSetting: FC = () => {
const disabledMessage = msc4155Disabled && msc4380Disabled;
const invitesBlocked = (!msc4155Disabled && msc4155Rules.allBlocked) || (!msc4380Disabled && msc4380BlockInvites);
return (
-
- {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
+
-
+
);
};
diff --git a/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx b/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx
index 622343b287..85d41cbf0d 100644
--- a/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx
@@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details.
import React, { type JSX } from "react";
import { sortBy } from "lodash";
import { type EmptyObject } from "matrix-js-sdk/src/matrix";
+import { Form } from "@vector-im/compound-web";
import { _t } from "../../../../../languageHandler";
import SettingsStore from "../../../../../settings/SettingsStore";
@@ -106,37 +107,44 @@ export default class LabsUserSettingsTab extends React.Component {
return (
-
-
- {_t("labs|beta_description", { brand: SdkConfig.get("brand") })}
-
- {betaSection}
-
-
- {labsSections && (
-
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
+
- {_t(
- "labs|experimental_description",
- {},
- {
- a: (sub) => {
- return (
-
- {sub}
-
- );
- },
- },
- )}
+ {_t("labs|beta_description", { brand: SdkConfig.get("brand") })}
- {labsSections}
+ {betaSection}
- )}
+
+ {labsSections && (
+
+
+ {_t(
+ "labs|experimental_description",
+ {},
+ {
+ a: (sub) => {
+ return (
+
+ {sub}
+
+ );
+ },
+ },
+ )}
+
+ {labsSections}
+
+ )}
+
);
}
diff --git a/src/components/views/settings/tabs/user/MediaPreviewAccountSettings.tsx b/src/components/views/settings/tabs/user/MediaPreviewAccountSettings.tsx
index f6a2b7cf38..1194f2fd02 100644
--- a/src/components/views/settings/tabs/user/MediaPreviewAccountSettings.tsx
+++ b/src/components/views/settings/tabs/user/MediaPreviewAccountSettings.tsx
@@ -6,9 +6,8 @@ Please see LICENSE files in the repository root for full details.
*/
import React, { type ChangeEventHandler, useCallback } from "react";
-import { Field, HelpMessage, InlineField, Label, RadioInput, Root } from "@vector-im/compound-web";
+import { Field, HelpMessage, InlineField, Label, RadioInput, Root, SettingsToggleInput } from "@vector-im/compound-web";
-import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
import { type MediaPreviewConfig, MediaPreviewValue } from "../../../../../@types/media_preview";
import { _t } from "../../../../../languageHandler";
import { useSettingValue } from "../../../../../hooks/useSettings";
@@ -30,12 +29,12 @@ export const MediaPreviewAccountSettings: React.FC<{ roomId?: string }> = ({ roo
[roomId],
);
- const avatarOnChange = useCallback(
- (c: boolean) => {
+ const avatarOnChange = useCallback>(
+ (evt) => {
changeSetting({
...currentMediaPreview,
// Switch is inverted. "Hide avatars..."
- invite_avatars: c ? MediaPreviewValue.Off : MediaPreviewValue.On,
+ invite_avatars: evt.target.checked ? MediaPreviewValue.Off : MediaPreviewValue.On,
});
},
[changeSetting, currentMediaPreview],
@@ -83,10 +82,10 @@ export const MediaPreviewAccountSettings: React.FC<{ roomId?: string }> = ({ roo
return (
{!roomId && (
-
)}
diff --git a/src/components/views/settings/tabs/user/NotificationUserSettingsTab.tsx b/src/components/views/settings/tabs/user/NotificationUserSettingsTab.tsx
index b63e790736..6d6c25e122 100644
--- a/src/components/views/settings/tabs/user/NotificationUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/NotificationUserSettingsTab.tsx
@@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/
import React from "react";
+import { Form } from "@vector-im/compound-web";
import { Features } from "../../../../../settings/Settings";
import SettingsStore from "../../../../../settings/SettingsStore";
@@ -21,13 +22,20 @@ export default class NotificationUserSettingsTab extends React.Component {
return (
- {newNotificationSettingsEnabled ? (
-
- ) : (
-
-
-
- )}
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
+ {newNotificationSettingsEnabled ? (
+
+ ) : (
+
+
+
+ )}
+
);
}
diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx
index d373aee60e..cab58ee085 100644
--- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx
@@ -7,7 +7,8 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React, { type JSX, type ReactElement, useCallback, useEffect, useState } from "react";
+import React, { type ChangeEvent, type JSX, type ReactElement, useCallback, useEffect, useState } from "react";
+import { SettingsToggleInput } from "@vector-im/compound-web";
import { type NonEmptyArray } from "../../../../../@types/common";
import { _t, getCurrentLanguage } from "../../../../../languageHandler";
@@ -29,7 +30,6 @@ import LanguageDropdown from "../../../elements/LanguageDropdown";
import PlatformPeg from "../../../../../PlatformPeg";
import { IS_MAC } from "../../../../../Keyboard";
import SpellCheckSettings from "../../SpellCheckSettings";
-import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
import * as TimezoneHandler from "../../../../../TimezoneHandler";
import { type BooleanSettingKey } from "../../../../../settings/Settings.tsx";
import { MediaPreviewAccountSettings } from "./MediaPreviewAccountSettings.tsx";
@@ -92,7 +92,8 @@ const SpellCheckSection: React.FC = () => {
})();
}, []);
- const onSpellCheckEnabledChange = useCallback((enabled: boolean) => {
+ const onSpellCheckEnabledChange = useCallback((e: ChangeEvent) => {
+ const enabled = e.target.checked;
setSpellCheckEnabled(enabled);
PlatformPeg.get()?.setSpellCheckEnabled(enabled);
}, []);
@@ -106,10 +107,11 @@ const SpellCheckSection: React.FC = () => {
return (
<>
-
{spellCheckEnabled && spellCheckLanguages !== undefined && !IS_MAC && (
@@ -261,13 +263,16 @@ export default class PreferencesUserSettingsTab extends React.Component
{/* The heading string is still 'general' from where it was moved, but this section should become 'general' */}
-
+
{SettingsStore.canSetValue("Electron.autoLaunch", null, SettingLevel.PLATFORM) && (
-
+
)}
-
+
{!newRoomListEnabled && this.renderGroup(PreferencesUserSettingsTab.ROOM_LIST_SETTINGS)}
{/* The settings is on device level where the other room list settings are on account level */}
{newRoomListEnabled && (
@@ -285,7 +290,7 @@ export default class PreferencesUserSettingsTab extends React.Component
-
+
{this.renderGroup(PreferencesUserSettingsTab.SPACES_SETTINGS, SettingLevel.ACCOUNT)}
@@ -302,11 +307,12 @@ export default class PreferencesUserSettingsTab extends React.Component
{this.renderGroup(PreferencesUserSettingsTab.KEYBINDINGS_SETTINGS)}
-
+
{_t("settings|preferences|user_timezone")}
{this.renderGroup(PreferencesUserSettingsTab.PRESENCE_SETTINGS)}
-
+
{this.renderGroup(PreferencesUserSettingsTab.COMPOSER_SETTINGS)}
-
+
{this.renderGroup(PreferencesUserSettingsTab.CODE_BLOCKS_SETTINGS)}
-
+
{this.renderGroup(PreferencesUserSettingsTab.IMAGES_AND_VIDEOS_SETTINGS)}
-
+
{this.renderGroup(PreferencesUserSettingsTab.TIMELINE_SETTINGS)}
@@ -356,11 +363,11 @@ export default class PreferencesUserSettingsTab extends React.Component
-
+
{this.renderGroup(PreferencesUserSettingsTab.ROOM_DIRECTORY_SETTINGS)}
-
+
{this.renderGroup(PreferencesUserSettingsTab.GENERAL_SETTINGS)}
diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx
index c0e63f6f04..d301f9daab 100644
--- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx
@@ -12,6 +12,7 @@ import { type Room, RoomEvent, type IServerVersions } from "matrix-js-sdk/src/ma
import { KnownMembership, type Membership } from "matrix-js-sdk/src/types";
import { logger } from "matrix-js-sdk/src/logger";
import { WarningIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
+import { Form } from "@vector-im/compound-web";
import { _t } from "../../../../../languageHandler";
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
@@ -321,7 +322,13 @@ export default class SecurityUserSettingsTab extends React.Component
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ className="mx_SecurityUserSettingsTab_posthogSection"
+ >
- >
+
);
}
diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx
index 84b4ec778f..b1b47788a5 100644
--- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx
@@ -7,10 +7,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React, { type JSX, type ReactNode } from "react";
+import React, { type ChangeEventHandler, type JSX, type ReactNode } from "react";
import { logger } from "matrix-js-sdk/src/logger";
import { FALLBACK_ICE_SERVER } from "matrix-js-sdk/src/webrtc/call";
import { type EmptyObject } from "matrix-js-sdk/src/matrix";
+import { Form, SettingsToggleInput } from "@vector-im/compound-web";
import { _t } from "../../../../../languageHandler";
import MediaDeviceHandler, { type IMediaDevices, MediaDeviceKindEnum } from "../../../../../MediaDeviceHandler";
@@ -18,7 +19,6 @@ import Field from "../../../elements/Field";
import AccessibleButton from "../../../elements/AccessibleButton";
import { SettingLevel } from "../../../../../settings/SettingLevel";
import SettingsFlag from "../../../elements/SettingsFlag";
-import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
import { requestMediaPermissions } from "../../../../../utils/media/requestMediaPermissions";
import SettingsTab from "../SettingsTab";
import { SettingsSection } from "../../shared/SettingsSection";
@@ -140,6 +140,24 @@ export default class VoiceUserSettingsTab extends React.Component = async (event) => {
+ const enable = event.target.checked;
+ await MediaDeviceHandler.setAudioAutoGainControl(enable);
+ this.setState({ audioAutoGainControl: MediaDeviceHandler.getAudioAutoGainControl() });
+ };
+
+ private onNoiseSuppressionChanged: ChangeEventHandler = async (event) => {
+ const enable = event.target.checked;
+ await MediaDeviceHandler.setAudioNoiseSuppression(enable);
+ this.setState({ audioNoiseSuppression: MediaDeviceHandler.getAudioNoiseSuppression() });
+ };
+
+ private onEchoCancellationChanged: ChangeEventHandler = async (event) => {
+ const enable = event.target.checked;
+ await MediaDeviceHandler.setAudioEchoCancellation(enable);
+ this.setState({ audioEchoCancellation: MediaDeviceHandler.getAudioEchoCancellation() });
+ };
+
public render(): ReactNode {
let requestButton: ReactNode | undefined;
let speakerDropdown: ReactNode | undefined;
@@ -169,64 +187,62 @@ export default class VoiceUserSettingsTab extends React.Component
-
- {requestButton}
-
- {speakerDropdown}
- {microphoneDropdown}
- => {
- await MediaDeviceHandler.setAudioAutoGainControl(v);
- this.setState({ audioAutoGainControl: MediaDeviceHandler.getAudioAutoGainControl() });
- }}
- label={_t("settings|voip|voice_agc")}
- data-testid="voice-auto-gain"
- />
-
-
- {webcamDropdown}
-
-
-
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
+
+ {requestButton}
+
+ {speakerDropdown}
+ {microphoneDropdown}
+
+
+
+ {webcamDropdown}
+
+
+
-
-
- => {
- await MediaDeviceHandler.setAudioNoiseSuppression(v);
- this.setState({ audioNoiseSuppression: MediaDeviceHandler.getAudioNoiseSuppression() });
- }}
- label={_t("settings|voip|noise_suppression")}
- data-testid="voice-noise-suppression"
- />
- => {
- await MediaDeviceHandler.setAudioEchoCancellation(v);
- this.setState({ audioEchoCancellation: MediaDeviceHandler.getAudioEchoCancellation() });
- }}
- label={_t("settings|voip|echo_cancellation")}
- data-testid="voice-echo-cancellation"
- />
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/components/views/spaces/SpaceSettingsVisibilityTab.tsx b/src/components/views/spaces/SpaceSettingsVisibilityTab.tsx
index e456070cce..a148608790 100644
--- a/src/components/views/spaces/SpaceSettingsVisibilityTab.tsx
+++ b/src/components/views/spaces/SpaceSettingsVisibilityTab.tsx
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React, { type JSX, useState } from "react";
+import React, { type ChangeEventHandler, type JSX, useCallback, useState } from "react";
import {
type Room,
EventType,
@@ -15,12 +15,12 @@ import {
JoinRule,
type MatrixClient,
} from "matrix-js-sdk/src/matrix";
+import { Form, SettingsToggleInput } from "@vector-im/compound-web";
import { _t } from "../../../languageHandler";
import AccessibleButton from "../elements/AccessibleButton";
import AliasSettings from "../room_settings/AliasSettings";
import { useStateToggle } from "../../../hooks/useStateToggle";
-import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import { useLocalEcho } from "../../../hooks/useLocalEcho";
import JoinRuleSettings from "../settings/JoinRuleSettings";
import { useRoomState } from "../../../hooks/useRoomState";
@@ -50,6 +50,7 @@ const SpaceSettingsVisibilityTab: React.FC = ({ matrixClient: cli, space
const userId = cli.getUserId()!;
const joinRule = useRoomState(space, (state) => state.getJoinRule());
+
const [guestAccessEnabled, setGuestAccessEnabled] = useLocalEcho(
() =>
space.currentState.getStateEvents(EventType.RoomGuestAccess, "")?.getContent()?.guest_access ===
@@ -65,6 +66,10 @@ const SpaceSettingsVisibilityTab: React.FC = ({ matrixClient: cli, space
),
() => setError(_t("room_settings|visibility|error_update_guest_access")),
);
+ const onGuestAccessEnabledChanged = useCallback>(
+ (e) => setGuestAccessEnabled(e.target.checked),
+ [setGuestAccessEnabled],
+ );
const [historyVisibility, setHistoryVisibility] = useLocalEcho(
() =>
space.currentState.getStateEvents(EventType.RoomHistoryVisibility, "")?.getContent()?.history_visibility ||
@@ -103,19 +108,15 @@ const SpaceSettingsVisibilityTab: React.FC = ({ matrixClient: cli, space
{showAdvancedSection && (
-
-
-
- {_t("room_settings|visibility|guest_access_explainer")}
-
- {_t("room_settings|visibility|guest_access_explainer_public_space")}
-
-
+
)}
);
@@ -155,26 +156,32 @@ const SpaceSettingsVisibilityTab: React.FC = ({ matrixClient: cli, space
onError={(): void => setError(_t("room_settings|visibility|error_failed_save"))}
closeSettingsFn={closeSettingsFn}
/>
- {advancedSection}
-
-
{
+ {
+ evt.preventDefault();
+ evt.stopPropagation();
+ }}
+ >
+ {advancedSection}
+ {
setHistoryVisibility(
- checked ? HistoryVisibility.WorldReadable : HistoryVisibility.Shared,
+ evt.target.checked ? HistoryVisibility.WorldReadable : HistoryVisibility.Shared,
);
}}
+ helpMessage={_t("room_settings|visibility|history_visibility_anyone_space_description")}
disabled={!canSetHistoryVisibility}
+ disabledMessage={_t("room_settings|visibility|history_visibility_anyone_space_disabled")}
label={_t("room_settings|visibility|history_visibility_anyone_space")}
/>
- {_t("room_settings|visibility|history_visibility_anyone_space_description")}
-
{_t("room_settings|visibility|history_visibility_anyone_space_recommendation")}
-
+
{addressesSection}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 968fefae10..3d2fd7f6d9 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -2333,6 +2333,8 @@
"no_aliases_space": "This space has no local addresses",
"other_section": "Other",
"publish_toggle": "Publish this room to the public in %(domain)s's room directory?",
+ "publish_warn_invite_only": "You cannot publish a room that is invite-only.",
+ "publish_warn_no_canonical_permission": "You must have permission to set the main address to publish this room.",
"published_aliases_description": "To publish an address, it needs to be set as a local address first.",
"published_aliases_explainer_room": "Published addresses can be used by anyone on any server to join your room.",
"published_aliases_explainer_space": "Published addresses can be used by anyone on any server to join your space.",
@@ -2488,11 +2490,12 @@
"error_failed_save": "Failed to update the visibility of this space",
"error_update_guest_access": "Failed to update the guest access of this space",
"error_update_history_visibility": "Failed to update the history visibility of this space",
- "guest_access_explainer": "Guests can join a space without having an account.",
- "guest_access_explainer_public_space": "This may be useful for public spaces.",
+ "guest_access_disabled": "You do not have permission to change guest access.",
+ "guest_access_explainer": "Guests can join a space without having an account. This may be useful for public spaces.",
"guest_access_label": "Enable guest access",
"history_visibility_anyone_space": "Preview Space",
"history_visibility_anyone_space_description": "Allow people to preview your space before they join.",
+ "history_visibility_anyone_space_disabled": "You do not have permission to change history visibilty.",
"history_visibility_anyone_space_recommendation": "Recommended for public spaces.",
"title": "Visibility"
},
diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx
index d9a8ec1ebf..2ceb1b807f 100644
--- a/src/settings/Settings.tsx
+++ b/src/settings/Settings.tsx
@@ -974,6 +974,10 @@ export const SETTINGS: Settings = {
default: false,
displayName: _td("settings|appearance|custom_font"),
controller: new SystemFontController(),
+ description: () =>
+ _t("settings|appearance|custom_font_description", {
+ brand: SdkConfig.get().brand,
+ }),
},
"systemFont": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
@@ -1135,10 +1139,12 @@ export const SETTINGS: Settings = {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
default: false,
controller: new NotificationsEnabledController(),
+ displayName: _td("settings|notifications|enable_desktop_notifications_session"),
},
"deviceNotificationsEnabled": {
supportedLevels: [SettingLevel.DEVICE],
default: true,
+ displayName: _td("settings|notifications|enable_notifications_device"),
},
"notificationSound": {
supportedLevels: LEVELS_ROOM_OR_ACCOUNT,
@@ -1150,10 +1156,12 @@ export const SETTINGS: Settings = {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
default: true,
controller: new NotificationBodyEnabledController(),
+ displayName: _td("settings|notifications|show_message_desktop_notification"),
},
"audioNotificationsEnabled": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
default: true,
+ displayName: _td("settings|notifications|enable_audible_notifications_session"),
},
"enableWidgetScreenshots": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
diff --git a/test/unit-tests/components/views/dialogs/CreateRoomDialog-test.tsx b/test/unit-tests/components/views/dialogs/CreateRoomDialog-test.tsx
index 6ac423570f..f9ebaacbd9 100644
--- a/test/unit-tests/components/views/dialogs/CreateRoomDialog-test.tsx
+++ b/test/unit-tests/components/views/dialogs/CreateRoomDialog-test.tsx
@@ -19,9 +19,6 @@ describe(" ", () => {
const userId = "@alice:server.org";
const getE2eeEnableToggleInputElement = () => screen.getByLabelText("Enable end-to-end encryption");
- // labelled toggle switch doesn't set the disabled attribute, only aria-disabled
- const getE2eeEnableToggleIsDisabled = () =>
- getE2eeEnableToggleInputElement().getAttribute("aria-disabled") === "true";
let mockClient: ReturnType;
beforeEach(() => {
@@ -121,7 +118,7 @@ describe(" ", () => {
await flushPromises();
expect(getE2eeEnableToggleInputElement()).not.toBeChecked();
- expect(getE2eeEnableToggleIsDisabled()).toBeFalsy();
+ expect(getE2eeEnableToggleInputElement()).not.toBeDisabled();
expect(
screen.getByText(
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.",
@@ -141,7 +138,7 @@ describe(" ", () => {
await flushPromises();
expect(getE2eeEnableToggleInputElement()).not.toBeChecked();
- expect(getE2eeEnableToggleIsDisabled()).toBeTruthy();
+ expect(getE2eeEnableToggleInputElement()).toBeDisabled();
expect(
screen.getByText(
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.",
@@ -161,7 +158,7 @@ describe(" ", () => {
await flushPromises();
// encryption enabled
expect(getE2eeEnableToggleInputElement()).toBeChecked();
- expect(getE2eeEnableToggleIsDisabled()).toBeFalsy();
+ expect(getE2eeEnableToggleInputElement()).not.toBeDisabled();
});
it("should use defaultEncrypted prop when it is false", async () => {
@@ -177,7 +174,7 @@ describe(" ", () => {
// encryption disabled
expect(getE2eeEnableToggleInputElement()).not.toBeChecked();
// not forced to off
- expect(getE2eeEnableToggleIsDisabled()).toBeFalsy();
+ expect(getE2eeEnableToggleInputElement()).not.toBeDisabled();
});
it("should override defaultEncrypted when server .well-known forces disabled encryption", async () => {
@@ -192,7 +189,7 @@ describe(" ", () => {
// server forces encryption to disabled, even though defaultEncrypted is false
expect(getE2eeEnableToggleInputElement()).not.toBeChecked();
- expect(getE2eeEnableToggleIsDisabled()).toBeTruthy();
+ expect(getE2eeEnableToggleInputElement()).toBeDisabled();
expect(
screen.getByText(
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.",
@@ -207,7 +204,7 @@ describe(" ", () => {
// server forces encryption to enabled, even though defaultEncrypted is true
expect(getE2eeEnableToggleInputElement()).toBeChecked();
- expect(getE2eeEnableToggleIsDisabled()).toBeTruthy();
+ expect(getE2eeEnableToggleInputElement()).toBeDisabled();
expect(screen.getByText("Your server requires encryption to be enabled in private rooms.")).toBeDefined();
});
@@ -217,7 +214,7 @@ describe(" ", () => {
await flushPromises();
expect(getE2eeEnableToggleInputElement()).toBeChecked();
- expect(getE2eeEnableToggleIsDisabled()).toBeTruthy();
+ expect(getE2eeEnableToggleInputElement()).toBeDisabled();
expect(screen.getByText("Your server requires encryption to be enabled in private rooms.")).toBeDefined();
});
@@ -319,7 +316,7 @@ describe(" ", () => {
it("should create a knock room with public visibility", async () => {
fireEvent.click(
- screen.getByRole("checkbox", { name: "Make this room visible in the public room directory." }),
+ screen.getByRole("switch", { name: "Make this room visible in the public room directory." }),
);
fireEvent.click(screen.getByText("Create room"));
await flushPromises();
diff --git a/test/unit-tests/components/views/dialogs/WidgetOpenIDPermissionsDialog-test.tsx b/test/unit-tests/components/views/dialogs/WidgetOpenIDPermissionsDialog-test.tsx
new file mode 100644
index 0000000000..2f1ddae972
--- /dev/null
+++ b/test/unit-tests/components/views/dialogs/WidgetOpenIDPermissionsDialog-test.tsx
@@ -0,0 +1,37 @@
+/*
+Copyright 2025 Element Creations Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE files in the repository root for full details.
+*/
+
+import React from "react";
+import { render } from "jest-matrix-react";
+import { WidgetKind } from "matrix-widget-api";
+
+import { stubClient } from "../../../../test-utils";
+import WidgetOpenIDPermissionsDialog from "../../../../../src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx";
+
+describe("WidgetOpenIDPermissionsDialog", () => {
+ const mockWidget = {
+ id: "test-widget",
+ name: "Test Widget",
+ templateUrl: "https://imawidget",
+ } as any;
+
+ const onFinished = jest.fn();
+
+ beforeEach(() => {
+ stubClient();
+ onFinished.mockClear();
+ });
+
+ it("should render", () => {
+ const dialog = render(
+ ,
+ );
+
+ expect(dialog.getByText("Allow this widget to verify your identity")).toBeInTheDocument();
+ expect(dialog.asFragment()).toMatchSnapshot();
+ });
+});
diff --git a/test/unit-tests/components/views/dialogs/__snapshots__/ConfirmRejectInviteDialog-test.tsx.snap b/test/unit-tests/components/views/dialogs/__snapshots__/ConfirmRejectInviteDialog-test.tsx.snap
index f67b0aa1be..74b5bf31eb 100644
--- a/test/unit-tests/components/views/dialogs/__snapshots__/ConfirmRejectInviteDialog-test.tsx.snap
+++ b/test/unit-tests/components/views/dialogs/__snapshots__/ConfirmRejectInviteDialog-test.tsx.snap
@@ -32,67 +32,77 @@ exports[`ConfirmRejectInviteDialog can reject with options selected 1`] = `
Are you sure you want to decline the invitation to join "foo"?
+
+
Ignore user
-
+
You will not see any messages or room invites from this user.
-
-
+
+
Report room
-
+
Report this room to your account provider.
-
-
for a private room should create a private room 1`
Create a private room
-
-
+
for a private room should create a private room 1`
Topic (optional)
-
+
- Private room (invite only)
+
+ Private room (invite only)
+
+
+
+
-
-
-
+
+ Only people invited will be able to find and join this room. You can change this at any time from room settings.
+
-
- Only people invited will be able to find and join this room. You can change this at any time from room settings.
-
+
+
Enable end-to-end encryption
-
-
-
-
- You can't disable this later. Bridges & most bots won't work yet.
-
@@ -137,36 +151,49 @@ exports[` for a private room should create a private room 1`
Show advanced
+
+
Block anyone not part of server.org from ever joining this room.
-
-
-
+ z
You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.
-
-
+
+
@@ -227,9 +254,11 @@ exports[` for a private room should render not the advanced
Create a private room
-
-
+
for a private room should render not the advanced
Topic (optional)
-
+
- Private room (invite only)
+
+ Private room (invite only)
+
+
+
+
-
-
-
+
+ Only people invited will be able to find and join this room. You can change this at any time from room settings.
+
-
- Only people invited will be able to find and join this room. You can change this at any time from room settings.
-
+
+
Enable end-to-end encryption
-
-
-
-
- You can't disable this later. Bridges & most bots won't work yet.
-
-
-
+
+
diff --git a/test/unit-tests/components/views/dialogs/__snapshots__/DevtoolsDialog-test.tsx.snap b/test/unit-tests/components/views/dialogs/__snapshots__/DevtoolsDialog-test.tsx.snap
index 45b6afe664..7db3667746 100644
--- a/test/unit-tests/components/views/dialogs/__snapshots__/DevtoolsDialog-test.tsx.snap
+++ b/test/unit-tests/components/views/dialogs/__snapshots__/DevtoolsDialog-test.tsx.snap
@@ -116,119 +116,129 @@ exports[`DevtoolsDialog renders the devtools dialog 1`] = `
End-to-end encryption
-
+
-
-
- Developer mode
-
-
-
-
-
-
-
- Show hidden events in timeline
-
-
-
-
-
-
-
- Enable widget screenshots on supported widgets
-
-
-
-
-
-
-
+
+
+ Developer mode
+
+
+
+
+
+
+
+ Show hidden events in timeline
+
+
+
+
+
+
+
+ Enable widget screenshots on supported widgets
+
+
+
+
+
+ Element Call URL
+
+
+
+
+
+
Report this room to your account provider. If the messages are encrypted, your admin will not be able to read them.
@@ -66,28 +66,34 @@ exports[`ReportRoomDialog displays admin message 1`] = `
+
+
Leave room
-
-
-
+
+
+
+
+`;
diff --git a/test/unit-tests/components/views/dialogs/devtools/__snapshots__/Users-test.tsx.snap b/test/unit-tests/components/views/dialogs/devtools/__snapshots__/Users-test.tsx.snap
index a4cc5f2ca1..7693862522 100644
--- a/test/unit-tests/components/views/dialogs/devtools/__snapshots__/Users-test.tsx.snap
+++ b/test/unit-tests/components/views/dialogs/devtools/__snapshots__/Users-test.tsx.snap
@@ -417,31 +417,42 @@ exports[`
should render a user list 1`] = `
No results found
-
-
-
- Only joined users
-
-
+
+
+ Only joined users
+
+
-
+
", () => {
setShareType(getByText, LocationShareType.Live);
- expect(getByText("OK").hasAttribute("disabled")).toBeTruthy();
+ expect(getByText("OK")).toHaveAttribute("aria-disabled", "true");
});
it("enables OK button when labs flag is toggled to enabled", () => {
@@ -311,7 +311,7 @@ describe(" ", () => {
fireEvent.click(getByLabelText("Enable live location sharing"));
- expect(getByText("OK").hasAttribute("disabled")).toBeFalsy();
+ expect(getByText("OK")).not.toHaveAttribute("aria-disabled", "true");
});
it("enables live share setting on ok button submit", () => {
diff --git a/test/unit-tests/components/views/location/__snapshots__/LocationShareMenu-test.tsx.snap b/test/unit-tests/components/views/location/__snapshots__/LocationShareMenu-test.tsx.snap
index 962f814bac..3216492774 100644
--- a/test/unit-tests/components/views/location/__snapshots__/LocationShareMenu-test.tsx.snap
+++ b/test/unit-tests/components/views/location/__snapshots__/LocationShareMenu-test.tsx.snap
@@ -18,41 +18,50 @@ exports[` with live location disabled goes to labs flag scr
>
Please note: this is a labs feature using a temporary implementation. This means you will not be able to delete your location history, and advanced users will be able to see your location history even after you stop sharing your live location with this room.
-
-
- Enable live location sharing
+
-
-
+
+ Enable live location sharing
+
+
+
+
-
-
-
-
- OK
-
+ OK
+
+
`;
diff --git a/test/unit-tests/components/views/room_settings/UrlPreviewSettings-test.tsx b/test/unit-tests/components/views/room_settings/UrlPreviewSettings-test.tsx
index c392788e38..23e9b12682 100644
--- a/test/unit-tests/components/views/room_settings/UrlPreviewSettings-test.tsx
+++ b/test/unit-tests/components/views/room_settings/UrlPreviewSettings-test.tsx
@@ -9,6 +9,7 @@ import React from "react";
import { type MatrixClient, type Room } from "matrix-js-sdk/src/matrix";
import { render, screen } from "jest-matrix-react";
import { waitFor } from "@testing-library/dom";
+import { Form } from "@vector-im/compound-web";
import { createTestClient, mkStubRoom, withClientContextRenderOptions } from "../../../../test-utils";
import { UrlPreviewSettings } from "../../../../../src/components/views/room_settings/UrlPreviewSettings.tsx";
@@ -30,7 +31,12 @@ describe("UrlPreviewSettings", () => {
});
function renderComponent() {
- return render( , withClientContextRenderOptions(client));
+ return render(
+
+
+ ,
+ withClientContextRenderOptions(client),
+ );
}
it("should display the correct preview when the setting is in a loading state", () => {
diff --git a/test/unit-tests/components/views/room_settings/__snapshots__/UrlPreviewSettings-test.tsx.snap b/test/unit-tests/components/views/room_settings/__snapshots__/UrlPreviewSettings-test.tsx.snap
index be9fc0a4c3..cbb3153219 100644
--- a/test/unit-tests/components/views/room_settings/__snapshots__/UrlPreviewSettings-test.tsx.snap
+++ b/test/unit-tests/components/views/room_settings/__snapshots__/UrlPreviewSettings-test.tsx.snap
@@ -2,235 +2,269 @@
exports[`UrlPreviewSettings should display the correct preview when the room is encrypted and the url preview is enabled 1`] = `
-
-
- URL Previews
-
-
-
-
- When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.
-
-
- In encrypted rooms, like this one, URL previews are disabled by default to ensure that your homeserver (where the previews are generated) cannot gather information about links you see in this room.
-
-
-
-
-
+
+
+
+
+
+ urlPreviewsEnabled_e2ee
+
+
+
+
+
+
`;
exports[`UrlPreviewSettings should display the correct preview when the room is unencrypted and the url preview is disabled 1`] = `
-
-
- URL Previews
-
-
-
+ URL Previews
+
+
-
- When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.
-
-
-
- You have
-
-
- disabled
-
- URL previews by default.
-
-
-
-
-
- URL previews are disabled by default for participants in this room.
-
-
-
-
+ When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.
+
+
+
+ You have
+
+
+
- Enable inline URL previews by default
-
-
+ disabled
+
+ URL previews by default.
+
+
+
+
+
+ URL previews are disabled by default for participants in this room.
+
+
+
+ Enable inline URL previews by default
+
+
-
-
+
+
`;
exports[`UrlPreviewSettings should display the correct preview when the room is unencrypted and the url preview is enabled 1`] = `
-
-
- URL Previews
-
-
-
+ URL Previews
+
+
-
- When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.
-
-
-
- You have
-
-
- enabled
-
- URL previews by default.
-
-
-
-
-
- URL previews are enabled by default for participants in this room.
-
-
-
-
+ When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.
+
+
+
+ You have
+
+
+
- Enable inline URL previews by default
-
-
+ enabled
+
+ URL previews by default.
+
+
+
+
+
+ URL previews are enabled by default for participants in this room.
+
+
+
+ Enable inline URL previews by default
+
+
-
-
+
+
`;
exports[`UrlPreviewSettings should display the correct preview when the setting is in a loading state 1`] = `
-
-
- URL Previews
-
-
-
+ URL Previews
+
+
+
+
`;
diff --git a/test/unit-tests/components/views/settings/Notifications-test.tsx b/test/unit-tests/components/views/settings/Notifications-test.tsx
index 1566013aba..6e349baef0 100644
--- a/test/unit-tests/components/views/settings/Notifications-test.tsx
+++ b/test/unit-tests/components/views/settings/Notifications-test.tsx
@@ -37,6 +37,7 @@ import {
import { mocked } from "jest-mock";
import userEvent from "@testing-library/user-event";
import { PushProcessor } from "matrix-js-sdk/src/pushprocessor";
+import { Form } from "@vector-im/compound-web";
import Notifications from "../../../../../src/components/views/settings/Notifications";
import SettingsStore from "../../../../../src/settings/SettingsStore";
@@ -248,7 +249,12 @@ const pushRules: IPushRules = {
const flushPromises = async () => await new Promise((resolve) => window.setTimeout(resolve));
describe(" ", () => {
- const getComponent = () => render( );
+ const getComponent = () =>
+ render(
+
+
+ ,
+ );
// get component, wait for async data and force a render
const getComponentAndWait = async () => {
@@ -347,11 +353,11 @@ describe(" ", () => {
it("renders switches correctly", async () => {
await getComponentAndWait();
- expect(screen.getByTestId("notif-master-switch")).toBeInTheDocument();
- expect(screen.getByTestId("notif-device-switch")).toBeInTheDocument();
- expect(screen.getByTestId("notif-setting-notificationsEnabled")).toBeInTheDocument();
- expect(screen.getByTestId("notif-setting-notificationBodyEnabled")).toBeInTheDocument();
- expect(screen.getByTestId("notif-setting-audioNotificationsEnabled")).toBeInTheDocument();
+ expect(screen.getByLabelText("Enable notifications for this account")).toBeInTheDocument();
+ expect(screen.getByLabelText("Enable notifications for this device")).toBeInTheDocument();
+ expect(screen.getByLabelText("Enable desktop notifications for this session")).toBeInTheDocument();
+ expect(screen.getByLabelText("Show message in desktop notification")).toBeInTheDocument();
+ expect(screen.getByLabelText("Enable audible notifications for this session")).toBeInTheDocument();
});
describe("email switches", () => {
@@ -370,7 +376,7 @@ describe(" ", () => {
it("renders email switches correctly when email 3pids exist", async () => {
await getComponentAndWait();
- expect(screen.getByTestId("notif-email-switch")).toBeInTheDocument();
+ expect(screen.getByLabelText(`Enable email notifications for ${testEmail}`)).toBeInTheDocument();
});
it("renders email switches correctly when notifications are on for email", async () => {
@@ -379,14 +385,14 @@ describe(" ", () => {
});
await getComponentAndWait();
- const emailSwitch = screen.getByTestId("notif-email-switch");
- expect(emailSwitch.querySelector('[aria-checked="true"]')).toBeInTheDocument();
+ const emailSwitch = screen.getByLabelText(`Enable email notifications for ${testEmail}`);
+ expect(emailSwitch).toBeChecked();
});
it("enables email notification when toggling on", async () => {
await getComponentAndWait();
- const emailToggle = screen.getByTestId("notif-email-switch").querySelector('div[role="switch"]')!;
+ const emailToggle = screen.getByLabelText(`Enable email notifications for ${testEmail}`);
fireEvent.click(emailToggle);
expect(mockClient.setPusher).toHaveBeenCalledWith(
@@ -405,7 +411,7 @@ describe(" ", () => {
mockClient.setPusher.mockRejectedValue({});
await getComponentAndWait();
- const emailToggle = screen.getByTestId("notif-email-switch").querySelector('div[role="switch"]')!;
+ const emailToggle = screen.getByLabelText(`Enable email notifications for ${testEmail}`);
fireEvent.click(emailToggle);
// force render
@@ -431,7 +437,7 @@ describe(" ", () => {
mockClient.getPushers.mockResolvedValue({ pushers: [testPusher] });
await getComponentAndWait();
- const emailToggle = screen.getByTestId("notif-email-switch").querySelector('div[role="switch"]')!;
+ const emailToggle = screen.getByLabelText(`Enable email notifications for ${testEmail}`);
fireEvent.click(emailToggle);
expect(mockClient.removePusher).toHaveBeenCalledWith(testPusher.pushkey, testPusher.app_id);
@@ -452,22 +458,20 @@ describe(" ", () => {
it("toggles and sets settings correctly", async () => {
await getComponentAndWait();
- let audioNotifsToggle!: HTMLDivElement;
+ let audioNotifsToggle!: HTMLInputElement;
const update = () => {
- audioNotifsToggle = screen
- .getByTestId("notif-setting-audioNotificationsEnabled")
- .querySelector('div[role="switch"]')!;
+ audioNotifsToggle = screen.getByLabelText("Enable audible notifications for this session");
};
update();
- expect(audioNotifsToggle.getAttribute("aria-checked")).toEqual("true");
+ expect(audioNotifsToggle).toBeChecked();
expect(SettingsStore.getValue("audioNotificationsEnabled")).toEqual(true);
fireEvent.click(audioNotifsToggle);
update();
- expect(audioNotifsToggle.getAttribute("aria-checked")).toEqual("false");
+ expect(audioNotifsToggle).not.toBeChecked();
expect(SettingsStore.getValue("audioNotificationsEnabled")).toEqual(false);
});
});
diff --git a/test/unit-tests/components/views/settings/__snapshots__/Notifications-test.tsx.snap b/test/unit-tests/components/views/settings/__snapshots__/Notifications-test.tsx.snap
index 6607b7b271..d971d9001b 100644
--- a/test/unit-tests/components/views/settings/__snapshots__/Notifications-test.tsx.snap
+++ b/test/unit-tests/components/views/settings/__snapshots__/Notifications-test.tsx.snap
@@ -2,94 +2,114 @@
exports[` main notification switches renders only enable notifications switch when notifications are disabled 1`] = `
-
-
-
- Enable notifications for this account
-
-
- Turn off to disable notifications on all your devices and sessions
-
-
-
-
-
-
-
- Show all activity in the room list (dots or number of unread messages)
-
-
-
+
+
+
+ Enable notifications for this account
+
+
+ Turn off to disable notifications on all your devices and sessions
+
-
-
-
- Only show notifications in the thread activity centre
-
-
+
+
+ Show all activity in the room list (dots or number of unread messages)
+
+
-
-
+
+
+
+
+ Only show notifications in the thread activity centre
+
+
+
+
+
`;
diff --git a/test/unit-tests/components/views/settings/__snapshots__/SetIntegrationManager-test.tsx.snap b/test/unit-tests/components/views/settings/__snapshots__/SetIntegrationManager-test.tsx.snap
index 52bcc520f4..edb42d8c67 100644
--- a/test/unit-tests/components/views/settings/__snapshots__/SetIntegrationManager-test.tsx.snap
+++ b/test/unit-tests/components/views/settings/__snapshots__/SetIntegrationManager-test.tsx.snap
@@ -1,8 +1,8 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`SetIntegrationManager should render manage integrations sections 1`] = `
-
(scalar.vector.im)
@@ -25,6 +26,7 @@ exports[`SetIntegrationManager should render manage integrations sections 1`] =
Use an integration manager
@@ -39,40 +41,36 @@ exports[`SetIntegrationManager should render manage integrations sections 1`] =
>
Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.
-
-
-
- Enable the integration manager
-
+ class="_ui_udcm8_34"
+ />
-
-
+
+
+ Enable the integration manager
+
+
+
+
`;
diff --git a/test/unit-tests/components/views/settings/notifications/Notifications2-test.tsx b/test/unit-tests/components/views/settings/notifications/Notifications2-test.tsx
index d33b5c4e26..0f8289a42c 100644
--- a/test/unit-tests/components/views/settings/notifications/Notifications2-test.tsx
+++ b/test/unit-tests/components/views/settings/notifications/Notifications2-test.tsx
@@ -18,6 +18,7 @@ import {
RuleId,
} from "matrix-js-sdk/src/matrix";
import React from "react";
+import { Form } from "@vector-im/compound-web";
import NotificationSettings2 from "../../../../../../src/components/views/settings/notifications/NotificationSettings2";
import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext";
@@ -93,7 +94,9 @@ describe(" ", () => {
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -106,7 +109,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(async () => {
@@ -114,7 +119,7 @@ describe(" ", () => {
expect(screen.container).toMatchSnapshot();
const globalMute = screen.getByLabelText(labelGlobalMute);
- expect(globalMute).toHaveAttribute("aria-disabled", "true");
+ expect(globalMute).toBeDisabled();
const levelAllMessages = screen.getByLabelText(labelLevelAllMessage);
expect(levelAllMessages).toBeDisabled();
@@ -167,7 +172,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -183,7 +190,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -221,7 +230,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -256,7 +267,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -285,7 +298,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -310,7 +325,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -332,7 +349,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -360,7 +379,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -384,7 +405,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -406,7 +429,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -434,7 +459,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -458,7 +485,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -485,7 +514,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -504,7 +535,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -615,7 +648,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -674,7 +709,9 @@ describe(" ", () => {
const user = userEvent.setup();
const screen = render(
-
+
+
+
,
);
await act(waitForUpdate);
@@ -694,7 +731,9 @@ describe(" ", () => {
const { container } = render(
-
+
+
+
,
);
await waitForUpdate();
@@ -721,7 +760,9 @@ describe(" ", () => {
const user = userEvent.setup();
const { container } = render(
-
+
+
+
,
);
await waitForUpdate();
diff --git a/test/unit-tests/components/views/settings/notifications/__snapshots__/Notifications2-test.tsx.snap b/test/unit-tests/components/views/settings/notifications/__snapshots__/Notifications2-test.tsx.snap
index 04b6501f8a..2474759a7e 100644
--- a/test/unit-tests/components/views/settings/notifications/__snapshots__/Notifications2-test.tsx.snap
+++ b/test/unit-tests/components/views/settings/notifications/__snapshots__/Notifications2-test.tsx.snap
@@ -2,2125 +2,265 @@
exports[` correctly handles the loading/disabled state 1`] = `
-
-
-
- Enable notifications for this account
-
-
-
-
-
-
-
- Enable desktop notifications for this session
-
-
-
-
-
-
-
- Show message preview in desktop notification
-
-
-
-
-
-
-
- Enable audible notifications for this session
-
-
-
-
-
-
-
-
- I want to be notified for (Default Setting)
-
-
-
- This setting will be applied by default to all your rooms.
-
-
-
-
-
-
- All messages
-
-
-
-
-
-
-
- People, Mentions and Keywords
-
-
-
-
-
-
-
- Mentions and Keywords only
-
-
-
-
-
-
-
-
- Play a sound for
-
-
-
-
- Applied by default to all rooms on all devices.
-
-
-
-
-
-
-
-
-
-
-
- Mentions and Keywords
-
-
-
-
-
-
-
-
-
-
-
-
-
- Audio and Video calls
-
-
-
-
-
-
-
-
-
-
-
- Other things we think you might be interested in:
-
-
-
-
-
-
-
-
-
-
- Invited to a room
-
-
-
-
-
-
-
-
-
-
-
-
-
- New room activity, upgrades and status messages occur
-
-
-
-
-
-
-
-
-
-
-
-
-
- Messages sent by bots
-
-
-
-
-
-
-
-
-
-
-
- Mentions and Keywords
-
-
-
-
-
- Show a badge
-
-
- 1
-
-
- when keywords are used in a room.
-
-
-
-
-
-
-
-
-
-
-
- Notify when someone mentions using @room
-
-
-
-
-
-
-
-
-
-
-
-
-
- Notify when someone mentions using @displayname or @userId:matrix.org
-
-
-
-
-
-
-
-
-
-
-
-
-
- Notify when someone uses a keyword
-
-
-
- Enter keywords here, or use for spelling variations or nicknames
-
-
-
-
-
-
-
-
-
-
- Show all activity in the room list (dots or number of unread messages)
-
-
-
-
-
- Only show notifications in the thread activity centre
-
-
-
-
-
-
-
-
- Email summary
-
-
-
-
- Receive an email summary of missed notifications
-
-
-
-
- Select which emails you want to send summaries to. Manage your emails in
-
- General
-
- .
-
-
-
-
-
-
-
-
-
- Quick Actions
-
-
-
-
- Reset to default settings
-
-
-
-
-
-
-
-`;
-
-exports[` matches the snapshot 1`] = `
-
-
-
-
-
-
-
-
- Enable notifications for this account
-
-
-
-
-
-
-
- Enable desktop notifications for this session
-
-
-
-
-
-
-
- Show message preview in desktop notification
-
-
-
-
-
-
-
- Enable audible notifications for this session
-
-
-
-
-
-
-
-
- I want to be notified for (Default Setting)
-
-
-
-
- This setting will be applied by default to all your rooms.
-
-
-
-
-
-
-
- All messages
-
-
-
-
-
-
-
- People, Mentions and Keywords
-
-
-
-
-
-
-
- Mentions and Keywords only
-
-
-
-
-
-
-
-
- Play a sound for
-
-
-
-
- Applied by default to all rooms on all devices.
-
-
-
-
-
-
-
-
-
-
-
- Mentions and Keywords
-
-
-
-
-
-
-
-
-
-
-
-
-
- Audio and Video calls
-
-
-
-
-
-
-
-
-
-
-
- Other things we think you might be interested in:
-
-
-
-
-
-
-
-
-
-
- Invited to a room
-
-
-
-
-
-
-
-
-
-
-
-
-
- New room activity, upgrades and status messages occur
-
-
-
-
-
-
-
-
-
-
-
-
-
- Messages sent by bots
-
-
-
-
-
-
-
-
-
-
-
- Mentions and Keywords
-
-
-
-
-
- Show a badge
-
-
- 1
-
-
- when keywords are used in a room.
-
-
-
-
-
-
-
-
-
-
-
- Notify when someone mentions using @room
-
-
-
-
-
-
-
-
-
-
-
-
-
- Notify when someone mentions using @displayname or @userId:matrix.org
-
-
-
-
-
-
-
-
-
-
-
-
-
- Notify when someone uses a keyword
-
-
-
- Enter keywords here, or use for spelling variations or nicknames
-
-
-
-
-
-
-
-
- Show all activity in the room list (dots or number of unread messages)
-
-
+
+
+
+ Show message preview in desktop notification
+
-
-
- Only show notifications in the thread activity centre
-
-
+
+
+
+ Enable audible notifications for this session
+
-
-
-
- Email summary
-
-
-
- Receive an email summary of missed notifications
+
+ I want to be notified for (Default Setting)
+
-
- Select which emails you want to send summaries to. Manage your emails in
-
- General
-
- .
-
+ This setting will be applied by default to all your rooms.
+
+
+
+
+ All messages
+
+
+
+
+
+
+
+ People, Mentions and Keywords
+
+
+
+
+
+
+
+ Mentions and Keywords only
+
+
+
+
+
+
+
+
+ Play a sound for
+
+
+
+
+ Applied by default to all rooms on all devices.
+
+
+
matches the snapshot 1`] = `
class="_container_1md5v_10"
>
matches the snapshot 1`] = `
>
- test@example.tld
+ People
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Mentions and Keywords
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Audio and Video calls
@@ -2179,55 +435,1900 @@ exports[`
matches the snapshot 1`] = `
-
-
-
- Notification targets
-
-
-
-
-
-
-
- Quick Actions
-
-
-
- Reset to default settings
+
+ Other things we think you might be interested in:
+
+
+
+
+
+
+
+
+
+
+ Invited to a room
+
+
+
+
+
+
+
+
+
+
+
+
+
+ New room activity, upgrades and status messages occur
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Messages sent by bots
+
+
+
+
+
+
+
+
+
+
+
+ Mentions and Keywords
+
+
+
+
+
+ Show a badge
+
+
+ 1
+
+
+ when keywords are used in a room.
+
+
+
+
+
+
+
+
+
+
+
+ Notify when someone mentions using @room
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Notify when someone mentions using @displayname or @userId:matrix.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Notify when someone uses a keyword
+
+
+
+ Enter keywords here, or use for spelling variations or nicknames
+
+
+
+
+
+
+
+
+
+
+ Keyword
+
+
+
+ Add
+
+
+
+
+
+
+
+
+ Show all activity in the room list (dots or number of unread messages)
+
+
+
+
+
+
+
+ Only show notifications in the thread activity centre
+
+
+
+
+
+
+
+
+ Email summary
+
+
+
+
+ Receive an email summary of missed notifications
+
+
+
+
+ Select which emails you want to send summaries to. Manage your emails in
+
+ General
+
+ .
+
+
+
+
+
+
+
+
+
+
+ Quick Actions
+
+
+
+
+ Reset to default settings
+
-
+
+
+`;
+
+exports[` matches the snapshot 1`] = `
+
+
+
+
+
+
+
+
+
+
+ Enable notifications for this account
+
+
+
+
+
+
+
+ Enable desktop notifications for this session
+
+
+
+
+
+
+
+ Show message preview in desktop notification
+
+
+
+
+
+
+
+ Enable audible notifications for this session
+
+
+
+
+
+
+
+ I want to be notified for (Default Setting)
+
+
+
+
+ This setting will be applied by default to all your rooms.
+
+
+
+
+
+
+
+ All messages
+
+
+
+
+
+
+
+ People, Mentions and Keywords
+
+
+
+
+
+
+
+ Mentions and Keywords only
+
+
+
+
+
+
+
+
+ Play a sound for
+
+
+
+
+ Applied by default to all rooms on all devices.
+
+
+
+
+
+
+
+
+
+
+
+ Mentions and Keywords
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Audio and Video calls
+
+
+
+
+
+
+
+
+
+
+
+ Other things we think you might be interested in:
+
+
+
+
+
+
+
+
+
+
+ Invited to a room
+
+
+
+
+
+
+
+
+
+
+
+
+
+ New room activity, upgrades and status messages occur
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Messages sent by bots
+
+
+
+
+
+
+
+
+
+
+
+ Mentions and Keywords
+
+
+
+
+
+ Show a badge
+
+
+ 1
+
+
+ when keywords are used in a room.
+
+
+
+
+
+
+
+
+
+
+
+ Notify when someone mentions using @room
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Notify when someone mentions using @displayname or @userId:matrix.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Notify when someone uses a keyword
+
+
+
+ Enter keywords here, or use for spelling variations or nicknames
+
+
+
+
+
+
+
+
+
+
+ Keyword
+
+
+
+ Add
+
+
+
+
+
+
+
+
+ Show all activity in the room list (dots or number of unread messages)
+
+
+
+
+
+
+
+ Only show notifications in the thread activity centre
+
+
+
+
+
+
+
+
+ Email summary
+
+
+
+
+ Receive an email summary of missed notifications
+
+
+
+
+ Select which emails you want to send summaries to. Manage your emails in
+
+ General
+
+ .
+
+
+
+
+
+
+
+
+
+
+
+ test@example.tld
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Notification targets
+
+
+
+
+
+
+
+
+ Quick Actions
+
+
+
+
+ Reset to default settings
+
+
+
+
+
+
+
`;
diff --git a/test/unit-tests/components/views/settings/tabs/room/SecurityRoomSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/room/SecurityRoomSettingsTab-test.tsx
index 6078fa4fe9..bf702f8199 100644
--- a/test/unit-tests/components/views/settings/tabs/room/SecurityRoomSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/room/SecurityRoomSettingsTab-test.tsx
@@ -252,7 +252,7 @@ describe(" ", () => {
fireEvent.click(screen.getByText("Show advanced"));
- expect(screen.getByLabelText("Enable guest access").getAttribute("aria-checked")).toBe("false");
+ expect(screen.getByLabelText("Enable guest access")).not.toBeChecked();
});
it("updates guest access on toggle", () => {
@@ -264,7 +264,7 @@ describe(" ", () => {
fireEvent.click(screen.getByLabelText("Enable guest access"));
// toggle set immediately
- expect(screen.getByLabelText("Enable guest access").getAttribute("aria-checked")).toBe("true");
+ expect(screen.getByLabelText("Enable guest access")).toBeChecked();
expect(client.sendStateEvent).toHaveBeenCalledWith(
room.roomId,
@@ -285,14 +285,14 @@ describe(" ", () => {
fireEvent.click(screen.getByLabelText("Enable guest access"));
// toggle set immediately
- expect(screen.getByLabelText("Enable guest access").getAttribute("aria-checked")).toBe("false");
+ expect(screen.getByLabelText("Enable guest access")).not.toBeChecked();
await flushPromises();
expect(client.sendStateEvent).toHaveBeenCalled();
expect(logger.error).toHaveBeenCalledWith("oups");
// toggle reset to old value
- expect(screen.getByLabelText("Enable guest access").getAttribute("aria-checked")).toBe("true");
+ expect(screen.getByLabelText("Enable guest access")).toBeChecked();
});
});
@@ -388,7 +388,7 @@ describe(" ", () => {
await waitFor(() => expect(screen.getByLabelText("Encrypted")).toBeChecked());
// can't disable encryption once enabled
- expect(screen.getByLabelText("Encrypted").getAttribute("aria-disabled")).toEqual("true");
+ expect(screen.getByLabelText("Encrypted")).toBeDisabled();
});
it("asks users to confirm when setting room to encrypted", async () => {
@@ -495,7 +495,7 @@ describe(" ", () => {
getComponent(room);
await waitFor(() => expect(screen.getByLabelText("Encrypted")).toBeChecked());
- expect(screen.getByLabelText("Encrypted").getAttribute("aria-disabled")).toEqual("true");
+ expect(screen.getByLabelText("Encrypted")).toBeDisabled();
expect(screen.getByText("Once enabled, encryption cannot be disabled.")).toBeInTheDocument();
});
@@ -505,7 +505,7 @@ describe(" ", () => {
getComponent(room);
await waitFor(() => expect(screen.getByLabelText("Encrypted")).not.toBeChecked());
- expect(screen.getByLabelText("Encrypted").getAttribute("aria-disabled")).toEqual("true");
+ expect(screen.getByLabelText("Encrypted")).toBeDisabled();
expect(screen.queryByText("Once enabled, encryption cannot be disabled.")).not.toBeInTheDocument();
expect(screen.getByText("Your server requires encryption to be disabled.")).toBeInTheDocument();
});
diff --git a/test/unit-tests/components/views/settings/tabs/room/VoipRoomSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/room/VoipRoomSettingsTab-test.tsx
index 1008aadbc9..13c7912f29 100644
--- a/test/unit-tests/components/views/settings/tabs/room/VoipRoomSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/room/VoipRoomSettingsTab-test.tsx
@@ -43,7 +43,7 @@ describe("VoipRoomSettingsTab", () => {
};
const getElementCallSwitch = (tab: RenderResult): HTMLElement => {
- return tab.container.querySelector("[data-testid='element-call-switch']")!;
+ return tab.getByLabelText("Enable Element Call as an additional calling option in this room")!;
};
describe("correct state", () => {
@@ -52,7 +52,7 @@ describe("VoipRoomSettingsTab", () => {
const tab = renderTab();
- expect(getElementCallSwitch(tab).querySelector("[aria-checked='true']")).toBeTruthy();
+ expect(getElementCallSwitch(tab)).toBeChecked();
});
it.each([1, 50, 100])("shows disabled when call member power level is 0", (level: number) => {
@@ -60,7 +60,7 @@ describe("VoipRoomSettingsTab", () => {
const tab = renderTab();
- expect(getElementCallSwitch(tab).querySelector("[aria-checked='false']")).toBeTruthy();
+ expect(getElementCallSwitch(tab)).not.toBeChecked();
});
});
@@ -75,7 +75,7 @@ describe("VoipRoomSettingsTab", () => {
const tab = renderTab();
- fireEvent.click(getElementCallSwitch(tab).querySelector(".mx_ToggleSwitch")!);
+ fireEvent.click(getElementCallSwitch(tab));
await waitFor(() =>
expect(cli.sendStateEvent).toHaveBeenCalledWith(
room.roomId,
@@ -95,7 +95,7 @@ describe("VoipRoomSettingsTab", () => {
const tab = renderTab();
- fireEvent.click(getElementCallSwitch(tab).querySelector(".mx_ToggleSwitch")!);
+ fireEvent.click(getElementCallSwitch(tab));
await waitFor(() =>
expect(cli.sendStateEvent).toHaveBeenCalledWith(
room.roomId,
@@ -116,7 +116,7 @@ describe("VoipRoomSettingsTab", () => {
const tab = renderTab();
- fireEvent.click(getElementCallSwitch(tab).querySelector(".mx_ToggleSwitch")!);
+ fireEvent.click(getElementCallSwitch(tab));
await waitFor(() =>
expect(cli.sendStateEvent).toHaveBeenCalledWith(
room.roomId,
diff --git a/test/unit-tests/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx
index 0918b7809f..b0f17fae4c 100644
--- a/test/unit-tests/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/user/PreferencesUserSettingsTab-test.tsx
@@ -89,7 +89,7 @@ describe("PreferencesUserSettingsTab", () => {
renderTab();
const toggle = await screen.findByRole("switch", { name: "Allow spell check" });
- expect(toggle).toHaveAttribute("aria-checked", "false");
+ expect(toggle).not.toBeDisabled();
await userEvent.click(toggle);
@@ -149,7 +149,7 @@ describe("PreferencesUserSettingsTab", () => {
mockGetValue(false);
const toggle = getToggle();
- await waitFor(() => expect(toggle).toHaveAttribute("aria-disabled", "false"));
+ await waitFor(() => expect(toggle).not.toBeDisabled());
fireEvent.click(toggle);
expectSetValueToHaveBeenCalled("sendReadReceipts", null, SettingLevel.ACCOUNT, true);
});
@@ -158,7 +158,7 @@ describe("PreferencesUserSettingsTab", () => {
mockGetValue(true);
const toggle = getToggle();
- await waitFor(() => expect(toggle).toHaveAttribute("aria-disabled", "false"));
+ await waitFor(() => expect(toggle).not.toBeDisabled());
fireEvent.click(toggle);
expectSetValueToHaveBeenCalled("sendReadReceipts", null, SettingLevel.ACCOUNT, false);
});
@@ -172,8 +172,8 @@ describe("PreferencesUserSettingsTab", () => {
it("is forcibly enabled", async () => {
const toggle = getToggle();
await waitFor(() => {
- expect(toggle).toHaveAttribute("aria-checked", "true");
- expect(toggle).toHaveAttribute("aria-disabled", "true");
+ expect(toggle).toBeChecked();
+ expect(toggle).toBeDisabled();
});
});
@@ -181,7 +181,8 @@ describe("PreferencesUserSettingsTab", () => {
mockGetValue(true);
const toggle = getToggle();
- await waitFor(() => expect(toggle).toHaveAttribute("aria-disabled", "true"));
+ await waitFor(() => expect(toggle).toBeDisabled());
+ console.log(toggle.innerHTML);
fireEvent.click(toggle);
expect(SettingsStore.setValue).not.toHaveBeenCalled();
});
diff --git a/test/unit-tests/components/views/settings/tabs/user/VoiceUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/VoiceUserSettingsTab-test.tsx
index d4519d429a..b30ed7a716 100644
--- a/test/unit-tests/components/views/settings/tabs/user/VoiceUserSettingsTab-test.tsx
+++ b/test/unit-tests/components/views/settings/tabs/user/VoiceUserSettingsTab-test.tsx
@@ -113,10 +113,10 @@ describe(" ", () => {
});
it("renders audio processing settings", () => {
- const { getByTestId } = render(getComponent());
- expect(getByTestId("voice-auto-gain")).toBeTruthy();
- expect(getByTestId("voice-noise-suppression")).toBeTruthy();
- expect(getByTestId("voice-echo-cancellation")).toBeTruthy();
+ const { getByRole } = render(getComponent());
+ expect(getByRole("switch", { name: "Automatically adjust the microphone volume" })).toBeTruthy();
+ expect(getByRole("switch", { name: "Noise suppression" })).toBeTruthy();
+ expect(getByRole("switch", { name: "Echo cancellation" })).toBeTruthy();
});
it("sets and displays audio processing settings", () => {
diff --git a/test/unit-tests/components/views/settings/tabs/user/__snapshots__/PreferencesUserSettingsTab-test.tsx.snap b/test/unit-tests/components/views/settings/tabs/user/__snapshots__/PreferencesUserSettingsTab-test.tsx.snap
index e298e13b7c..4df5ff9f96 100644
--- a/test/unit-tests/components/views/settings/tabs/user/__snapshots__/PreferencesUserSettingsTab-test.tsx.snap
+++ b/test/unit-tests/components/views/settings/tabs/user/__snapshots__/PreferencesUserSettingsTab-test.tsx.snap
@@ -15,1143 +15,1374 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
-
-
- Language
-
-
-
- Application language
-
-
- The app will reload after selecting another language
-
+ Language
+
-
-
-
-
-
- Room list
-
-
-
-
-
- Show message previews
-
-
-
-
-
-
-
-
- Spaces
-
-
-
-
-
-
- Show all rooms in Home
-
-
- All rooms you're in will appear in Home.
-
-
-
-
-
-
-
-
-
- Keyboard shortcuts
-
-
-
-
-
- To view all keyboard shortcuts,
-
- click here
-
- .
-
-
-
-
-
-
-
- Use Ctrl + F to search timeline
-
-
-
-
-
-
-
-
-
- Displaying time
-
-
-
-
- Set timezone
-
-
- Browser default (UTC)
-
-
-
-
+ aria-label="Loading…"
+ class="mx_Spinner_icon"
+ data-testid="spinner"
+ role="progressbar"
+ style="width: 32px; height: 32px;"
+ />
+
+
+ The app will reload after selecting another language
-
-
-
- Show timestamps in 12 hour format (e.g. 2:30pm)
-
-
-
-
-
-
-
- Always show message timestamps
-
-
-
-
-
-
-
- Publish timezone on public profile
-
-
-
-
-
-
+
-
- Presence
-
-
-
- Share your activity and status with others.
-
-
-
-
-
-
- Send read receipts
-
-
-
+ Room list
+
-
-
- Send typing notifications
-
-
+
+
+ Show message previews
+
+
-
-
+
-
- Composer
-
-
-
-
-
- Automatically replace plain text Emoji
-
-
-
+ Spaces
+
-
-
- Enable Markdown
-
-
- Start messages with
-
- /plain
-
- to send without markdown.
+
+
+
+
+ Show all rooms in Home
+
+
+ All rooms you're in will appear in Home.
-
-
-
-
-
-
- Enable Emoji suggestions while typing
-
-
-
-
-
-
-
- Use Ctrl + Enter to send a message
-
-
-
-
-
-
-
- Surround selected text when typing special characters
-
-
-
-
-
-
-
- Show stickers button
-
-
-
-
-
-
-
- Insert a trailing colon after user mentions at the start of a message
-
-
-
-
-
+
-
- Code blocks
-
-
-
-
-
- Enable automatic language detection for syntax highlighting
-
-
+ Keyboard shortcuts
+
+
+
-
-
- Expand code blocks by default
-
-
-
-
-
-
- Show line numbers in code blocks
-
-
-
+ class="_inline-field-body_19upo_38"
+ >
+
+ Use Ctrl + F to search timeline
+
+
-
-
+
-
- Images, GIFs and videos
-
-
-
-
-
- Enable inline URL previews by default
-
-
-
+ Displaying time
+
-
-
-
-
- Autoplay videos
-
-
+
+
+ Show timestamps in 12 hour format (e.g. 2:30pm)
+
+
+
+
+
+
+
+ Always show message timestamps
+
+
+
+
+
+
+
+ Publish timezone on public profile
+
+
+ Requires your server to support MSC4133
+
+
-
-
+
-
- Timeline
-
+
+ Presence
+
+
+
+
+ Share your activity and status with others.
+
+
+
+
+
+
+
+ Send read receipts
+
+
+ Your server doesn't support disabling sending read receipts.
+
+
+
+
+
+
+
+ Send typing notifications
+
+
+
+
+
+
-
-
- Show typing notifications
-
-
-
+ Composer
+
-
-
- Show a placeholder for removed messages
-
-
+
+
+ Automatically replace plain text Emoji
+
+
-
-
-
-
- Show read receipts sent by other users
-
-
+
+
+ Enable Markdown
+
+
+
+ Start messages with
+
+ /plain
+
+ to send without markdown.
+
+
+
-
-
-
-
- Show join/leave messages (invites/removes/bans unaffected)
-
-
+
+
+ Enable Emoji suggestions while typing
+
+
-
-
-
-
- Show display name changes
-
-
+
+
+ Use Ctrl + Enter to send a message
+
+
-
-
-
-
- Show chat effects (animations when receiving e.g. confetti)
-
-
+
+
+ Surround selected text when typing special characters
+
+
-
-
-
-
- Show profile picture changes
-
-
+
+
+ Show stickers button
+
+
-
-
-
-
- Show avatars in user, room and event mentions
-
-
-
-
-
-
- Enable big emoji in chat
-
-
-
-
-
-
-
-
- Jump to the bottom of the timeline when you send a message
-
-
-
-
-
-
-
- Show current profile picture and name for users in message history
-
-
-
-
+
+
+
+
+
+ Code blocks
+
+
+
+
+
+
+
+ Enable automatic language detection for syntax highlighting
+
+
+
+
+
+
+
+ Expand code blocks by default
+
+
+
+
+
+
+
+ Show line numbers in code blocks
+
+
+
+
+
+
+
+
+
+
+ Images, GIFs and videos
+
+
+
+
+
+
+
+ Enable inline URL previews by default
+
+
+
+
+
+
+
+ Autoplay GIFs
+
+
+
+
+
+
+
+ Autoplay videos
+
+
+
+
+
+
+
+
+
+
+ Timeline
+
+
+
+
+
+
+
+ Show typing notifications
+
+
+
+
+
+
+
+ Show a placeholder for removed messages
+
+
+
+
+
+
+
+ Show read receipts sent by other users
+
+
+
+
+
+
+
+ Show join/leave messages (invites/removes/bans unaffected)
+
+
+
+
+
+
+
+ Show display name changes
+
+
+
+
+
+
+
+ Show chat effects (animations when receiving e.g. confetti)
+
+
+
+
+
+
+
+ Show profile picture changes
+
+
+
+
+
+
+
+ Show avatars in user, room and event mentions
+
+
+
+
+
+
+
+ Enable big emoji in chat
+
+
+
+
+
+
+
+ Jump to the bottom of the timeline when you send a message
+
+
+
+
+
+
+
+ Show current profile picture and name for users in message history
+
+
+
+
+
+
@@ -1171,28 +1402,34 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
class="_root_19upo_16 mx_MediaPreviewAccountSetting_Form"
>
+
+
Hide avatars of room and inviter
-
-
-
Show media in timeline
A hidden media can always be shown by tapping on it
@@ -1310,29 +1547,42 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
class="_root_19upo_16 mx_MediaPreviewAccountSetting_Form"
>
+
+
Allow users to invite you to rooms
-
-
-
@@ -1344,142 +1594,161 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
role="separator"
/>
-
-
- Room directory
-
-
-
-
-
- Show NSFW content
-
-
+ Room directory
+
+
+
+
+
+ Show NSFW content
+
+
-
-
+
diff --git a/test/unit-tests/components/views/settings/tabs/user/__snapshots__/SecurityUserSettingsTab-test.tsx.snap b/test/unit-tests/components/views/settings/tabs/user/__snapshots__/SecurityUserSettingsTab-test.tsx.snap
index 1f0a6cb75e..146277e9f2 100644
--- a/test/unit-tests/components/views/settings/tabs/user/__snapshots__/SecurityUserSettingsTab-test.tsx.snap
+++ b/test/unit-tests/components/views/settings/tabs/user/__snapshots__/SecurityUserSettingsTab-test.tsx.snap
@@ -34,8 +34,8 @@ exports[` renders security section 1`] = `
-
renders security section 1`] = `
(scalar.vector.im)
@@ -58,6 +59,7 @@ exports[`
renders security section 1`] = `
Use an integration manager
@@ -72,43 +74,39 @@ exports[` renders security section 1`] = `
>
Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.
-
-
-
- Enable the integration manager
-
+ class="_ui_udcm8_34"
+ />
-
-
+
+
+ Enable the integration manager
+
+
+
+
@@ -213,7 +211,7 @@ exports[`
renders security section 1`] = `
>
Enter a new identity server
@@ -222,7 +220,7 @@ exports[`
renders security section 1`] = `
>
", () => {
await toggleGuestAccessSection(component);
const guestAccessInput = getGuestAccessToggle(component);
- expect(guestAccessInput?.getAttribute("aria-checked")).toEqual("true");
+ expect(guestAccessInput).toBeChecked();
fireEvent.click(guestAccessInput!);
expect(mockMatrixClient.sendStateEvent).toHaveBeenCalledWith(
@@ -162,7 +162,7 @@ describe("
", () => {
);
// toggled off
- expect(guestAccessInput?.getAttribute("aria-checked")).toEqual("false");
+ expect(guestAccessInput).not.toBeChecked();
});
it("renders error message when update fails", async () => {
@@ -184,7 +184,7 @@ describe("
", () => {
await toggleGuestAccessSection(component);
- expect(getGuestAccessToggle(component)?.getAttribute("aria-disabled")).toEqual("true");
+ expect(getGuestAccessToggle(component)).toBeDisabled();
});
});
@@ -194,7 +194,7 @@ describe("
", () => {
const component = getComponent({ space });
// toggle off because space settings is != WorldReadable
- expect(getHistoryVisibilityToggle(component)?.getAttribute("aria-checked")).toEqual("false");
+ expect(getHistoryVisibilityToggle(component)).not.toBeChecked();
});
it("updates history visibility on toggle", () => {
@@ -202,7 +202,7 @@ describe("
", () => {
const component = getComponent({ space });
// toggle off because space settings is != WorldReadable
- expect(getHistoryVisibilityToggle(component)?.getAttribute("aria-checked")).toEqual("false");
+ expect(getHistoryVisibilityToggle(component)).not.toBeChecked();
fireEvent.click(getHistoryVisibilityToggle(component)!);
expect(mockMatrixClient.sendStateEvent).toHaveBeenCalledWith(
@@ -212,7 +212,7 @@ describe("
", () => {
"",
);
- expect(getHistoryVisibilityToggle(component)?.getAttribute("aria-checked")).toEqual("true");
+ expect(getHistoryVisibilityToggle(component)).toBeChecked();
});
it("renders error message when history update fails", async () => {
@@ -231,7 +231,7 @@ describe("
", () => {
const space = makeMockSpace(mockMatrixClient, joinRule, guestRule, historyRule);
(space.currentState.maySendStateEvent as jest.Mock).mockReturnValue(false);
const component = getComponent({ space });
- expect(getHistoryVisibilityToggle(component)?.getAttribute("aria-disabled")).toEqual("true");
+ expect(getHistoryVisibilityToggle(component)).toBeDisabled();
});
});
diff --git a/test/unit-tests/components/views/spaces/__snapshots__/SpaceSettingsVisibilityTab-test.tsx.snap b/test/unit-tests/components/views/spaces/__snapshots__/SpaceSettingsVisibilityTab-test.tsx.snap
index 88fd7fcf6f..22ef6a657d 100644
--- a/test/unit-tests/components/views/spaces/__snapshots__/SpaceSettingsVisibilityTab-test.tsx.snap
+++ b/test/unit-tests/components/views/spaces/__snapshots__/SpaceSettingsVisibilityTab-test.tsx.snap
@@ -1,18 +1,13 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`
for a public space Access renders guest access section toggle 1`] = `
-
+ type="checkbox"
+/>
`;
exports[`
renders container 1`] = `
@@ -112,42 +107,53 @@ exports[`
renders container 1`] = `
>
Anyone can find and join.
-
- Allow people to preview your space before they join.
-
Recommended for public spaces.
-
+