Various fixes to components for tests.

This commit is contained in:
Half-Shot 2025-07-09 08:44:23 +01:00
parent 7df3b45ee3
commit c81d600307
22 changed files with 535 additions and 424 deletions

View File

@ -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;

View File

@ -98,7 +98,12 @@ const DevtoolsDialog: React.FC<IProps> = ({ roomId, threadRootId, onFinished })
})}
</div>
))}
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
<h3>{_t("common|options")}</h3>
<SettingsFlag name="developerMode" level={SettingLevel.ACCOUNT} />
<SettingsFlag name="showHiddenEventsInTimeline" level={SettingLevel.DEVICE} />

View File

@ -104,7 +104,12 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
let inviteToggle: JSX.Element | undefined;
if (this.isInviteOrKnockRoom) {
inviteToggle = (
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
<SettingsToggleInput
name="room-upgrade-warning"
checked={this.state.inviteUsersToNewRoom}

View File

@ -85,7 +85,12 @@ export default class WidgetOpenIDPermissionsDialog extends React.PureComponent<I
onPrimaryButtonClick={this.onAllow}
onCancel={this.onDeny}
additive={
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
<SettingsToggleInput
name="remember-selection"
checked={this.state.rememberSelection}

View File

@ -111,15 +111,26 @@ export default class SettingsFlag extends React.Component<IProps, IState> {
},
)
: description;
if (this.props.name === "sendReadReceipts") {
console.log(
"Fully disabled",
this.props.name,
SettingsStore.disabledMessage(this.props.name),
description,
helpMessage,
);
}
const disabledMessage = SettingsStore.disabledMessage(this.props.name);
return (
<SettingsToggleInput
id={this.id}
checked={this.state.value}
onChange={this.onChange}
onChange={disabledMessage ? undefined : this.onChange}
name={this.props.name}
disabled={disabled}
label={label ?? this.props.name}
helpMessage={helpMessage as string}
disabledMessage={SettingsStore.disabledMessage(this.props.name)}
disabledMessage={disabledMessage}
/>
);
}

View File

@ -36,6 +36,8 @@ export const EnableLiveShare: React.FC<Props> = ({ onSubmit }) => {
[isEnabled, onSubmit],
);
console.log("EnableLiveShare", isEnabled);
return (
<div data-testid="location-picker-enable-live-share" className="mx_EnableLiveShare">
<StyledLiveBeaconIcon className="mx_EnableLiveShare_icon" />
@ -50,12 +52,7 @@ export const EnableLiveShare: React.FC<Props> = ({ onSubmit }) => {
onChange={onEnabledChanged}
label={_t("location_sharing|live_toggle_label")}
/>
<Button
data-testid="enable-live-share-submit"
className="mx_EnableLiveShare_button"
kind="primary"
disabled={!isEnabled}
>
<Button className="mx_EnableLiveShare_button" kind="primary" disabled={!isEnabled}>
{_t("action|ok")}
</Button>
</Form.Root>

View File

@ -9,13 +9,13 @@ Please see LICENSE files in the repository root for full details.
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 { _t } from "../../../languageHandler";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import DirectoryCustomisations from "../../../customisations/Directory";
import Modal from "../../../Modal";
import ErrorDialog from "../dialogs/ErrorDialog";
import { logger } from "matrix-js-sdk/src/logger";
interface IProps {
roomId: string;

View File

@ -191,7 +191,12 @@ const maximumVectorState = (
const NotificationActivitySettings = (): JSX.Element => {
return (
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
<SettingsFlag name="Notifications.showbold" level={SettingLevel.DEVICE} />
<SettingsFlag name="Notifications.tac_only_notifications" level={SettingLevel.DEVICE} />
</Form.Root>
@ -815,7 +820,12 @@ export default class Notifications extends React.PureComponent<EmptyObject, ISta
}
return (
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
{this.renderTopSection()}
{this.renderCategory(RuleClass.VectorGlobal)}
{this.renderCategory(RuleClass.VectorMentions)}

View File

@ -66,11 +66,20 @@ export default class SetIntegrationManager extends React.Component<EmptyObject,
if (!SettingsStore.getValue(UIFeature.Widgets)) return null;
return (
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}} className="mx_SetIntegrationManager" data-testid="mx_SetIntegrationManager">
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
className="mx_SetIntegrationManager"
data-testid="mx_SetIntegrationManager"
>
<div className="mx_SettingsFlag">
<div className="mx_SetIntegrationManager_heading_manager">
<Heading size="3">{_t("integration_manager|manage_title")}</Heading>
<Heading id="mx_SetIntegrationManager_ManagerName" size="4">{managerName}</Heading>
<Heading id="mx_SetIntegrationManager_ManagerName" size="4">
{managerName}
</Heading>
</div>
</div>
<SettingsSubsectionText id="mx_SetIntegrationManager_BodyText">{bodyText}</SettingsSubsectionText>

View File

@ -93,7 +93,6 @@ export default function NotificationSettings2(): JSX.Element {
return (
<div className="mx_NotificationSettings2">
{hasPendingChanges && model !== null && (
<SettingsBanner
icon={<img src={NewAndImprovedIcon} alt="" width={12} />}
@ -111,252 +110,257 @@ export default function NotificationSettings2(): JSX.Element {
</SettingsBanner>
)}
<SettingsSection>
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<div className="mx_SettingsSubsection_content mx_NotificationSettings2_flags">
<SettingsToggleInput
name="enable_notifications_account"
label={_t("settings|notifications|enable_notifications_account")}
checked={!settings.globalMute}
disabled={disabled}
onChange={(evt) => {
reconcile({
...model!,
globalMute: !evt.target.checked,
});
}}
/>
<SettingsFlag name="notificationsEnabled" level={SettingLevel.DEVICE} />
<SettingsFlag name="notificationBodyEnabled" level={SettingLevel.DEVICE} />
<SettingsFlag name="audioNotificationsEnabled" level={SettingLevel.DEVICE} />
</div>
<SettingsSubsection
heading={_t("settings|notifications|default_setting_section")}
description={_t("settings|notifications|default_setting_description")}
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
<StyledRadioGroup
name="defaultNotificationLevel"
value={toDefaultLevels(settings.defaultLevels)}
disabled={disabled}
definitions={NotificationOptions}
onChange={(value) => {
reconcile({
...model!,
defaultLevels: {
...model!.defaultLevels,
dm:
value !== NotificationDefaultLevels.MentionsKeywords
? RoomNotifState.AllMessages
: RoomNotifState.MentionsOnly,
room:
value === NotificationDefaultLevels.AllMessages
? RoomNotifState.AllMessages
: RoomNotifState.MentionsOnly,
},
});
}}
/>
</SettingsSubsection>
<SettingsSubsection
heading={_t("settings|notifications|play_sound_for_section")}
description={_t("settings|notifications|play_sound_for_description")}
>
<LabelledCheckbox
label={_t("common|people")}
value={settings.sound.people !== undefined}
disabled={disabled || settings.defaultLevels.dm === RoomNotifState.MentionsOnly}
onChange={(value) => {
reconcile({
...model!,
sound: {
...model!.sound,
people: value ? "default" : undefined,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|mentions_keywords")}
value={settings.sound.mentions !== undefined}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
sound: {
...model!.sound,
mentions: value ? "default" : undefined,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|voip")}
value={settings.sound.calls !== undefined}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
sound: {
...model!.sound,
calls: value ? "ring" : undefined,
},
});
}}
/>
</SettingsSubsection>
<SettingsSubsection heading={_t("settings|notifications|other_section")}>
<LabelledCheckbox
label={_t("settings|notifications|invites")}
value={settings.activity.invite}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
activity: {
...model!.activity,
invite: value,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|room_activity")}
value={settings.activity.status_event}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
activity: {
...model!.activity,
status_event: value,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|notices")}
value={settings.activity.bot_notices}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
activity: {
...model!.activity,
bot_notices: value,
},
});
}}
/>
</SettingsSubsection>
<SettingsSubsection
heading={_t("settings|notifications|mentions_keywords")}
description={_t(
"settings|notifications|keywords",
{},
{
badge: (
<StatelessNotificationBadge
symbol="1"
count={1}
level={NotificationLevel.Notification}
/>
),
},
)}
>
<LabelledCheckbox
label={_t("settings|notifications|notify_at_room")}
value={settings.mentions.room}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
mentions: {
...model!.mentions,
room: value,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|notify_mention", {
mxid: cli.getUserId()!,
})}
id="mx_NotificationSettings2_MentionCheckbox"
value={settings.mentions.user}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
mentions: {
...model!.mentions,
user: value,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|notify_keyword")}
byline={_t("settings|notifications|keywords_prompt")}
value={settings.mentions.keywords}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
mentions: {
...model!.mentions,
keywords: value,
},
});
}}
/>
<TagComposer
id="mx_NotificationSettings2_Keywords"
tags={model?.keywords ?? []}
disabled={disabled}
onAdd={(keyword) => {
reconcile({
...model!,
keywords: [keyword, ...model!.keywords],
});
}}
onRemove={(keyword) => {
reconcile({
...model!,
keywords: model!.keywords.filter((it) => it !== keyword),
});
}}
label={_t("notifications|keyword")}
placeholder={_t("notifications|keyword_new")}
/>
<div className="mx_SettingsSubsection_content mx_NotificationSettings2_flags">
<SettingsToggleInput
name="enable_notifications_account"
label={_t("settings|notifications|enable_notifications_account")}
checked={!settings.globalMute}
disabled={disabled}
onChange={(evt) => {
reconcile({
...model!,
globalMute: !evt.target.checked,
});
}}
/>
<SettingsFlag name="notificationsEnabled" level={SettingLevel.DEVICE} />
<SettingsFlag name="notificationBodyEnabled" level={SettingLevel.DEVICE} />
<SettingsFlag name="audioNotificationsEnabled" level={SettingLevel.DEVICE} />
</div>
<SettingsSubsection
heading={_t("settings|notifications|default_setting_section")}
description={_t("settings|notifications|default_setting_description")}
>
<StyledRadioGroup
name="defaultNotificationLevel"
value={toDefaultLevels(settings.defaultLevels)}
disabled={disabled}
definitions={NotificationOptions}
onChange={(value) => {
reconcile({
...model!,
defaultLevels: {
...model!.defaultLevels,
dm:
value !== NotificationDefaultLevels.MentionsKeywords
? RoomNotifState.AllMessages
: RoomNotifState.MentionsOnly,
room:
value === NotificationDefaultLevels.AllMessages
? RoomNotifState.AllMessages
: RoomNotifState.MentionsOnly,
},
});
}}
/>
</SettingsSubsection>
<SettingsSubsection
heading={_t("settings|notifications|play_sound_for_section")}
description={_t("settings|notifications|play_sound_for_description")}
>
<LabelledCheckbox
label={_t("common|people")}
value={settings.sound.people !== undefined}
disabled={disabled || settings.defaultLevels.dm === RoomNotifState.MentionsOnly}
onChange={(value) => {
reconcile({
...model!,
sound: {
...model!.sound,
people: value ? "default" : undefined,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|mentions_keywords")}
value={settings.sound.mentions !== undefined}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
sound: {
...model!.sound,
mentions: value ? "default" : undefined,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|voip")}
value={settings.sound.calls !== undefined}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
sound: {
...model!.sound,
calls: value ? "ring" : undefined,
},
});
}}
/>
</SettingsSubsection>
<SettingsSubsection heading={_t("settings|notifications|other_section")}>
<LabelledCheckbox
label={_t("settings|notifications|invites")}
value={settings.activity.invite}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
activity: {
...model!.activity,
invite: value,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|room_activity")}
value={settings.activity.status_event}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
activity: {
...model!.activity,
status_event: value,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|notices")}
value={settings.activity.bot_notices}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
activity: {
...model!.activity,
bot_notices: value,
},
});
}}
/>
</SettingsSubsection>
<SettingsSubsection
heading={_t("settings|notifications|mentions_keywords")}
description={_t(
"settings|notifications|keywords",
{},
{
badge: (
<StatelessNotificationBadge
symbol="1"
count={1}
level={NotificationLevel.Notification}
/>
),
},
)}
>
<LabelledCheckbox
label={_t("settings|notifications|notify_at_room")}
value={settings.mentions.room}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
mentions: {
...model!.mentions,
room: value,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|notify_mention", {
mxid: cli.getUserId()!,
})}
id="mx_NotificationSettings2_MentionCheckbox"
value={settings.mentions.user}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
mentions: {
...model!.mentions,
user: value,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|notify_keyword")}
byline={_t("settings|notifications|keywords_prompt")}
value={settings.mentions.keywords}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
mentions: {
...model!.mentions,
keywords: value,
},
});
}}
/>
<TagComposer
id="mx_NotificationSettings2_Keywords"
tags={model?.keywords ?? []}
disabled={disabled}
onAdd={(keyword) => {
reconcile({
...model!,
keywords: [keyword, ...model!.keywords],
});
}}
onRemove={(keyword) => {
reconcile({
...model!,
keywords: model!.keywords.filter((it) => it !== keyword),
});
}}
label={_t("notifications|keyword")}
placeholder={_t("notifications|keyword_new")}
/>
<SettingsFlag name="Notifications.showbold" level={SettingLevel.DEVICE} />
<SettingsFlag name="Notifications.tac_only_notifications" level={SettingLevel.DEVICE} />
</SettingsSubsection>
<NotificationPusherSettings />
<SettingsSubsection heading={_t("settings|notifications|quick_actions_section")}>
{hasUnreadNotifications && (
<SettingsFlag name="Notifications.showbold" level={SettingLevel.DEVICE} />
<SettingsFlag name="Notifications.tac_only_notifications" level={SettingLevel.DEVICE} />
</SettingsSubsection>
<NotificationPusherSettings />
<SettingsSubsection heading={_t("settings|notifications|quick_actions_section")}>
{hasUnreadNotifications && (
<AccessibleButton
kind="primary_outline"
disabled={updatingUnread}
onClick={async () => {
setUpdatingUnread(true);
await clearAllNotifications(cli);
setUpdatingUnread(false);
}}
>
{_t("settings|notifications|quick_actions_mark_all_read")}
</AccessibleButton>
)}
<AccessibleButton
kind="primary_outline"
disabled={updatingUnread}
onClick={async () => {
setUpdatingUnread(true);
await clearAllNotifications(cli);
setUpdatingUnread(false);
kind="danger_outline"
disabled={model === null}
onClick={() => {
reconcile(DefaultNotificationSettings);
}}
>
{_t("settings|notifications|quick_actions_mark_all_read")}
{_t("settings|notifications|quick_actions_reset")}
</AccessibleButton>
)}
<AccessibleButton
kind="danger_outline"
disabled={model === null}
onClick={() => {
reconcile(DefaultNotificationSettings);
}}
>
{_t("settings|notifications|quick_actions_reset")}
</AccessibleButton>
</SettingsSubsection>
</SettingsSubsection>
</Form.Root>
</SettingsSection>
</div>

View File

@ -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<HTMLDivElement>
* @default true
*/
legacy?: boolean;
/**
* Wrap in a Form Root component, for compatibility with compound components.
*/
formWrap?: boolean;
}
export const SettingsSubsectionText: React.FC<HTMLAttributes<HTMLDivElement>> = ({ children, ...rest }) => (
@ -37,31 +42,48 @@ export const SettingsSubsection: React.FC<SettingsSubsectionProps> = ({
children,
stretchContent,
legacy = true,
formWrap,
...rest
}) => (
<div
{...rest}
className={classNames("mx_SettingsSubsection", {
mx_SettingsSubsection_newUi: !legacy,
})}
>
{typeof heading === "string" ? <SettingsSubsectionHeading heading={heading} /> : <>{heading}</>}
{!!description && (
<div className="mx_SettingsSubsection_description">
<SettingsSubsectionText>{description}</SettingsSubsectionText>
</div>
)}
{!!children && (
<div
className={classNames("mx_SettingsSubsection_content", {
mx_SettingsSubsection_contentStretch: !!stretchContent,
mx_SettingsSubsection_noHeading: !heading && !description,
mx_SettingsSubsection_content_newUi: !legacy,
})}
}) => {
const content = (
<div
{...rest}
className={classNames("mx_SettingsSubsection", {
mx_SettingsSubsection_newUi: !legacy,
})}
>
{typeof heading === "string" ? <SettingsSubsectionHeading heading={heading} /> : <>{heading}</>}
{!!description && (
<div className="mx_SettingsSubsection_description">
<SettingsSubsectionText>{description}</SettingsSubsectionText>
</div>
)}
{!!children && (
<div
className={classNames("mx_SettingsSubsection_content", {
mx_SettingsSubsection_contentStretch: !!stretchContent,
mx_SettingsSubsection_noHeading: !heading && !description,
mx_SettingsSubsection_content_newUi: !legacy,
})}
>
{children}
</div>
)}
{!legacy && <Separator />}
</div>
);
if (formWrap) {
return (
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
{children}
</div>
)}
{!legacy && <Separator />}
</div>
);
{content}
</Form.Root>
);
}
return content;
};

View File

@ -7,7 +7,6 @@ Please see LICENSE files in the repository root for full details.
*/
import React, { type HTMLAttributes } from "react";
import classNames from "classnames";
import { Form } from "@vector-im/compound-web";
export interface SettingsTabProps extends HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
@ -37,7 +36,6 @@ export interface SettingsTabProps extends HTMLAttributes<HTMLDivElement> {
*/
const SettingsTab: React.FC<SettingsTabProps> = ({ children, className, ...rest }) => (
<div {...rest} className={classNames("mx_SettingsTab", className)}>
{/* Prevent settings from doing any accidental submits. */}
<div className="mx_SettingsTab_sections">{children}</div>
</div>
);

View File

@ -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";
@ -23,7 +24,6 @@ import SettingsTab from "../SettingsTab";
import { SettingsSection } from "../../shared/SettingsSection";
import { UrlPreviewSettings } from "../../../room_settings/UrlPreviewSettings";
import { MediaPreviewAccountSettings } from "../user/MediaPreviewAccountSettings";
import { Form } from "@vector-im/compound-web";
interface IProps {
room: Room;
@ -79,7 +79,12 @@ export default class GeneralRoomSettingsTab extends React.Component<IProps, ISta
return (
<SettingsTab data-testid="General">
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
<SettingsSection heading={_t("common|general")}>
<RoomProfileSettings roomId={room.roomId} />
</SettingsSection>

View File

@ -446,35 +446,40 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
return (
<SettingsTab>
<SettingsSection heading={_t("room_settings|security|title")}>
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<SettingsFieldset
legend={_t("settings|security|encryption_section")}
description={
isEncryptionForceDisabled && !isEncrypted
? undefined
: _t("room_settings|security|encryption_permanent")
}
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
{isEncryptionLoading ? (
<InlineSpinner />
) : (
<>
<SettingsToggleInput
name="enable-encryption"
checked={isEncrypted}
onChange={this.onEncryptionChange}
label={_t("common|encrypted")}
disabled={!canEnableEncryption}
/>
{isEncryptionForceDisabled && !isEncrypted && (
<Caption>{_t("room_settings|security|encryption_forced")}</Caption>
)}
{encryptionSettings}
</>
)}
</SettingsFieldset>
{this.renderJoinRule()}
{historySection}
<SettingsFieldset
legend={_t("settings|security|encryption_section")}
description={
isEncryptionForceDisabled && !isEncrypted
? undefined
: _t("room_settings|security|encryption_permanent")
}
>
{isEncryptionLoading ? (
<InlineSpinner />
) : (
<>
<SettingsToggleInput
name="enable-encryption"
checked={isEncrypted}
onChange={this.onEncryptionChange}
label={_t("common|encrypted")}
disabled={!canEnableEncryption}
/>
{isEncryptionForceDisabled && !isEncrypted && (
<Caption>{_t("room_settings|security|encryption_forced")}</Caption>
)}
{encryptionSettings}
</>
)}
</SettingsFieldset>
{this.renderJoinRule()}
{historySection}
</Form.Root>
</SettingsSection>
</SettingsTab>

View File

@ -76,6 +76,7 @@ const ElementCallSwitch: React.FC<ElementCallSwitchProps> = ({ room }) => {
return (
<SettingsToggleInput
name="element-call-switch"
data-test-id="element-call-switch"
label={_t("room_settings|voip|enable_element_call_label", { brand })}
helpMessage={_t("room_settings|voip|enable_element_call_caption", {
brand,
@ -96,7 +97,12 @@ export const VoipRoomSettingsTab: React.FC<Props> = ({ room }) => {
return (
<SettingsTab>
<SettingsSection heading={_t("settings|voip|title")}>
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
<SettingsSubsection heading={_t("room_settings|voip|call_type_section")}>
<ElementCallSwitch room={room} />
</SettingsSubsection>

View File

@ -9,6 +9,7 @@ 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 SettingsStore from "../../../../../settings/SettingsStore";
@ -24,7 +25,6 @@ import ImageSizePanel from "../../ImageSizePanel";
import SettingsTab from "../SettingsTab";
import { SettingsSection } from "../../shared/SettingsSection";
import { SettingsSubsection } from "../../shared/SettingsSubsection";
import { Form } from "@vector-im/compound-web";
interface IState {
useBundledEmojiFont: boolean;
@ -103,7 +103,12 @@ export default class AppearanceUserSettingsTab extends React.Component<EmptyObje
return (
<SettingsTab data-testid="mx_AppearanceUserSettingsTab">
<SettingsSection>
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
<ThemeChoicePanel />
<LayoutSwitcher />
<FontScalingPanel />

View File

@ -32,7 +32,13 @@ export const InviteRulesAccountSetting: FC = () => {
}
}, []);
return (
<Root className="mx_MediaPreviewAccountSetting_Form" onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<Root
className="mx_MediaPreviewAccountSetting_Form"
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
<SettingsToggleInput
className="mx_MediaPreviewAccountSetting_ToggleSwitch"
name="invite_control_blocked"

View File

@ -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";
@ -20,7 +21,6 @@ import { EnhancedMap } from "../../../../../utils/maps";
import { SettingsSection } from "../../shared/SettingsSection";
import { SettingsSubsection, SettingsSubsectionText } from "../../shared/SettingsSubsection";
import SettingsTab from "../SettingsTab";
import { Form } from "@vector-im/compound-web";
export const showLabsFlags = (): boolean => {
return SdkConfig.get("show_labs_settings") || SettingsStore.getValue("developerMode");
@ -107,38 +107,43 @@ export default class LabsUserSettingsTab extends React.Component<EmptyObject> {
return (
<SettingsTab>
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<SettingsSection heading={_t("labs|beta_section")}>
<SettingsSubsectionText>
{_t("labs|beta_description", { brand: SdkConfig.get("brand") })}
</SettingsSubsectionText>
{betaSection}
</SettingsSection>
{labsSections && (
<SettingsSection heading={_t("labs|experimental_section")}>
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
<SettingsSection heading={_t("labs|beta_section")}>
<SettingsSubsectionText>
{_t(
"labs|experimental_description",
{},
{
a: (sub) => {
return (
<a
href="https://github.com/vector-im/element-web/blob/develop/docs/labs.md"
rel="noreferrer noopener"
target="_blank"
>
{sub}
</a>
);
},
},
)}
{_t("labs|beta_description", { brand: SdkConfig.get("brand") })}
</SettingsSubsectionText>
{labsSections}
{betaSection}
</SettingsSection>
)}
{labsSections && (
<SettingsSection heading={_t("labs|experimental_section")}>
<SettingsSubsectionText>
{_t(
"labs|experimental_description",
{},
{
a: (sub) => {
return (
<a
href="https://github.com/vector-im/element-web/blob/develop/docs/labs.md"
rel="noreferrer noopener"
target="_blank"
>
{sub}
</a>
);
},
},
)}
</SettingsSubsectionText>
{labsSections}
</SettingsSection>
)}
</Form.Root>
</SettingsTab>
);

View File

@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
*/
import React, { type ChangeEventHandler, type JSX, type ReactElement, useCallback, useEffect, useState } from "react";
import { Form, SettingsToggleControl } from "@vector-im/compound-web";
import { Form, SettingsToggleInput } from "@vector-im/compound-web";
import { type NonEmptyArray } from "../../../../../@types/common";
import { _t, getCurrentLanguage } from "../../../../../languageHandler";
@ -105,12 +105,14 @@ const SpellCheckSection: React.FC = () => {
return (
<>
<SettingsToggleControl
label={_t("settings|general|allow_spellcheck")}
name="spell_check"
checked={Boolean(spellCheckEnabled)}
onChange={onSpellCheckEnabledChange}
/>
<Form.Root>
<SettingsToggleInput
label={_t("settings|general|allow_spellcheck")}
name="spell_check"
checked={Boolean(spellCheckEnabled)}
onChange={onSpellCheckEnabledChange}
/>
</Form.Root>
{spellCheckEnabled && spellCheckLanguages !== undefined && !IS_MAC && (
<SpellCheckSettings languages={spellCheckLanguages} onLanguagesChange={onSpellCheckLanguagesChange} />
)}
@ -258,15 +260,13 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
return (
<SettingsTab data-testid="mx_PreferencesUserSettingsTab">
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<SettingsSection>
{/* The heading string is still 'general' from where it was moved, but this section should become 'general' */}
<SettingsSubsection heading={_t("settings|general|language_section")}>
<LanguageSection />
<SpellCheckSection />
</SettingsSubsection>
<SettingsSubsection heading={_t("settings|preferences|room_list_heading")}>
<SettingsSubsection formWrap heading={_t("settings|preferences|room_list_heading")}>
{this.renderGroup(PreferencesUserSettingsTab.ROOM_LIST_SETTINGS)}
{/* The settings is on device level where the other room list settings are on account level */}
{newRoomListEnabled && (
@ -274,12 +274,13 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
)}
</SettingsSubsection>
<SettingsSubsection heading={_t("common|spaces")}>
<SettingsSubsection formWrap heading={_t("common|spaces")}>
{this.renderGroup(PreferencesUserSettingsTab.SPACES_SETTINGS, SettingLevel.ACCOUNT)}
</SettingsSubsection>
<SettingsSubsection
heading={_t("settings|preferences|keyboard_heading")}
formWrap
description={_t(
"settings|preferences|keyboard_view_shortcuts_button",
{},
@ -295,7 +296,7 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
{this.renderGroup(PreferencesUserSettingsTab.KEYBINDINGS_SETTINGS)}
</SettingsSubsection>
<SettingsSubsection heading={_t("settings|preferences|time_heading")}>
<SettingsSubsection heading={_t("settings|preferences|time_heading")} formWrap>
<div className="mx_SettingsSubsection_dropdown">
{_t("settings|preferences|user_timezone")}
<Dropdown
@ -318,38 +319,39 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
</SettingsSubsection>
<SettingsSubsection
formWrap
heading={_t("common|presence")}
description={_t("settings|preferences|presence_description")}
>
{this.renderGroup(PreferencesUserSettingsTab.PRESENCE_SETTINGS)}
</SettingsSubsection>
<SettingsSubsection heading={_t("settings|preferences|composer_heading")}>
<SettingsSubsection formWrap heading={_t("settings|preferences|composer_heading")}>
{this.renderGroup(PreferencesUserSettingsTab.COMPOSER_SETTINGS)}
</SettingsSubsection>
<SettingsSubsection heading={_t("settings|preferences|code_blocks_heading")}>
<SettingsSubsection formWrap heading={_t("settings|preferences|code_blocks_heading")}>
{this.renderGroup(PreferencesUserSettingsTab.CODE_BLOCKS_SETTINGS)}
</SettingsSubsection>
<SettingsSubsection heading={_t("settings|preferences|media_heading")}>
<SettingsSubsection formWrap heading={_t("settings|preferences|media_heading")}>
{this.renderGroup(PreferencesUserSettingsTab.IMAGES_AND_VIDEOS_SETTINGS)}
</SettingsSubsection>
<SettingsSubsection heading={_t("common|timeline")}>
<SettingsSubsection formWrap heading={_t("common|timeline")}>
{this.renderGroup(PreferencesUserSettingsTab.TIMELINE_SETTINGS)}
</SettingsSubsection>
<SettingsSubsection heading={_t("common|moderation_and_safety")} legacy={false}>
<SettingsSubsection formWrap heading={_t("common|moderation_and_safety")} legacy={false}>
<MediaPreviewAccountSettings />
<InviteRulesAccountSetting />
</SettingsSubsection>
<SettingsSubsection heading={_t("settings|preferences|room_directory_heading")}>
<SettingsSubsection formWrap heading={_t("settings|preferences|room_directory_heading")}>
{this.renderGroup(PreferencesUserSettingsTab.ROOM_DIRECTORY_SETTINGS)}
</SettingsSubsection>
<SettingsSubsection heading={_t("common|general")} stretchContent>
<SettingsSubsection formWrap heading={_t("common|general")} stretchContent>
{this.renderGroup(PreferencesUserSettingsTab.GENERAL_SETTINGS)}
<SettingsFlag name="Electron.showTrayIcon" level={SettingLevel.PLATFORM} hideIfCannotSet />
@ -391,7 +393,6 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
/>
</SettingsSubsection>
</SettingsSection>
</Form.Root>
</SettingsTab>
);
}

View File

@ -11,6 +11,7 @@ import { sleep } from "matrix-js-sdk/src/utils";
import { type Room, RoomEvent, type IServerVersions } from "matrix-js-sdk/src/matrix";
import { KnownMembership, type Membership } from "matrix-js-sdk/src/types";
import { logger } from "matrix-js-sdk/src/logger";
import { Form } from "@vector-im/compound-web";
import { _t } from "../../../../../languageHandler";
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
@ -32,7 +33,6 @@ import { SettingsSubsection, SettingsSubsectionText } from "../../shared/Setting
import { useOwnDevices } from "../../devices/useOwnDevices";
import { DiscoverySettings } from "../../discovery/DiscoverySettings";
import SetIntegrationManager from "../../SetIntegrationManager";
import { Form } from "@vector-im/compound-web";
interface IIgnoredUserProps {
userId: string;
@ -356,21 +356,31 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
return (
<SettingsTab>
{warning}
<SetIntegrationManager />
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<SettingsSection heading={_t("settings|security|encryption_section")}>
{secureBackup}
{eventIndex}
</SettingsSection>
</Form.Root>
<SettingsSection heading={_t("common|privacy")}>
<DiscoverySettings />
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
{posthogSection}
</Form.Root>
{warning}
<SetIntegrationManager />
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
<SettingsSection heading={_t("settings|security|encryption_section")}>
{secureBackup}
{eventIndex}
</SettingsSection>
{advancedSection}
</Form.Root>
<SettingsSection heading={_t("common|privacy")}>
<DiscoverySettings />
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
{posthogSection}
</Form.Root>
</SettingsSection>
{advancedSection}
</SettingsTab>
);
}

View File

@ -187,7 +187,12 @@ export default class VoiceUserSettingsTab extends React.Component<EmptyObject, I
return (
<SettingsTab>
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
<SettingsSection>
{requestButton}
<SettingsSubsection heading={_t("settings|voip|voice_section")} stretchContent>

View File

@ -108,17 +108,15 @@ const SpaceSettingsVisibilityTab: React.FC<IProps> = ({ matrixClient: cli, space
</AccessibleButton>
{showAdvancedSection && (
<div className="mx_SettingsTab_toggleWithDescription">
<SettingsToggleInput
name="guest-access-enabled"
checked={guestAccessEnabled}
onChange={onGuestAccessEnabledChanged}
disabled={!canSetGuestAccess}
disabledMessage={_t("room_settings|visibility|guest_access_disabled")}
helpMessage={_t("room_settings|visibility|guest_access_explainer")}
label={_t("room_settings|visibility|guest_access_label")}
/>
</div>
<SettingsToggleInput
name="guest-access-enabled"
checked={guestAccessEnabled}
onChange={onGuestAccessEnabledChanged}
disabled={!canSetGuestAccess}
disabledMessage={_t("room_settings|visibility|guest_access_disabled")}
helpMessage={_t("room_settings|visibility|guest_access_explainer")}
label={_t("room_settings|visibility|guest_access_label")}
/>
)}
</div>
);
@ -158,29 +156,32 @@ const SpaceSettingsVisibilityTab: React.FC<IProps> = ({ matrixClient: cli, space
onError={(): void => setError(_t("room_settings|visibility|error_failed_save"))}
closeSettingsFn={closeSettingsFn}
/>
{advancedSection}
<div className="mx_SettingsTab_toggleWithDescription">
<Form.Root onSubmit={(evt) => {evt.preventDefault(); evt.stopPropagation();}}>
<SettingsToggleInput
name="space-history-visibility"
checked={historyVisibility === HistoryVisibility.WorldReadable}
onChange={(evt): void => {
setHistoryVisibility(
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")}
/>
<p>
<strong>
{_t("room_settings|visibility|history_visibility_anyone_space_recommendation")}
</strong>
</p>
</Form.Root>
</div>
<Form.Root
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
{advancedSection}
<SettingsToggleInput
name="space-history-visibility"
checked={historyVisibility === HistoryVisibility.WorldReadable}
onChange={(evt): void => {
setHistoryVisibility(
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")}
/>
<p>
<strong>
{_t("room_settings|visibility|history_visibility_anyone_space_recommendation")}
</strong>
</p>
</Form.Root>
</SettingsFieldset>
{addressesSection}