diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index 6456368211..7ba2022c6d 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -43,6 +43,7 @@ import { ensureDMExists } from "./createRoom"; import { ViewUserPayload } from "./dispatcher/payloads/ViewUserPayload"; import { Action } from "./dispatcher/actions"; import { EffectiveMembership, getEffectiveMembership, leaveRoomBehaviour } from "./utils/membership"; +import SdkConfig from "./SdkConfig"; // XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816 interface HTMLInputEvent extends Event { @@ -87,6 +88,7 @@ interface ICommandOpts { runFn?: RunFn; category: string; hideCompletionAfterSpace?: boolean; + isEnabled?(): boolean; } export class Command { @@ -97,6 +99,7 @@ export class Command { runFn: undefined | RunFn; category: string; hideCompletionAfterSpace: boolean; + _isEnabled?: () => boolean; constructor(opts: ICommandOpts) { this.command = opts.command; @@ -106,6 +109,7 @@ export class Command { this.runFn = opts.runFn; this.category = opts.category || CommandCategories.other; this.hideCompletionAfterSpace = opts.hideCompletionAfterSpace || false; + this._isEnabled = opts.isEnabled; } getCommand() { @@ -125,6 +129,10 @@ export class Command { getUsage() { return _t('Usage') + ': ' + this.getCommandWithArgs(); } + + isEnabled() { + return this._isEnabled ? this._isEnabled() : true; + } } function reject(error) { @@ -971,6 +979,7 @@ export const Commands = [ command: "rageshake", aliases: ["bugreport"], description: _td("Send a bug report with logs"), + isEnabled: () => !!SdkConfig.get().bug_report_endpoint_url, args: "", runFn: function(roomId, args) { return success( @@ -1048,7 +1057,7 @@ Commands.forEach(cmd => { }); }); -export function parseCommandString(input) { +export function parseCommandString(input: string) { // trim any trailing whitespace, as it can confuse the parser for // IRC-style commands input = input.replace(/\s+$/, ''); @@ -1075,10 +1084,10 @@ export function parseCommandString(input) { * processing the command, or 'promise' if a request was sent out. * Returns null if the input didn't match a command. */ -export function getCommand(roomId, input) { +export function getCommand(roomId: string, input: string) { const {cmd, args} = parseCommandString(input); - if (CommandMap.has(cmd)) { + if (CommandMap.has(cmd) && CommandMap.get(cmd).isEnabled()) { return () => CommandMap.get(cmd).run(roomId, args, cmd); } } diff --git a/src/autocomplete/CommandProvider.tsx b/src/autocomplete/CommandProvider.tsx index 3ff8ff0469..c2d1290e08 100644 --- a/src/autocomplete/CommandProvider.tsx +++ b/src/autocomplete/CommandProvider.tsx @@ -47,7 +47,7 @@ export default class CommandProvider extends AutocompleteProvider { if (command[0] !== command[1]) { // The input looks like a command with arguments, perform exact match const name = command[1].substr(1); // strip leading `/` - if (CommandMap.has(name)) { + if (CommandMap.has(name) && CommandMap.get(name).isEnabled()) { // some commands, namely `me` and `ddg` don't suit having the usage shown whilst typing their arguments if (CommandMap.get(name).hideCompletionAfterSpace) return []; matches = [CommandMap.get(name)]; @@ -63,7 +63,7 @@ export default class CommandProvider extends AutocompleteProvider { } - return matches.map((result) => { + return matches.filter(cmd => cmd.isEnabled()).map((result) => { let completion = result.getCommand() + ' '; const usedAlias = result.aliases.find(alias => `/${alias}` === command[1]); // If the command (or an alias) is the same as the one they entered, we don't want to discard their arguments diff --git a/src/components/views/dialogs/SlashCommandHelpDialog.js b/src/components/views/dialogs/SlashCommandHelpDialog.js index bae5b37993..5b4148e939 100644 --- a/src/components/views/dialogs/SlashCommandHelpDialog.js +++ b/src/components/views/dialogs/SlashCommandHelpDialog.js @@ -24,6 +24,7 @@ export default ({onFinished}) => { const categories = {}; Commands.forEach(cmd => { + if (!cmd.isEnabled()) return; if (!categories[cmd.category]) { categories[cmd.category] = []; } diff --git a/src/components/views/rooms/BasicMessageComposer.tsx b/src/components/views/rooms/BasicMessageComposer.tsx index 6024f272ec..7c2eb83a94 100644 --- a/src/components/views/rooms/BasicMessageComposer.tsx +++ b/src/components/views/rooms/BasicMessageComposer.tsx @@ -207,7 +207,8 @@ export default class BasicMessageEditor extends React.Component // If the user is entering a command, only consider them typing if it is one which sends a message into the room if (isTyping && this.props.model.parts[0].type === "command") { const {cmd} = parseCommandString(this.props.model.parts[0].text); - if (!CommandMap.has(cmd) || CommandMap.get(cmd).category !== CommandCategories.messages) { + const command = CommandMap.get(cmd); + if (!command || !command.isEnabled() || command.category !== CommandCategories.messages) { isTyping = false; } } diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.js b/src/components/views/settings/tabs/user/HelpUserSettingsTab.js index 64807ddb21..85ba22a353 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.js @@ -204,9 +204,9 @@ export default class HelpUserSettingsTab extends React.Component { updateButton = ; } - return ( -
-
{_t("Help & About")}
+ let bugReportingSection; + if (SdkConfig.get().bug_report_endpoint_url) { + bugReportingSection = (
{_t('Bug reporting')}
@@ -223,22 +223,24 @@ export default class HelpUserSettingsTab extends React.Component { {_t("Submit debug logs")}
-
- - {_t("Clear cache and reload")} - -
{ _t( "To report a Matrix-related security issue, please read the Matrix.org " + "Security Disclosure Policy.", {}, { 'a': (sub) => {sub}, + rel="noreferrer noopener" target="_blank">{sub}, }) }
+ ); + } + + return ( +
+
{_t("Help & About")}
+ { bugReportingSection }
{_t("FAQ")}
@@ -268,6 +270,11 @@ export default class HelpUserSettingsTab extends React.Component { data-spoiler={MatrixClientPeg.get().getAccessToken()}> <{ _t("click to reveal") }> +
+ + {_t("Clear cache and reload")} + +
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 8c342fe0ae..4414077005 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -840,12 +840,11 @@ "For help with using %(brand)s, click here.": "For help with using %(brand)s, click here.", "For help with using %(brand)s, click here or start a chat with our bot using the button below.": "For help with using %(brand)s, click here or start a chat with our bot using the button below.", "Chat with %(brand)s Bot": "Chat with %(brand)s Bot", - "Help & About": "Help & About", "Bug reporting": "Bug reporting", "If you've submitted a bug via GitHub, debug logs can help us track down the problem. Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "If you've submitted a bug via GitHub, debug logs can help us track down the problem. Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.", "Submit debug logs": "Submit debug logs", - "Clear cache and reload": "Clear cache and reload", "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.": "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.", + "Help & About": "Help & About", "FAQ": "FAQ", "Keyboard Shortcuts": "Keyboard Shortcuts", "Versions": "Versions", @@ -855,6 +854,7 @@ "Identity Server is": "Identity Server is", "Access Token:": "Access Token:", "click to reveal": "click to reveal", + "Clear cache and reload": "Clear cache and reload", "Labs": "Labs", "Customise your experience with experimental labs features. Learn more.": "Customise your experience with experimental labs features. Learn more.", "Ignored/Blocked": "Ignored/Blocked",