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")} + +