mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-04 19:56:45 +02:00
Fixup labs feature
This commit is contained in:
parent
c3986a937a
commit
eb356d960b
@ -297,7 +297,9 @@ class MatrixClientPegClass implements IMatrixClientPeg {
|
||||
opts.lazyLoadMembers = true;
|
||||
opts.clientWellKnownPollPeriod = 2 * 60 * 60; // 2 hours
|
||||
opts.threadSupport = true;
|
||||
opts.unstableMSC4429SyncUserProfileFields = ["org.matrix.msc4426.status"];
|
||||
if (SettingsStore.getValue("feature_user_status")) {
|
||||
opts.unstableMSC4429SyncUserProfileFields = ["org.matrix.msc4426.status"];
|
||||
}
|
||||
|
||||
if (SettingsStore.getValue("feature_sliding_sync")) {
|
||||
throw new UserFriendlyError("sliding_sync_legacy_no_longer_supported");
|
||||
|
||||
@ -11,6 +11,7 @@ import { logger as rootLogger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import { useMatrixClientContext } from "../contexts/MatrixClientContext";
|
||||
import { useTypedEventEmitter } from "./useEventEmitter";
|
||||
import { useFeatureEnabled } from "./useSettings";
|
||||
|
||||
const logger = rootLogger.getChild("useUserStatus");
|
||||
|
||||
@ -19,7 +20,15 @@ export interface UserStatus {
|
||||
text: string;
|
||||
}
|
||||
|
||||
const MAX_STATUS_TEXT_BYTES = 256;
|
||||
|
||||
export function userStatusTextWithinMaxLength(text: string): boolean {
|
||||
const textEncoder = new TextEncoder();
|
||||
return textEncoder.encode(text).length <= MAX_STATUS_TEXT_BYTES;
|
||||
}
|
||||
|
||||
export function useUserStatus(userId: string | undefined): UserStatus | undefined {
|
||||
const isEnabled = useFeatureEnabled("feature_user_status");
|
||||
const matrixClient = useMatrixClientContext();
|
||||
const [rawUserStatus, setRawUserStatus] = useState<unknown | undefined>();
|
||||
|
||||
@ -33,6 +42,9 @@ export function useUserStatus(userId: string | undefined): UserStatus | undefine
|
||||
});
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
if (!userId) {
|
||||
setRawUserStatus(undefined);
|
||||
return;
|
||||
@ -52,23 +64,26 @@ export function useUserStatus(userId: string | undefined): UserStatus | undefine
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, [userId, matrixClient]);
|
||||
}, [isEnabled, userId, matrixClient]);
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof rawUserStatus !== "object" || rawUserStatus === null) {
|
||||
logger.warn(`value of "org.matrix.msc4426.status" was not an object for ${userId}`);
|
||||
return undefined;
|
||||
return;
|
||||
}
|
||||
if ("emoji" in rawUserStatus === false || typeof rawUserStatus.emoji !== "string" || !rawUserStatus.emoji) {
|
||||
logger.warn(`"emoji" property was not a valid string for ${userId}`);
|
||||
return undefined;
|
||||
return;
|
||||
}
|
||||
if ("text" in rawUserStatus === false || typeof rawUserStatus.text !== "string" || !rawUserStatus.text) {
|
||||
logger.warn(`"status" property was not a valid string for ${userId}`);
|
||||
return undefined;
|
||||
logger.warn(`"text" property was not a valid string for ${userId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
emoji: rawUserStatus.emoji,
|
||||
text: rawUserStatus.text,
|
||||
text: userStatusTextWithinMaxLength(rawUserStatus.text) ? rawUserStatus.text : `${rawUserStatus.text}…`,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1530,6 +1530,11 @@
|
||||
"experimental_section": "Early previews",
|
||||
"extended_profiles_msc_support": "Requires your server to support MSC4133",
|
||||
"feature_disable_call_per_sender_encryption": "Disable per-sender encryption for Element Call",
|
||||
"feature_user_status": {
|
||||
"description": "Enables being able to see and set a current status.",
|
||||
"display_name": "User status",
|
||||
"required_msc_support": "Requires MSC4429 (Profile Updates for Legacy Sync)"
|
||||
},
|
||||
"feature_wysiwyg_composer_description": "Use rich text instead of Markdown in the message composer.",
|
||||
"group_calls": "New group call experience",
|
||||
"group_developer": "Developer",
|
||||
@ -3135,6 +3140,14 @@
|
||||
"server_error_detail": "Server unavailable, overloaded, or something else went wrong.",
|
||||
"shrug": "Prepends ¯\\_(ツ)_/¯ to a plain-text message",
|
||||
"spoiler": "Sends the given message as a spoiler",
|
||||
"status": {
|
||||
"description": "Set your current status",
|
||||
"no_args": "No arguments provided. You should supply an emoij and an optional text component.",
|
||||
"no_emoji": "You did not provide an emoji",
|
||||
"no_text": "You did not provide any status text",
|
||||
"too_long_emoji": "The first argument must be an emoji",
|
||||
"too_long_text": "The text you provided was too long."
|
||||
},
|
||||
"tableflip": "Prepends (╯°□°)╯︵ ┻━┻ to a plain-text message",
|
||||
"topic": "Gets or sets the room topic",
|
||||
"topic_none": "This room has no topic.",
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
Copyright 2024, 2025 New Vector Ltd.
|
||||
Copyright 2018-2024 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2017 Travis Ralston
|
||||
@ -226,6 +227,7 @@ export interface Settings {
|
||||
"feature_ask_to_join": IFeature;
|
||||
"feature_notifications": IFeature;
|
||||
"feature_msc4362_encrypted_state_events": IFeature;
|
||||
"feature_user_status": IFeature;
|
||||
// These are in the feature namespace but aren't actually features
|
||||
"feature_hidebold": IBaseSetting<boolean>;
|
||||
|
||||
@ -795,6 +797,30 @@ export const SETTINGS: Settings = {
|
||||
shouldWarn: true,
|
||||
default: false,
|
||||
},
|
||||
"feature_user_status": {
|
||||
isFeature: true,
|
||||
labsGroup: LabGroup.Profile,
|
||||
displayName: _td("labs|feature_user_status|display_name"),
|
||||
description: _td("labs|feature_user_status|description"),
|
||||
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG_PRIORITISED,
|
||||
supportedLevelsAreOrdered: true,
|
||||
controller: new ServerSupportUnstableFeatureController(
|
||||
"feature_user_status",
|
||||
defaultWatchManager,
|
||||
[["org.matrix.msc4429"], ["org.matrix.msc4429.stable"]],
|
||||
undefined,
|
||||
_td("labs|feature_user_status|required_msc_support"),
|
||||
false,
|
||||
// We have to assume it's available during early startup because of a race:
|
||||
// The feature is used to enable extra sync filters during MatrixClient setup
|
||||
// and we can't check for serverside support until the client has finished setting up.
|
||||
// Once the client has setup, (so by the time the user actually opens the labs menu) we can
|
||||
// enforce proper checks.
|
||||
true,
|
||||
true,
|
||||
),
|
||||
default: false,
|
||||
},
|
||||
"useCompactLayout": {
|
||||
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
|
||||
displayName: _td("settings|preferences|compact_modern"),
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
@ -12,6 +13,7 @@ import { type WatchManager } from "../WatchManager";
|
||||
import SettingsStore from "../SettingsStore";
|
||||
import { type SettingKey } from "../Settings.tsx";
|
||||
import { _t } from "../../languageHandler.tsx";
|
||||
import PlatformPeg from "../../PlatformPeg.ts";
|
||||
|
||||
/**
|
||||
* Disables a given setting if the server unstable feature it requires is not supported
|
||||
@ -28,6 +30,9 @@ export default class ServerSupportUnstableFeatureController extends MatrixClient
|
||||
* @param unstableFeatureGroups - If any one of the feature groups is satisfied,
|
||||
* then the setting is considered enabled. A feature group is satisfied if all of
|
||||
* the features in the group are supported (all features in a group are required).
|
||||
* @param defaultEnabled - If we haven't been able to check for support yet, should
|
||||
* this feature be enabled or disabled (default).
|
||||
* @param forceReload - Should the client force reload.
|
||||
*/
|
||||
public constructor(
|
||||
private readonly settingName: SettingKey,
|
||||
@ -36,12 +41,23 @@ export default class ServerSupportUnstableFeatureController extends MatrixClient
|
||||
private readonly stableVersion?: string,
|
||||
private readonly disabledMessage?: TranslationKey,
|
||||
private readonly forcedValue: any = false,
|
||||
private readonly defaultEnabled = false,
|
||||
private readonly forceReload = false,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public async onChange(): Promise<void> {
|
||||
if (this.forceReload) {
|
||||
PlatformPeg.get()?.reload();
|
||||
}
|
||||
}
|
||||
|
||||
public get disabled(): boolean {
|
||||
return !this.enabled;
|
||||
if (this.enabled !== undefined) {
|
||||
return !this.enabled;
|
||||
}
|
||||
return !this.defaultEnabled;
|
||||
}
|
||||
|
||||
public set disabled(newDisabledValue: boolean) {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
||||
@ -62,6 +63,7 @@ import { goto, join } from "./join";
|
||||
import { manuallyVerifyDevice } from "../components/views/dialogs/ManualDeviceKeyVerificationDialog";
|
||||
import upgraderoom from "./upgraderoom/upgraderoom";
|
||||
import { emoticon } from "./emoticon";
|
||||
import { userStatusTextWithinMaxLength } from "../hooks/useUserStatus";
|
||||
|
||||
export { CommandCategories, Command };
|
||||
|
||||
@ -819,6 +821,39 @@ export const Commands = [
|
||||
},
|
||||
renderingTypes: [TimelineRenderingType.Room],
|
||||
}),
|
||||
new Command({
|
||||
command: "status",
|
||||
args: "<emoji> <text>",
|
||||
description: _td("slash_command|status|description"),
|
||||
isEnabled: () => SettingsStore.getValue("feature_user_status"),
|
||||
runFn: function (cli, _roomId, _threadId, args) {
|
||||
if (!args) {
|
||||
return reject(new UserFriendlyError("slash_command|status|no_args"));
|
||||
}
|
||||
const [emojiText, text] = splitAtFirstSpace(args);
|
||||
if (!emojiText) {
|
||||
return reject(new UserFriendlyError("slash_command|status|no_emoji"));
|
||||
}
|
||||
if (!text) {
|
||||
return reject(new UserFriendlyError("slash_command|status|no_text"));
|
||||
}
|
||||
const [emoji, additionalSegment] = [...new Intl.Segmenter().segment(emojiText)];
|
||||
if (additionalSegment) {
|
||||
return reject(new UserFriendlyError("slash_command|status|too_long_emoji"));
|
||||
}
|
||||
if (text && !userStatusTextWithinMaxLength(text)) {
|
||||
return reject(new UserFriendlyError("slash_command|status|too_long_text"));
|
||||
}
|
||||
return success(
|
||||
cli.setExtendedProfileProperty("org.matrix.msc4426.status", {
|
||||
emoji: emoji.segment,
|
||||
text,
|
||||
}),
|
||||
);
|
||||
},
|
||||
category: CommandCategories.actions,
|
||||
renderingTypes: [TimelineRenderingType.Room],
|
||||
}),
|
||||
|
||||
// Command definitions for autocompletion ONLY:
|
||||
// /me is special because its not handled by SlashCommands.js and is instead done inside the Composer classes
|
||||
|
||||
@ -139,5 +139,10 @@ joining a room.
|
||||
|
||||
Replaces the legacy notification settings with a new one to manage push rules.
|
||||
|
||||
## User status (`feature_user_status`)
|
||||
|
||||
Enables setting a status message in your profile and to be able to view other's statuses.
|
||||
Requires [MSC4429](https://github.com/matrix-org/matrix-spec-proposals/pull/4429) and [MSC4426](https://github.com/matrix-org/matrix-spec-proposals/pull/4426).
|
||||
|
||||
**Warning** This feature has options which are not backwards compatible, disabling
|
||||
it may have unintended consequences.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user