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

Group Labs flags #7190

Merged
merged 3 commits into from
Nov 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 36 additions & 12 deletions src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ limitations under the License.
*/

import React from 'react';
import { sortBy } from "lodash";

import { _t } from "../../../../../languageHandler";
import SettingsStore from "../../../../../settings/SettingsStore";
import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
Expand All @@ -24,6 +26,8 @@ import SdkConfig from "../../../../../SdkConfig";
import BetaCard from "../../../beta/BetaCard";
import SettingsFlag from '../../../elements/SettingsFlag';
import { MatrixClientPeg } from '../../../../../MatrixClientPeg';
import { LabGroup, labGroupNames } from "../../../../../settings/Settings";
import { EnhancedMap } from "../../../../../utils/maps";

interface ILabsSettingToggleProps {
featureId: string;
Expand Down Expand Up @@ -66,7 +70,7 @@ export default class LabsUserSettingsTab extends React.Component<{}, IState> {
const [labs, betas] = features.reduce((arr, f) => {
arr[SettingsStore.getBetaInfo(f) ? 1 : 0].push(f);
return arr;
}, [[], []]);
}, [[], []] as [string[], string[]]);

let betaSection;
if (betas.length) {
Expand All @@ -77,23 +81,43 @@ export default class LabsUserSettingsTab extends React.Component<{}, IState> {

let labsSection;
if (SdkConfig.get()['showLabsSettings']) {
const flags = labs.map(f => <LabsSettingToggle featureId={f} key={f} />);
const groups = new EnhancedMap<LabGroup, JSX.Element[]>();
labs.forEach(f => {
groups.getOrCreate(SettingsStore.getLabGroup(f), []).push(
<LabsSettingToggle featureId={f} key={f} />,
);
});

groups.get(LabGroup.Widgets).push(
<SettingsFlag name="enableWidgetScreenshots" level={SettingLevel.ACCOUNT} />,
);

groups.get(LabGroup.Experimental).push(
<SettingsFlag name="lowBandwidth" level={SettingLevel.DEVICE} />,
);

groups.getOrCreate(LabGroup.Developer, []).push(
<SettingsFlag name="developerMode" level={SettingLevel.ACCOUNT} />,
<SettingsFlag name="showHiddenEventsInTimeline" level={SettingLevel.DEVICE} />,
);

groups.get(LabGroup.Analytics).push(
<SettingsFlag name="automaticErrorReporting" level={SettingLevel.DEVICE} />,
);

let hiddenReadReceipts;
if (this.state.showHiddenReadReceipts) {
hiddenReadReceipts = (
<SettingsFlag name="feature_hidden_read_receipts" level={SettingLevel.DEVICE} />
groups.get(LabGroup.Messaging).push(
<SettingsFlag name="feature_hidden_read_receipts" level={SettingLevel.DEVICE} />,
);
}

labsSection = <div className="mx_SettingsTab_section">
<SettingsFlag name="developerMode" level={SettingLevel.ACCOUNT} />
{ flags }
<SettingsFlag name="enableWidgetScreenshots" level={SettingLevel.ACCOUNT} />
<SettingsFlag name="showHiddenEventsInTimeline" level={SettingLevel.DEVICE} />
<SettingsFlag name="lowBandwidth" level={SettingLevel.DEVICE} />
<SettingsFlag name="automaticErrorReporting" level={SettingLevel.DEVICE} />
{ hiddenReadReceipts }
{ sortBy(Array.from(groups.entries()), "0").map(([group, flags]) => (
<div key={group}>
<span className="mx_SettingsTab_subheading">{ _t(labGroupNames[group]) }</span>
{ flags }
</div>
)) }
</div>;
}

Expand Down
16 changes: 11 additions & 5 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,17 @@
"%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s",
"%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s",
"Change notification settings": "Change notification settings",
"Messaging": "Messaging",
"Profile": "Profile",
"Spaces": "Spaces",
"Widgets": "Widgets",
"Rooms": "Rooms",
"Moderation": "Moderation",
"Message Previews": "Message Previews",
"Themes": "Themes",
"Encryption": "Encryption",
"Experimental": "Experimental",
"Developer": "Developer",
"Report to moderators prototype. In rooms that support moderation, the `report` button will let you report abuse to room moderators": "Report to moderators prototype. In rooms that support moderation, the `report` button will let you report abuse to room moderators",
"Show options to enable 'Do not disturb' mode": "Show options to enable 'Do not disturb' mode",
"Render LaTeX maths in messages": "Render LaTeX maths in messages",
Expand Down Expand Up @@ -1073,7 +1084,6 @@
"Favourites": "Favourites",
"People": "People",
"Other rooms": "Other rooms",
"Spaces": "Spaces",
"Expand space panel": "Expand space panel",
"Collapse space panel": "Collapse space panel",
"Click to copy": "Click to copy",
Expand Down Expand Up @@ -1172,7 +1182,6 @@
"Sign Out": "Sign Out",
"Display Name": "Display Name",
"Rename": "Rename",
"Encryption": "Encryption",
"Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s rooms.|other": "Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s rooms.",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s rooms.|one": "Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s room.",
Expand Down Expand Up @@ -1236,7 +1245,6 @@
"Failed to save your profile": "Failed to save your profile",
"The operation could not be completed": "The operation could not be completed",
"<a>Upgrade</a> to your own domain": "<a>Upgrade</a> to your own domain",
"Profile": "Profile",
"Profile picture": "Profile picture",
"Save": "Save",
"Delete Backup": "Delete Backup",
Expand Down Expand Up @@ -1700,7 +1708,6 @@
"Search": "Search",
"Invites": "Invites",
"Start chat": "Start chat",
"Rooms": "Rooms",
"Add room": "Add room",
"Create new room": "Create new room",
"You do not have permissions to create new rooms in this space": "You do not have permissions to create new rooms in this space",
Expand Down Expand Up @@ -1882,7 +1889,6 @@
"Unpin this widget to view it in this panel": "Unpin this widget to view it in this panel",
"Close this widget to view it in this panel": "Close this widget to view it in this panel",
"Set my room layout for everyone": "Set my room layout for everyone",
"Widgets": "Widgets",
"Edit widgets, bridges & bots": "Edit widgets, bridges & bots",
"Add widgets, bridges & bots": "Add widgets, bridges & bots",
"Not encrypted": "Not encrypted",
Expand Down
69 changes: 63 additions & 6 deletions src/settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,38 @@ const LEVELS_UI_FEATURE = [
// in future we might have a .well-known level or something
];

export interface ISetting {
// Must be set to true for features. Default is 'false'.
isFeature?: boolean;
export enum LabGroup {
Messaging,
Profile,
Spaces,
Widgets,
Rooms,
Moderation,
Analytics,
MessagePreviews,
Themes,
Encryption,
Experimental,
Developer,
}

export const labGroupNames: Record<LabGroup, string> = {
[LabGroup.Messaging]: _td("Messaging"),
[LabGroup.Profile]: _td("Profile"),
[LabGroup.Spaces]: _td("Spaces"),
[LabGroup.Widgets]: _td("Widgets"),
[LabGroup.Rooms]: _td("Rooms"),
[LabGroup.Moderation]: _td("Moderation"),
[LabGroup.Analytics]: _td("Analytics"),
[LabGroup.MessagePreviews]: _td("Message Previews"),
[LabGroup.Themes]: _td("Themes"),
[LabGroup.Encryption]: _td("Encryption"),
[LabGroup.Experimental]: _td("Experimental"),
[LabGroup.Developer]: _td("Developer"),
};

interface IBaseSetting {
isFeature?: false | undefined;

// Display names are strongly recommended for clarity.
// Display name can also be an object for different levels.
Expand Down Expand Up @@ -138,28 +167,41 @@ export interface ISetting {
};
}

export interface IFeature extends Omit<IBaseSetting, "isFeature"> {
// Must be set to true for features.
isFeature: true;
labsGroup: LabGroup;
}

// Type using I-identifier for backwards compatibility from before it became a discriminated union
export type ISetting = IBaseSetting | IFeature;

export const SETTINGS: {[setting: string]: ISetting} = {
"feature_report_to_moderators": {
isFeature: true,
labsGroup: LabGroup.Moderation,
displayName: _td("Report to moderators prototype. " +
"In rooms that support moderation, the `report` button will let you report abuse to room moderators"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_dnd": {
isFeature: true,
labsGroup: LabGroup.Profile,
displayName: _td("Show options to enable 'Do not disturb' mode"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_latex_maths": {
isFeature: true,
labsGroup: LabGroup.Messaging,
displayName: _td("Render LaTeX maths in messages"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_communities_v2_prototypes": {
isFeature: true,
labsGroup: LabGroup.Spaces,
displayName: _td(
"Communities v2 prototypes. Requires compatible homeserver. " +
"Highly experimental - use with caution.",
Expand All @@ -170,18 +212,21 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"feature_pinning": {
isFeature: true,
labsGroup: LabGroup.Messaging,
displayName: _td("Message Pinning"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_maximised_widgets": {
isFeature: true,
labsGroup: LabGroup.Widgets,
displayName: _td("Maximised widgets"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_thread": {
isFeature: true,
labsGroup: LabGroup.Messaging,
// Requires a reload as we change an option flag on the `js-sdk`
// And the entire sync history needs to be parsed again
controller: new ReloadOnChangeController(),
Expand All @@ -191,44 +236,51 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"feature_custom_status": {
isFeature: true,
labsGroup: LabGroup.Profile,
displayName: _td("Custom user status messages"),
supportedLevels: LEVELS_FEATURE,
default: false,
controller: new CustomStatusController(),
},
"feature_custom_tags": {
isFeature: true,
labsGroup: LabGroup.Experimental,
displayName: _td("Group & filter rooms by custom tags (refresh to apply changes)"),
supportedLevels: LEVELS_FEATURE,
default: false,
controller: new IncompatibleController("showCommunitiesInsteadOfSpaces", false, false),
},
"feature_state_counters": {
isFeature: true,
labsGroup: LabGroup.Rooms,
displayName: _td("Render simple counters in room header"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_many_integration_managers": {
isFeature: true,
labsGroup: LabGroup.Experimental,
displayName: _td("Multiple integration managers (requires manual setup)"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_mjolnir": {
isFeature: true,
labsGroup: LabGroup.Moderation,
displayName: _td("Try out new ways to ignore people (experimental)"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_custom_themes": {
isFeature: true,
labsGroup: LabGroup.Themes,
displayName: _td("Support adding custom themes"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_roomlist_preview_reactions_dms": {
isFeature: true,
labsGroup: LabGroup.MessagePreviews,
displayName: _td("Show message previews for reactions in DMs"),
supportedLevels: LEVELS_FEATURE,
default: false,
Expand All @@ -237,25 +289,29 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"feature_roomlist_preview_reactions_all": {
isFeature: true,
labsGroup: LabGroup.MessagePreviews,
displayName: _td("Show message previews for reactions in all rooms"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_dehydration": {
isFeature: true,
labsGroup: LabGroup.Encryption,
displayName: _td("Offline encrypted messaging using dehydrated devices"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_pseudonymous_analytics_opt_in": {
isFeature: true,
labsGroup: LabGroup.Analytics,
supportedLevels: LEVELS_FEATURE,
displayName: _td('Send pseudonymous analytics data'),
default: false,
controller: new PseudonymousAnalyticsController(),
},
"feature_polls": {
isFeature: true,
labsGroup: LabGroup.Messaging,
supportedLevels: LEVELS_FEATURE,
displayName: _td("Polls (under active development)"),
default: false,
Expand All @@ -274,19 +330,22 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"feature_bridge_state": {
isFeature: true,
labsGroup: LabGroup.Rooms,
supportedLevels: LEVELS_FEATURE,
displayName: _td("Show info about bridges in room settings"),
default: false,
},
"feature_new_layout_switcher": {
isFeature: true,
labsGroup: LabGroup.Messaging,
supportedLevels: LEVELS_FEATURE,
displayName: _td("New layout switcher (with message bubbles)"),
default: false,
controller: new NewLayoutSwitcherController(),
},
"feature_spaces_metaspaces": {
isFeature: true,
labsGroup: LabGroup.Spaces,
supportedLevels: LEVELS_FEATURE,
displayName: _td("Meta Spaces"),
default: false,
Expand All @@ -301,9 +360,7 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"feature_hidden_read_receipts": {
supportedLevels: LEVELS_FEATURE,
displayName: _td(
"Don't send read receipts",
),
displayName: _td("Don't send read receipts"),
default: false,
},
"baseFontSize": {
Expand Down
10 changes: 8 additions & 2 deletions src/settings/SettingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import RoomSettingsHandler from "./handlers/RoomSettingsHandler";
import ConfigSettingsHandler from "./handlers/ConfigSettingsHandler";
import { _t } from '../languageHandler';
import dis from '../dispatcher/dispatcher';
import { ISetting, SETTINGS } from "./Settings";
import { IFeature, ISetting, LabGroup, SETTINGS } from "./Settings";
import LocalEchoWrapper from "./handlers/LocalEchoWrapper";
import { WatchManager, CallbackFn as WatchCallbackFn } from "./WatchManager";
import { SettingLevel } from "./SettingLevel";
Expand Down Expand Up @@ -273,7 +273,7 @@ export default class SettingsStore {
return SETTINGS[settingName].isFeature;
}

public static getBetaInfo(settingName: string) {
public static getBetaInfo(settingName: string): ISetting["betaInfo"] {
// consider a beta disabled if the config is explicitly set to false, in which case treat as normal Labs flag
if (SettingsStore.isFeature(settingName)
&& SettingsStore.getValueAt(SettingLevel.CONFIG, settingName, null, true, true) !== false
Expand All @@ -282,6 +282,12 @@ export default class SettingsStore {
}
}

public static getLabGroup(settingName: string): LabGroup {
if (SettingsStore.isFeature(settingName)) {
return (<IFeature>SETTINGS[settingName]).labsGroup;
}
}

/**
* Determines if a setting is enabled.
* If a setting is disabled then it should be hidden from the user.
Expand Down