mirror of
https://github.com/element-hq/element-web
synced 2024-11-27 03:36:07 +03:00
Merge pull request #5686 from robintown/reply-commands
Support replying with a message command
This commit is contained in:
commit
da7d31aeb6
2 changed files with 47 additions and 25 deletions
|
@ -20,6 +20,7 @@ limitations under the License.
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { ContentHelpers } from 'matrix-js-sdk';
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import {MatrixClientPeg} from './MatrixClientPeg';
|
||||||
import dis from './dispatcher/dispatcher';
|
import dis from './dispatcher/dispatcher';
|
||||||
import * as sdk from './index';
|
import * as sdk from './index';
|
||||||
|
@ -126,10 +127,10 @@ export class Command {
|
||||||
return this.getCommand() + " " + this.args;
|
return this.getCommand() + " " + this.args;
|
||||||
}
|
}
|
||||||
|
|
||||||
run(roomId: string, args: string, cmd: string) {
|
run(roomId: string, args: string) {
|
||||||
// if it has no runFn then its an ignored/nop command (autocomplete only) e.g `/me`
|
// if it has no runFn then its an ignored/nop command (autocomplete only) e.g `/me`
|
||||||
if (!this.runFn) return reject(_t("Command error"));
|
if (!this.runFn) return reject(_t("Command error"));
|
||||||
return this.runFn.bind(this)(roomId, args, cmd);
|
return this.runFn.bind(this)(roomId, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUsage() {
|
getUsage() {
|
||||||
|
@ -163,7 +164,7 @@ export const Commands = [
|
||||||
if (args) {
|
if (args) {
|
||||||
message = message + ' ' + args;
|
message = message + ' ' + args;
|
||||||
}
|
}
|
||||||
return success(MatrixClientPeg.get().sendTextMessage(roomId, message));
|
return success(ContentHelpers.makeTextMessage(message));
|
||||||
},
|
},
|
||||||
category: CommandCategories.messages,
|
category: CommandCategories.messages,
|
||||||
}),
|
}),
|
||||||
|
@ -176,7 +177,7 @@ export const Commands = [
|
||||||
if (args) {
|
if (args) {
|
||||||
message = message + ' ' + args;
|
message = message + ' ' + args;
|
||||||
}
|
}
|
||||||
return success(MatrixClientPeg.get().sendTextMessage(roomId, message));
|
return success(ContentHelpers.makeTextMessage(message));
|
||||||
},
|
},
|
||||||
category: CommandCategories.messages,
|
category: CommandCategories.messages,
|
||||||
}),
|
}),
|
||||||
|
@ -189,7 +190,7 @@ export const Commands = [
|
||||||
if (args) {
|
if (args) {
|
||||||
message = message + ' ' + args;
|
message = message + ' ' + args;
|
||||||
}
|
}
|
||||||
return success(MatrixClientPeg.get().sendTextMessage(roomId, message));
|
return success(ContentHelpers.makeTextMessage(message));
|
||||||
},
|
},
|
||||||
category: CommandCategories.messages,
|
category: CommandCategories.messages,
|
||||||
}),
|
}),
|
||||||
|
@ -202,7 +203,7 @@ export const Commands = [
|
||||||
if (args) {
|
if (args) {
|
||||||
message = message + ' ' + args;
|
message = message + ' ' + args;
|
||||||
}
|
}
|
||||||
return success(MatrixClientPeg.get().sendTextMessage(roomId, message));
|
return success(ContentHelpers.makeTextMessage(message));
|
||||||
},
|
},
|
||||||
category: CommandCategories.messages,
|
category: CommandCategories.messages,
|
||||||
}),
|
}),
|
||||||
|
@ -211,7 +212,7 @@ export const Commands = [
|
||||||
args: '<message>',
|
args: '<message>',
|
||||||
description: _td('Sends a message as plain text, without interpreting it as markdown'),
|
description: _td('Sends a message as plain text, without interpreting it as markdown'),
|
||||||
runFn: function(roomId, messages) {
|
runFn: function(roomId, messages) {
|
||||||
return success(MatrixClientPeg.get().sendTextMessage(roomId, messages));
|
return success(ContentHelpers.makeTextMessage(messages));
|
||||||
},
|
},
|
||||||
category: CommandCategories.messages,
|
category: CommandCategories.messages,
|
||||||
}),
|
}),
|
||||||
|
@ -220,7 +221,7 @@ export const Commands = [
|
||||||
args: '<message>',
|
args: '<message>',
|
||||||
description: _td('Sends a message as html, without interpreting it as markdown'),
|
description: _td('Sends a message as html, without interpreting it as markdown'),
|
||||||
runFn: function(roomId, messages) {
|
runFn: function(roomId, messages) {
|
||||||
return success(MatrixClientPeg.get().sendHtmlMessage(roomId, messages, messages));
|
return success(ContentHelpers.makeHtmlMessage(messages, messages));
|
||||||
},
|
},
|
||||||
category: CommandCategories.messages,
|
category: CommandCategories.messages,
|
||||||
}),
|
}),
|
||||||
|
@ -965,7 +966,7 @@ export const Commands = [
|
||||||
args: '<message>',
|
args: '<message>',
|
||||||
runFn: function(roomId, args) {
|
runFn: function(roomId, args) {
|
||||||
if (!args) return reject(this.getUserId());
|
if (!args) return reject(this.getUserId());
|
||||||
return success(MatrixClientPeg.get().sendHtmlMessage(roomId, args, textToHtmlRainbow(args)));
|
return success(ContentHelpers.makeHtmlMessage(args, textToHtmlRainbow(args)));
|
||||||
},
|
},
|
||||||
category: CommandCategories.messages,
|
category: CommandCategories.messages,
|
||||||
}),
|
}),
|
||||||
|
@ -975,7 +976,7 @@ export const Commands = [
|
||||||
args: '<message>',
|
args: '<message>',
|
||||||
runFn: function(roomId, args) {
|
runFn: function(roomId, args) {
|
||||||
if (!args) return reject(this.getUserId());
|
if (!args) return reject(this.getUserId());
|
||||||
return success(MatrixClientPeg.get().sendHtmlEmote(roomId, args, textToHtmlRainbow(args)));
|
return success(ContentHelpers.makeHtmlEmote(args, textToHtmlRainbow(args)));
|
||||||
},
|
},
|
||||||
category: CommandCategories.messages,
|
category: CommandCategories.messages,
|
||||||
}),
|
}),
|
||||||
|
@ -1200,10 +1201,13 @@ export function parseCommandString(input: string) {
|
||||||
* processing the command, or 'promise' if a request was sent out.
|
* processing the command, or 'promise' if a request was sent out.
|
||||||
* Returns null if the input didn't match a command.
|
* Returns null if the input didn't match a command.
|
||||||
*/
|
*/
|
||||||
export function getCommand(roomId: string, input: string) {
|
export function getCommand(input: string) {
|
||||||
const {cmd, args} = parseCommandString(input);
|
const {cmd, args} = parseCommandString(input);
|
||||||
|
|
||||||
if (CommandMap.has(cmd) && CommandMap.get(cmd).isEnabled()) {
|
if (CommandMap.has(cmd) && CommandMap.get(cmd).isEnabled()) {
|
||||||
return () => CommandMap.get(cmd).run(roomId, args, cmd);
|
return {
|
||||||
|
cmd: CommandMap.get(cmd),
|
||||||
|
args,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ import ReplyThread from "../elements/ReplyThread";
|
||||||
import {parseEvent} from '../../../editor/deserialize';
|
import {parseEvent} from '../../../editor/deserialize';
|
||||||
import {findEditableEvent} from '../../../utils/EventUtils';
|
import {findEditableEvent} from '../../../utils/EventUtils';
|
||||||
import SendHistoryManager from "../../../SendHistoryManager";
|
import SendHistoryManager from "../../../SendHistoryManager";
|
||||||
import {getCommand} from '../../../SlashCommands';
|
import {CommandCategories, getCommand} from '../../../SlashCommands';
|
||||||
import * as sdk from '../../../index';
|
import * as sdk from '../../../index';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
import {_t, _td} from '../../../languageHandler';
|
import {_t, _td} from '../../../languageHandler';
|
||||||
|
@ -291,15 +291,22 @@ export default class SendMessageComposer extends React.Component {
|
||||||
}
|
}
|
||||||
return text + part.text;
|
return text + part.text;
|
||||||
}, "");
|
}, "");
|
||||||
return [getCommand(this.props.room.roomId, commandText), commandText];
|
const {cmd, args} = getCommand(commandText);
|
||||||
|
return [cmd, args, commandText];
|
||||||
}
|
}
|
||||||
|
|
||||||
async _runSlashCommand(fn) {
|
async _runSlashCommand(cmd, args) {
|
||||||
const cmd = fn();
|
const result = cmd.run(this.props.room.roomId, args);
|
||||||
let error = cmd.error;
|
let messageContent;
|
||||||
if (cmd.promise) {
|
let error = result.error;
|
||||||
|
if (result.promise) {
|
||||||
try {
|
try {
|
||||||
await cmd.promise;
|
if (cmd.category === CommandCategories.messages) {
|
||||||
|
// The command returns a modified message that we need to pass on
|
||||||
|
messageContent = await result.promise;
|
||||||
|
} else {
|
||||||
|
await result.promise;
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error = err;
|
error = err;
|
||||||
}
|
}
|
||||||
|
@ -308,7 +315,7 @@ export default class SendMessageComposer extends React.Component {
|
||||||
console.error("Command failure: %s", error);
|
console.error("Command failure: %s", error);
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
// assume the error is a server error when the command is async
|
// assume the error is a server error when the command is async
|
||||||
const isServerError = !!cmd.promise;
|
const isServerError = !!result.promise;
|
||||||
const title = isServerError ? _td("Server error") : _td("Command error");
|
const title = isServerError ? _td("Server error") : _td("Command error");
|
||||||
|
|
||||||
let errText;
|
let errText;
|
||||||
|
@ -326,6 +333,7 @@ export default class SendMessageComposer extends React.Component {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log("Command success.");
|
console.log("Command success.");
|
||||||
|
if (messageContent) return messageContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,13 +342,22 @@ export default class SendMessageComposer extends React.Component {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const replyToEvent = this.props.replyToEvent;
|
||||||
let shouldSend = true;
|
let shouldSend = true;
|
||||||
|
let content;
|
||||||
|
|
||||||
if (!containsEmote(this.model) && this._isSlashCommand()) {
|
if (!containsEmote(this.model) && this._isSlashCommand()) {
|
||||||
const [cmd, commandText] = this._getSlashCommand();
|
const [cmd, args, commandText] = this._getSlashCommand();
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
shouldSend = false;
|
if (cmd.category === CommandCategories.messages) {
|
||||||
this._runSlashCommand(cmd);
|
content = await this._runSlashCommand(cmd, args);
|
||||||
|
if (replyToEvent) {
|
||||||
|
addReplyToMessageContent(content, replyToEvent, this.props.permalinkCreator);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._runSlashCommand(cmd, args);
|
||||||
|
shouldSend = false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// ask the user if their unknown command should be sent as a message
|
// ask the user if their unknown command should be sent as a message
|
||||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||||
|
@ -375,11 +392,12 @@ export default class SendMessageComposer extends React.Component {
|
||||||
this._sendQuickReaction();
|
this._sendQuickReaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
const replyToEvent = this.props.replyToEvent;
|
|
||||||
if (shouldSend) {
|
if (shouldSend) {
|
||||||
const startTime = CountlyAnalytics.getTimestamp();
|
const startTime = CountlyAnalytics.getTimestamp();
|
||||||
const {roomId} = this.props.room;
|
const {roomId} = this.props.room;
|
||||||
const content = createMessageContent(this.model, this.props.permalinkCreator, replyToEvent);
|
if (!content) {
|
||||||
|
content = createMessageContent(this.model, this.props.permalinkCreator, replyToEvent);
|
||||||
|
}
|
||||||
// don't bother sending an empty message
|
// don't bother sending an empty message
|
||||||
if (!content.body.trim()) return;
|
if (!content.body.trim()) return;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue