Compare commits

...

3 Commits

Author SHA1 Message Date
Half-Shot
d213a226b0 Tweak to not use js-sdk 2025-03-27 14:29:58 +00:00
Half-Shot
794695a8c7 copyright 2025-03-27 14:21:20 +00:00
Half-Shot
a1d72ea2ed Add settings for MSC4155 2025-03-27 14:18:49 +00:00
5 changed files with 108 additions and 1 deletions

View File

@@ -15,6 +15,8 @@ import type { EmptyObject } from "matrix-js-sdk/src/matrix";
import type { DeviceClientInformation } from "../utils/device/types.ts";
import type { UserWidget } from "../utils/WidgetUtils-types.ts";
type InviteConfigAccountDataRule = "allow" | "block";
// Extend Matrix JS SDK types via Typescript declaration merging to support unspecced event fields and types
declare module "matrix-js-sdk/src/types" {
export interface FileInfo {
@@ -60,6 +62,21 @@ declare module "matrix-js-sdk/src/types" {
};
}
export interface InviteConfigAccountData {
/**
* Rule exceptions for users. Takes priority over `default` and `server_exceptions`.
*/
user_exceptions: Record<string, InviteConfigAccountDataRule>;
/**
* Rule exceptions for users. Takes priority over `default`.
*/
server_exceptions: Record<string, InviteConfigAccountDataRule>;
/**
* The default rule for invite handling when no exceptions match.
*/
default: InviteConfigAccountDataRule;
}
export interface AccountDataEvents {
// Analytics account data event
"im.vector.analytics": {
@@ -87,6 +104,9 @@ declare module "matrix-js-sdk/src/types" {
"m.accepted_terms": {
accepted: string[];
};
// MSC4155: Invite filtering
"org.matrix.msc4155.invite_permission_config": InviteConfigAccountData;
}
export interface AudioContent {

View File

@@ -0,0 +1,62 @@
/*
Copyright 2025 New Vector 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, { type ChangeEventHandler, type FC, useCallback, useState } from "react";
import { type AccountDataEvents } from "matrix-js-sdk/src/types";
import { ErrorMessage, InlineField, Label, Root, ToggleInput } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger";
import { SettingsSubsection } from "./shared/SettingsSubsection";
import { _t } from "../../../languageHandler";
import { useAccountData } from "../../../hooks/useAccountData";
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
export const InviteControlsPanel: FC = () => {
const client = useMatrixClientContext();
const inviteState = useAccountData<AccountDataEvents["org.matrix.msc4155.invite_permission_config"]>(
client,
"org.matrix.msc4155.invite_permission_config",
);
const isOn = inviteState.default !== "block";
const [hasError, setHasError] = useState(false);
const [busy, setBusy] = useState(false);
const setValue = useCallback<ChangeEventHandler<HTMLInputElement>>(
async (e) => {
setHasError(false);
setBusy(true);
try {
await client.setAccountData("org.matrix.msc4155.invite_permission_config", {
// Don't remove any other state set by other clients.
...inviteState,
default: e.target.checked ? "allow" : "block",
});
} catch (ex) {
logger.error("Could not change input config", ex);
setHasError(true);
} finally {
setBusy(false);
}
},
[client, inviteState, isOn],
);
return (
<SettingsSubsection heading={_t("settings|invite_controls|title")}>
<Root>
<InlineField
name="default"
control={<ToggleInput disabled={busy} onChange={setValue} checked={isOn} />}
>
<Label>{_t("settings|invite_controls|default_label")}</Label>
{hasError && <ErrorMessage>{_t("settings|invite_controls|error_message")}</ErrorMessage>}
</InlineField>
</Root>
</SettingsSubsection>
);
};

View File

@@ -1,5 +1,5 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2024,2025 New Vector Ltd.
Copyright 2019-2023 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
@@ -35,6 +35,7 @@ import { SettingsSubsection, SettingsSubsectionText } from "../../shared/Setting
import { useOwnDevices } from "../../devices/useOwnDevices";
import { DiscoverySettings } from "../../discovery/DiscoverySettings";
import SetIntegrationManager from "../../SetIntegrationManager";
import { InviteControlsPanel } from "../../InviteControlsPanel";
interface IIgnoredUserProps {
userId: string;
@@ -372,6 +373,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
<CryptographyPanel />
</SettingsSection>
<SettingsSection heading={_t("common|privacy")}>
{SettingsStore.getValue("feature_invite_controls") ? <InviteControlsPanel /> : null}
<DiscoverySettings />
{posthogSection}
</SettingsSection>

View File

@@ -1509,6 +1509,8 @@
"group_widgets": "Widgets",
"hidebold": "Hide notification dot (only display counters badges)",
"html_topic": "Show HTML representation of room topics",
"invite_controls": "Control who is allowed to invite you to rooms",
"invite_controls_msc_support": "Requires your server to support MSC4155",
"join_beta": "Join the beta",
"join_beta_reload": "Joining the beta will reload %(brand)s.",
"jump_to_date": "Jump to date (adds /jumptodate and jump to date headers)",
@@ -2684,6 +2686,11 @@
"inline_url_previews_room_account": "Enable URL previews for this room (only affects you)",
"insert_trailing_colon_mentions": "Insert a trailing colon after user mentions at the start of a message",
"invite_avatars": "Show avatars of rooms you have been invited to",
"invite_controls": {
"default_label": "Allow users to invite you to rooms",
"error_message": "An error occured while trying to change this setting",
"title": "Invite controls"
},
"jump_to_bottom_on_send": "Jump to the bottom of the timeline when you send a message",
"key_backup": {
"backup_in_progress": "Your keys are being backed up (the first backup could take a few minutes).",

View File

@@ -198,6 +198,7 @@ export interface Settings {
"feature_html_topic": IFeature;
"feature_bridge_state": IFeature;
"feature_jump_to_date": IFeature;
"feature_invite_controls": IFeature;
"feature_sliding_sync": IBaseSetting<boolean>;
"feature_simplified_sliding_sync": IFeature;
"feature_element_call_video_rooms": IFeature;
@@ -522,6 +523,21 @@ export const SETTINGS: Settings = {
_td("labs|jump_to_date_msc_support"),
),
},
"feature_invite_controls": {
isFeature: true,
labsGroup: LabGroup.Rooms,
displayName: _td("labs|invite_controls"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG_PRIORITISED,
supportedLevelsAreOrdered: true,
default: false,
controller: new ServerSupportUnstableFeatureController(
"feature_invite_controls",
defaultWatchManager,
[["org.matrix.msc4155"]],
"v1.6",
_td("labs|invite_controls_msc_support"),
),
},
"RoomList.backgroundImage": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
default: null,