From ad9ff2535b26b11b90cdaecc8290764b33fc5a9f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 11 Jan 2022 14:34:35 +0000 Subject: [PATCH 1/7] De-duplicate slash command code between edit & send composers --- src/SlashCommands.tsx | 1 - .../views/rooms/EditMessageComposer.tsx | 113 ++-------------- .../views/rooms/SendMessageComposer.tsx | 121 ++--------------- src/editor/commands.tsx | 125 ++++++++++++++++++ src/i18n/strings/en_EN.json | 14 +- 5 files changed, 157 insertions(+), 217 deletions(-) create mode 100644 src/editor/commands.tsx diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index 0004f786280..4e2020aa5d0 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -1248,7 +1248,6 @@ interface ICmd { /** * Process the given text for /commands and return a bound method to perform them. - * @param {string} roomId The room in which the command was performed. * @param {string} input The raw text input by the user. * @return {null|function(): Object} Function returning an object with the property 'error' if there was an error * processing the command, or 'promise' if a request was sent out. diff --git a/src/components/views/rooms/EditMessageComposer.tsx b/src/components/views/rooms/EditMessageComposer.tsx index 36e2e5bf2d7..a799d887f12 100644 --- a/src/components/views/rooms/EditMessageComposer.tsx +++ b/src/components/views/rooms/EditMessageComposer.tsx @@ -21,24 +21,23 @@ import { MsgType } from 'matrix-js-sdk/src/@types/event'; import { Room } from 'matrix-js-sdk/src/models/room'; import { logger } from "matrix-js-sdk/src/logger"; -import { _t, _td } from '../../../languageHandler'; +import { _t } from '../../../languageHandler'; import dis from '../../../dispatcher/dispatcher'; import EditorModel from '../../../editor/model'; import { getCaretOffsetAndText } from '../../../editor/dom'; import { htmlSerializeIfNeeded, textSerialize, containsEmote, stripEmoteCommand } from '../../../editor/serialize'; import { findEditableEvent } from '../../../utils/EventUtils'; import { parseEvent } from '../../../editor/deserialize'; -import { CommandPartCreator, Part, PartCreator, Type } from '../../../editor/parts'; +import { CommandPartCreator, Part, PartCreator } from '../../../editor/parts'; import EditorStateTransfer from '../../../utils/EditorStateTransfer'; import BasicMessageComposer, { REGEX_EMOTICON } from "./BasicMessageComposer"; -import { Command, CommandCategories, getCommand } from '../../../SlashCommands'; +import { CommandCategories } from '../../../SlashCommands'; import { Action } from "../../../dispatcher/actions"; import CountlyAnalytics from "../../../CountlyAnalytics"; import { getKeyBindingsManager, MessageComposerAction } from '../../../KeyBindingsManager'; import { replaceableComponent } from "../../../utils/replaceableComponent"; import SendHistoryManager from '../../../SendHistoryManager'; import Modal from '../../../Modal'; -import ErrorDialog from "../dialogs/ErrorDialog"; import QuestionDialog from "../dialogs/QuestionDialog"; import { ActionPayload } from "../../../dispatcher/payloads"; import AccessibleButton from '../elements/AccessibleButton'; @@ -47,6 +46,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import { withMatrixClientHOC, MatrixClientProps } from '../../../contexts/MatrixClientContext'; import RoomContext from '../../../contexts/RoomContext'; import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload"; +import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands"; function getHtmlReplyFallback(mxEvent: MatrixEvent): string { const html = mxEvent.getContent().formatted_body; @@ -282,22 +282,6 @@ class EditMessageComposer extends React.Component { - // use mxid to textify user pills in a command - if (part.type === Type.UserPill) { - return text + part.resourceId; - } - return text + part.text; - }, ""); - const { cmd, args } = getCommand(commandText); - return [cmd, args, commandText]; - } - - private async runSlashCommand(cmd: Command, args: string, roomId: string): Promise { - const threadId = this.props.editState?.getEvent()?.getThread()?.id || null; - - const result = cmd.run(roomId, threadId, args); - let messageContent; - let error = result.error; - if (result.promise) { - try { - if (cmd.category === CommandCategories.messages) { - messageContent = await result.promise; - } else { - await result.promise; - } - } catch (err) { - error = err; - } - } - if (error) { - logger.error("Command failure: %s", error); - // assume the error is a server error when the command is async - const isServerError = !!result.promise; - const title = isServerError ? _td("Server error") : _td("Command error"); - - let errText; - if (typeof error === 'string') { - errText = error; - } else if (error.message) { - errText = error.message; - } else { - errText = _t("Server unavailable, overloaded, or something else went wrong."); - } - - Modal.createTrackedDialog(title, '', ErrorDialog, { - title: _t(title), - description: errText, - }); - } else { - logger.log("Command success."); - if (messageContent) return messageContent; - } - } - private sendEdit = async (): Promise => { const startTime = CountlyAnalytics.getTimestamp(); const editedEvent = this.props.editState.getEvent(); @@ -389,40 +319,19 @@ class EditMessageComposer extends React.Component -

- { _t("Unrecognised command: %(commandText)s", { commandText }) } -

-

- { _t("You can use /help to list available commands. " + - "Did you mean to send this as a message?", {}, { - code: t => { t }, - }) } -

-

- { _t("Hint: Begin your message with // to start it with a slash.", {}, { - code: t => { t }, - }) } -

- , - button: _t('Send as message'), - }); - const [sendAnyway] = await finished; + } else if (!await shouldSendAnyway(commandText)) { // if !sendAnyway bail to let the user edit the composer and try again - if (!sendAnyway) return; + return; } } if (shouldSend) { diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx index 54bc69cd24e..200264ba1f5 100644 --- a/src/components/views/rooms/SendMessageComposer.tsx +++ b/src/components/views/rooms/SendMessageComposer.tsx @@ -34,13 +34,13 @@ import { unescapeMessage, } from '../../../editor/serialize'; import BasicMessageComposer, { REGEX_EMOTICON } from "./BasicMessageComposer"; -import { CommandPartCreator, Part, PartCreator, SerializedPart, Type } from '../../../editor/parts'; +import { CommandPartCreator, Part, PartCreator, SerializedPart } from '../../../editor/parts'; import ReplyChain from "../elements/ReplyChain"; import { findEditableEvent } from '../../../utils/EventUtils'; import SendHistoryManager from "../../../SendHistoryManager"; -import { Command, CommandCategories, getCommand } from '../../../SlashCommands'; +import { CommandCategories } from '../../../SlashCommands'; import Modal from '../../../Modal'; -import { _t, _td } from '../../../languageHandler'; +import { _t } from '../../../languageHandler'; import ContentMessages from '../../../ContentMessages'; import { withMatrixClientHOC, MatrixClientProps } from "../../../contexts/MatrixClientContext"; import { Action } from "../../../dispatcher/actions"; @@ -52,13 +52,13 @@ import { getKeyBindingsManager, MessageComposerAction } from '../../../KeyBindin import { replaceableComponent } from "../../../utils/replaceableComponent"; import SettingsStore from '../../../settings/SettingsStore'; import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; -import ErrorDialog from "../dialogs/ErrorDialog"; import QuestionDialog from "../dialogs/QuestionDialog"; import { ActionPayload } from "../../../dispatcher/payloads"; import { decorateStartSendingTime, sendRoundTripMetric } from "../../../sendTimePerformanceMetrics"; import RoomContext, { TimelineRenderingType } from '../../../contexts/RoomContext'; import DocumentPosition from "../../../editor/position"; import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload"; +import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands"; function addReplyToMessageContent( content: IContent, @@ -284,24 +284,6 @@ export class SendMessageComposer extends React.Component { - // use mxid to textify user pills in a command - if (part.type === "user-pill") { - return text + part.resourceId; - } - return text + part.text; - }, ""); - const { cmd, args } = getCommand(commandText); - return [cmd, args, commandText]; - } - - private async runSlashCommand(cmd: Command, args: string): Promise { - const threadId = this.props.relation?.rel_type === RelationType.Thread - ? this.props.relation?.event_id - : null; - - const result = cmd.run(this.props.room.roomId, threadId, args); - let messageContent; - let error = result.error; - if (result.promise) { - try { - 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) { - error = err; - } - } - if (error) { - logger.error("Command failure: %s", error); - // assume the error is a server error when the command is async - const isServerError = !!result.promise; - const title = isServerError ? _td("Server error") : _td("Command error"); - - let errText; - if (typeof error === 'string') { - errText = error; - } else if (error.message) { - errText = error.message; - } else { - errText = _t("Server unavailable, overloaded, or something else went wrong."); - } - - Modal.createTrackedDialog(title, '', ErrorDialog, { - title: _t(title), - description: errText, - }); - } else { - logger.log("Command success."); - if (messageContent) return messageContent; - } - } - public async sendMessage(): Promise { const model = this.model; @@ -415,11 +340,15 @@ export class SendMessageComposer extends React.Component -

- { _t("Unrecognised command: %(commandText)s", { commandText }) } -

-

- { _t("You can use /help to list available commands. " + - "Did you mean to send this as a message?", {}, { - code: t => { t }, - }) } -

-

- { _t("Hint: Begin your message with // to start it with a slash.", {}, { - code: t => { t }, - }) } -

- , - button: _t('Send as message'), - }); - const [sendAnyway] = await finished; + } else if (!await shouldSendAnyway(commandText)) { // if !sendAnyway bail to let the user edit the composer and try again - if (!sendAnyway) return; + return; } } diff --git a/src/editor/commands.tsx b/src/editor/commands.tsx new file mode 100644 index 00000000000..0838a48362b --- /dev/null +++ b/src/editor/commands.tsx @@ -0,0 +1,125 @@ +/* +Copyright 2019 - 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { logger } from "matrix-js-sdk/src/logger"; + +import EditorModel from "./model"; +import { Type } from "./parts"; +import { Command, CommandCategories, getCommand } from "../SlashCommands"; +import { _t, _td } from "../languageHandler"; +import Modal from "../Modal"; +import ErrorDialog from "../components/views/dialogs/ErrorDialog"; +import QuestionDialog from "../components/views/dialogs/QuestionDialog"; + +export function isSlashCommand(model: EditorModel): boolean { + const parts = model.parts; + const firstPart = parts[0]; + if (firstPart) { + if (firstPart.type === Type.Command && firstPart.text.startsWith("/") && !firstPart.text.startsWith("//")) { + return true; + } + + if (firstPart.text.startsWith("/") && !firstPart.text.startsWith("//") + && (firstPart.type === Type.Plain || firstPart.type === Type.PillCandidate)) { + return true; + } + } + return false; +} + +export function getSlashCommand(model: EditorModel): [Command, string, string] { + const commandText = model.parts.reduce((text, part) => { + // use mxid to textify user pills in a command + if (part.type === Type.UserPill) { + return text + part.resourceId; + } + return text + part.text; + }, ""); + const { cmd, args } = getCommand(commandText); + return [cmd, args, commandText]; +} + +export async function runSlashCommand( + cmd: Command, + args: string, + roomId: string, + threadId: string | null, +): Promise { + const result = cmd.run(roomId, threadId, args); + let messageContent; // TODO + let error = result.error; + if (result.promise) { + try { + if (cmd.category === CommandCategories.messages) { + messageContent = await result.promise; + } else { + await result.promise; + } + } catch (err) { + error = err; + } + } + if (error) { + logger.error("Command failure: %s", error); + // assume the error is a server error when the command is async + const isServerError = !!result.promise; + const title = isServerError ? _td("Server error") : _td("Command error"); + + let errText; + if (typeof error === 'string') { + errText = error; + } else if (error.message) { + errText = error.message; + } else { + errText = _t("Server unavailable, overloaded, or something else went wrong."); + } + + Modal.createTrackedDialog(title, '', ErrorDialog, { + title: _t(title), + description: errText, + }); + } else { + logger.log("Command success."); + if (messageContent) return messageContent; + } +} + +export async function shouldSendAnyway(commandText: string): Promise { + // ask the user if their unknown command should be sent as a message + const { finished } = Modal.createTrackedDialog("Unknown command", "", QuestionDialog, { + title: _t("Unknown Command"), + description:
+

+ { _t("Unrecognised command: %(commandText)s", { commandText }) } +

+

+ { _t("You can use /help to list available commands. " + + "Did you mean to send this as a message?", {}, { + code: t => { t }, + }) } +

+

+ { _t("Hint: Begin your message with // to start it with a slash.", {}, { + code: t => { t }, + }) } +

+
, + button: _t('Send as message'), + }); + const [sendAnyway] = await finished; + return sendAnyway; +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 308cf4736a9..f5131ec6786 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -973,6 +973,13 @@ "sends snowfall": "sends snowfall", "Sends the given message with a space themed effect": "Sends the given message with a space themed effect", "sends space invaders": "sends space invaders", + "Server error": "Server error", + "Server unavailable, overloaded, or something else went wrong.": "Server unavailable, overloaded, or something else went wrong.", + "Unknown Command": "Unknown Command", + "Unrecognised command: %(commandText)s": "Unrecognised command: %(commandText)s", + "You can use /help to list available commands. Did you mean to send this as a message?": "You can use /help to list available commands. Did you mean to send this as a message?", + "Hint: Begin your message with // to start it with a slash.": "Hint: Begin your message with // to start it with a slash.", + "Send as message": "Send as message", "unknown person": "unknown person", "Consulting with %(transferTarget)s. Transfer to %(transferee)s": "Consulting with %(transferTarget)s. Transfer to %(transferee)s", "You held the call Switch": "You held the call Switch", @@ -1629,13 +1636,6 @@ "Someone is using an unknown session": "Someone is using an unknown session", "This room is end-to-end encrypted": "This room is end-to-end encrypted", "Everyone in this room is verified": "Everyone in this room is verified", - "Server error": "Server error", - "Server unavailable, overloaded, or something else went wrong.": "Server unavailable, overloaded, or something else went wrong.", - "Unknown Command": "Unknown Command", - "Unrecognised command: %(commandText)s": "Unrecognised command: %(commandText)s", - "You can use /help to list available commands. Did you mean to send this as a message?": "You can use /help to list available commands. Did you mean to send this as a message?", - "Hint: Begin your message with // to start it with a slash.": "Hint: Begin your message with // to start it with a slash.", - "Send as message": "Send as message", "Edit message": "Edit message", "Mod": "Mod", "%(count)s reply|other": "%(count)s replies", From cdf359b475a6a790df2b445edd138a626fe09d58 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 11 Jan 2022 14:36:11 +0000 Subject: [PATCH 2/7] When using a pill in a slash command pass resourceId into the string --- src/editor/commands.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/editor/commands.tsx b/src/editor/commands.tsx index 0838a48362b..b9b91ae21f8 100644 --- a/src/editor/commands.tsx +++ b/src/editor/commands.tsx @@ -43,8 +43,8 @@ export function isSlashCommand(model: EditorModel): boolean { export function getSlashCommand(model: EditorModel): [Command, string, string] { const commandText = model.parts.reduce((text, part) => { - // use mxid to textify user pills in a command - if (part.type === Type.UserPill) { + // use mxid to textify user pills in a command and room alias/id for room pills + if (part.type === Type.UserPill || part.type === Type.RoomPill) { return text + part.resourceId; } return text + part.text; From a4f562d5b45fb90b7f491906865efaa4bf5f3d58 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 11 Jan 2022 17:27:00 +0000 Subject: [PATCH 3/7] delint --- src/components/views/rooms/EditMessageComposer.tsx | 2 -- src/components/views/rooms/SendMessageComposer.tsx | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/components/views/rooms/EditMessageComposer.tsx b/src/components/views/rooms/EditMessageComposer.tsx index a799d887f12..abecfbdba3f 100644 --- a/src/components/views/rooms/EditMessageComposer.tsx +++ b/src/components/views/rooms/EditMessageComposer.tsx @@ -37,8 +37,6 @@ import CountlyAnalytics from "../../../CountlyAnalytics"; import { getKeyBindingsManager, MessageComposerAction } from '../../../KeyBindingsManager'; import { replaceableComponent } from "../../../utils/replaceableComponent"; import SendHistoryManager from '../../../SendHistoryManager'; -import Modal from '../../../Modal'; -import QuestionDialog from "../dialogs/QuestionDialog"; import { ActionPayload } from "../../../dispatcher/payloads"; import AccessibleButton from '../elements/AccessibleButton'; import { createRedactEventDialog } from '../dialogs/ConfirmRedactDialog'; diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx index 200264ba1f5..985fd4883fc 100644 --- a/src/components/views/rooms/SendMessageComposer.tsx +++ b/src/components/views/rooms/SendMessageComposer.tsx @@ -39,8 +39,6 @@ import ReplyChain from "../elements/ReplyChain"; import { findEditableEvent } from '../../../utils/EventUtils'; import SendHistoryManager from "../../../SendHistoryManager"; import { CommandCategories } from '../../../SlashCommands'; -import Modal from '../../../Modal'; -import { _t } from '../../../languageHandler'; import ContentMessages from '../../../ContentMessages'; import { withMatrixClientHOC, MatrixClientProps } from "../../../contexts/MatrixClientContext"; import { Action } from "../../../dispatcher/actions"; @@ -52,7 +50,6 @@ import { getKeyBindingsManager, MessageComposerAction } from '../../../KeyBindin import { replaceableComponent } from "../../../utils/replaceableComponent"; import SettingsStore from '../../../settings/SettingsStore'; import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; -import QuestionDialog from "../dialogs/QuestionDialog"; import { ActionPayload } from "../../../dispatcher/payloads"; import { decorateStartSendingTime, sendRoundTripMetric } from "../../../sendTimePerformanceMetrics"; import RoomContext, { TimelineRenderingType } from '../../../contexts/RoomContext'; From cd224fd66ea687f7866cbdeebcdfdda8b5c1ba38 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 11 Jan 2022 17:34:29 +0000 Subject: [PATCH 4/7] improve typing --- src/SlashCommands.tsx | 34 +++++++++++-------- .../views/rooms/SendMessageComposer.tsx | 2 +- src/editor/commands.tsx | 5 +-- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index 4e2020aa5d0..ba2554c447a 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -24,6 +24,7 @@ import { EventType } from "matrix-js-sdk/src/@types/event"; import * as ContentHelpers from 'matrix-js-sdk/src/content-helpers'; import { parseFragment as parseHtml, Element as ChildElement } from "parse5"; import { logger } from "matrix-js-sdk/src/logger"; +import { IContent } from 'matrix-js-sdk/src/models/event'; import { MatrixClientPeg } from './MatrixClientPeg'; import dis from './dispatcher/dispatcher'; @@ -60,6 +61,7 @@ import SlashCommandHelpDialog from "./components/views/dialogs/SlashCommandHelpD import { shouldShowComponent } from "./customisations/helpers/UIComponents"; import { TimelineRenderingType } from './contexts/RoomContext'; import RoomViewStore from "./stores/RoomViewStore"; +import { XOR } from "./@types/common"; // XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816 interface HTMLInputEvent extends Event { @@ -94,7 +96,9 @@ export const CommandCategories = { "other": _td("Other"), }; -type RunFn = ((roomId: string, args: string, cmd: string) => {error: any} | {promise: Promise}); +export type RunResult = XOR<{ error: Error }, { promise: Promise }>; + +type RunFn = ((roomId: string, args: string, cmd: string) => RunResult); interface ICommandOpts { command: string; @@ -109,15 +113,15 @@ interface ICommandOpts { } export class Command { - command: string; - aliases: string[]; - args: undefined | string; - description: string; - runFn: undefined | RunFn; - category: string; - hideCompletionAfterSpace: boolean; - private _isEnabled?: () => boolean; - public renderingTypes?: TimelineRenderingType[]; + public readonly command: string; + public readonly aliases: string[]; + public readonly args: undefined | string; + public readonly description: string; + public readonly runFn: undefined | RunFn; + public readonly category: string; + public readonly hideCompletionAfterSpace: boolean; + public readonly renderingTypes?: TimelineRenderingType[]; + private readonly _isEnabled?: () => boolean; constructor(opts: ICommandOpts) { this.command = opts.command; @@ -131,15 +135,15 @@ export class Command { this.renderingTypes = opts.renderingTypes; } - getCommand() { + public getCommand() { return `/${this.command}`; } - getCommandWithArgs() { + public getCommandWithArgs() { return this.getCommand() + " " + this.args; } - run(roomId: string, threadId: string, args: string) { + public run(roomId: string, threadId: string, args: string): RunResult { // if it has no runFn then its an ignored/nop command (autocomplete only) e.g `/me` if (!this.runFn) return reject(_t("Command error")); @@ -153,11 +157,11 @@ export class Command { return this.runFn.bind(this)(roomId, args); } - getUsage() { + public getUsage() { return _t('Usage') + ': ' + this.getCommandWithArgs(); } - isEnabled(): boolean { + public isEnabled(): boolean { return this._isEnabled ? this._isEnabled() : true; } } diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx index 985fd4883fc..2e67715c185 100644 --- a/src/components/views/rooms/SendMessageComposer.tsx +++ b/src/components/views/rooms/SendMessageComposer.tsx @@ -335,7 +335,7 @@ export class SendMessageComposer extends React.Component { +): Promise { const result = cmd.run(roomId, threadId, args); - let messageContent; // TODO + let messageContent: IContent | null = null; let error = result.error; if (result.promise) { try { From a3cbfb737ca3572b6f122a66a041c39ea8ba8ba5 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 11 Jan 2022 17:43:57 +0000 Subject: [PATCH 5/7] Fix edge case with /me command --- src/components/views/rooms/EditMessageComposer.tsx | 3 +++ src/components/views/rooms/SendMessageComposer.tsx | 10 +++++----- src/editor/serialize.ts | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/views/rooms/EditMessageComposer.tsx b/src/components/views/rooms/EditMessageComposer.tsx index abecfbdba3f..e365d976e48 100644 --- a/src/components/views/rooms/EditMessageComposer.tsx +++ b/src/components/views/rooms/EditMessageComposer.tsx @@ -323,6 +323,9 @@ class EditMessageComposer extends React.Component 4; } export function startsWith(model: EditorModel, prefix: string, caseSensitive = true): boolean { From 0824fe42a3c9709887b2df118e51007a5f36f5c2 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 12 Jan 2022 09:05:19 +0000 Subject: [PATCH 6/7] i18n --- src/i18n/strings/en_EN.json | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 68abb912d72..062128c3da0 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -424,8 +424,6 @@ "Advanced": "Advanced", "Effects": "Effects", "Other": "Other", - "Command error: Unable to handle slash command.": "Command error: Unable to handle slash command.", - "Command error: Unable to find rendering type (%(renderingType)s)": "Command error: Unable to find rendering type (%(renderingType)s)", "Usage": "Usage", "Sends the given message as a spoiler": "Sends the given message as a spoiler", "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Prepends ¯\\_(ツ)_/¯ to a plain-text message", @@ -435,25 +433,20 @@ "Sends a message as plain text, without interpreting it as markdown": "Sends a message as plain text, without interpreting it as markdown", "Sends a message as html, without interpreting it as markdown": "Sends a message as html, without interpreting it as markdown", "Upgrades a room to a new version": "Upgrades a room to a new version", - "You do not have the required permissions to use this command.": "You do not have the required permissions to use this command.", "Jump to the given date in the timeline (YYYY-MM-DD)": "Jump to the given date in the timeline (YYYY-MM-DD)", - "We were unable to understand the given date (%(inputDate)s). Try using the format YYYY-MM-DD.": "We were unable to understand the given date (%(inputDate)s). Try using the format YYYY-MM-DD.", "Changes your display nickname": "Changes your display nickname", "Changes your display nickname in the current room only": "Changes your display nickname in the current room only", "Changes the avatar of the current room": "Changes the avatar of the current room", "Changes your avatar in this current room only": "Changes your avatar in this current room only", "Changes your avatar in all rooms": "Changes your avatar in all rooms", "Gets or sets the room topic": "Gets or sets the room topic", - "Failed to get room topic: Unable to find room (%(roomId)s": "Failed to get room topic: Unable to find room (%(roomId)s", "This room has no topic.": "This room has no topic.", "Sets the room name": "Sets the room name", "Invites user with given id to current room": "Invites user with given id to current room", "Use an identity server": "Use an identity server", "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.", - "Use an identity server to invite by email. Manage in Settings.": "Use an identity server to invite by email. Manage in Settings.", "Joins room with given address": "Joins room with given address", "Leave room": "Leave room", - "Unrecognised room address: %(roomAlias)s": "Unrecognised room address: %(roomAlias)s", "Kicks user with given id": "Kicks user with given id", "Bans user with given id": "Bans user with given id", "Unbans user with given ID": "Unbans user with given ID", @@ -464,19 +457,10 @@ "Unignored user": "Unignored user", "You are no longer ignoring %(userId)s": "You are no longer ignoring %(userId)s", "Define the power level of a user": "Define the power level of a user", - "Command failed: Unable to find room (%(roomId)s": "Command failed: Unable to find room (%(roomId)s", - "Could not find user in room": "Could not find user in room", "Deops user with given id": "Deops user with given id", "Opens the Developer Tools dialog": "Opens the Developer Tools dialog", "Adds a custom widget by URL to the room": "Adds a custom widget by URL to the room", - "Please supply a widget URL or embed code": "Please supply a widget URL or embed code", - "Please supply a https:// or http:// widget URL": "Please supply a https:// or http:// widget URL", - "You cannot modify widgets in this room.": "You cannot modify widgets in this room.", "Verifies a user, session, and pubkey tuple": "Verifies a user, session, and pubkey tuple", - "Unknown (user, session) pair: (%(userId)s, %(deviceId)s)": "Unknown (user, session) pair: (%(userId)s, %(deviceId)s)", - "Session already verified!": "Session already verified!", - "WARNING: Session already verified, but keys do NOT MATCH!": "WARNING: Session already verified, but keys do NOT MATCH!", - "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!", "Verified key": "Verified key", "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.", "Forces the current outbound group session in an encrypted room to be discarded": "Forces the current outbound group session in an encrypted room to be discarded", @@ -486,10 +470,8 @@ "Displays information about a user": "Displays information about a user", "Send a bug report with logs": "Send a bug report with logs", "Opens chat with the given user": "Opens chat with the given user", - "Unable to find Matrix ID for phone number": "Unable to find Matrix ID for phone number", "Sends a message to the given user": "Sends a message to the given user", "Places the call in the current room on hold": "Places the call in the current room on hold", - "No active call in this room": "No active call in this room", "Takes the call in the current room off hold": "Takes the call in the current room off hold", "Converts the room to a DM": "Converts the room to a DM", "Converts the DM to a room": "Converts the DM to a room", @@ -976,6 +958,14 @@ "sends snowfall": "sends snowfall", "Sends the given message with a space themed effect": "Sends the given message with a space themed effect", "sends space invaders": "sends space invaders", + "Server error": "Server error", + "Command error": "Command error", + "Server unavailable, overloaded, or something else went wrong.": "Server unavailable, overloaded, or something else went wrong.", + "Unknown Command": "Unknown Command", + "Unrecognised command: %(commandText)s": "Unrecognised command: %(commandText)s", + "You can use /help to list available commands. Did you mean to send this as a message?": "You can use /help to list available commands. Did you mean to send this as a message?", + "Hint: Begin your message with // to start it with a slash.": "Hint: Begin your message with // to start it with a slash.", + "Send as message": "Send as message", "unknown person": "unknown person", "Consulting with %(transferTarget)s. Transfer to %(transferee)s": "Consulting with %(transferTarget)s. Transfer to %(transferee)s", "You held the call Switch": "You held the call Switch", @@ -1632,14 +1622,6 @@ "Someone is using an unknown session": "Someone is using an unknown session", "This room is end-to-end encrypted": "This room is end-to-end encrypted", "Everyone in this room is verified": "Everyone in this room is verified", - "Server error": "Server error", - "Command error": "Command error", - "Server unavailable, overloaded, or something else went wrong.": "Server unavailable, overloaded, or something else went wrong.", - "Unknown Command": "Unknown Command", - "Unrecognised command: %(commandText)s": "Unrecognised command: %(commandText)s", - "You can use /help to list available commands. Did you mean to send this as a message?": "You can use /help to list available commands. Did you mean to send this as a message?", - "Hint: Begin your message with // to start it with a slash.": "Hint: Begin your message with // to start it with a slash.", - "Send as message": "Send as message", "Edit message": "Edit message", "Mod": "Mod", "%(count)s reply|other": "%(count)s replies", From e91ce622f3ea1965efe1775d79f8cc457f7d8dcc Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 12 Jan 2022 09:31:03 +0000 Subject: [PATCH 7/7] i18n --- src/i18n/strings/en_EN.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 062128c3da0..e22f07e1dbb 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -424,6 +424,8 @@ "Advanced": "Advanced", "Effects": "Effects", "Other": "Other", + "Command error: Unable to handle slash command.": "Command error: Unable to handle slash command.", + "Command error: Unable to find rendering type (%(renderingType)s)": "Command error: Unable to find rendering type (%(renderingType)s)", "Usage": "Usage", "Sends the given message as a spoiler": "Sends the given message as a spoiler", "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Prepends ¯\\_(ツ)_/¯ to a plain-text message", @@ -433,20 +435,25 @@ "Sends a message as plain text, without interpreting it as markdown": "Sends a message as plain text, without interpreting it as markdown", "Sends a message as html, without interpreting it as markdown": "Sends a message as html, without interpreting it as markdown", "Upgrades a room to a new version": "Upgrades a room to a new version", + "You do not have the required permissions to use this command.": "You do not have the required permissions to use this command.", "Jump to the given date in the timeline (YYYY-MM-DD)": "Jump to the given date in the timeline (YYYY-MM-DD)", + "We were unable to understand the given date (%(inputDate)s). Try using the format YYYY-MM-DD.": "We were unable to understand the given date (%(inputDate)s). Try using the format YYYY-MM-DD.", "Changes your display nickname": "Changes your display nickname", "Changes your display nickname in the current room only": "Changes your display nickname in the current room only", "Changes the avatar of the current room": "Changes the avatar of the current room", "Changes your avatar in this current room only": "Changes your avatar in this current room only", "Changes your avatar in all rooms": "Changes your avatar in all rooms", "Gets or sets the room topic": "Gets or sets the room topic", + "Failed to get room topic: Unable to find room (%(roomId)s": "Failed to get room topic: Unable to find room (%(roomId)s", "This room has no topic.": "This room has no topic.", "Sets the room name": "Sets the room name", "Invites user with given id to current room": "Invites user with given id to current room", "Use an identity server": "Use an identity server", "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.", + "Use an identity server to invite by email. Manage in Settings.": "Use an identity server to invite by email. Manage in Settings.", "Joins room with given address": "Joins room with given address", "Leave room": "Leave room", + "Unrecognised room address: %(roomAlias)s": "Unrecognised room address: %(roomAlias)s", "Kicks user with given id": "Kicks user with given id", "Bans user with given id": "Bans user with given id", "Unbans user with given ID": "Unbans user with given ID", @@ -457,10 +464,19 @@ "Unignored user": "Unignored user", "You are no longer ignoring %(userId)s": "You are no longer ignoring %(userId)s", "Define the power level of a user": "Define the power level of a user", + "Command failed: Unable to find room (%(roomId)s": "Command failed: Unable to find room (%(roomId)s", + "Could not find user in room": "Could not find user in room", "Deops user with given id": "Deops user with given id", "Opens the Developer Tools dialog": "Opens the Developer Tools dialog", "Adds a custom widget by URL to the room": "Adds a custom widget by URL to the room", + "Please supply a widget URL or embed code": "Please supply a widget URL or embed code", + "Please supply a https:// or http:// widget URL": "Please supply a https:// or http:// widget URL", + "You cannot modify widgets in this room.": "You cannot modify widgets in this room.", "Verifies a user, session, and pubkey tuple": "Verifies a user, session, and pubkey tuple", + "Unknown (user, session) pair: (%(userId)s, %(deviceId)s)": "Unknown (user, session) pair: (%(userId)s, %(deviceId)s)", + "Session already verified!": "Session already verified!", + "WARNING: Session already verified, but keys do NOT MATCH!": "WARNING: Session already verified, but keys do NOT MATCH!", + "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!", "Verified key": "Verified key", "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.", "Forces the current outbound group session in an encrypted room to be discarded": "Forces the current outbound group session in an encrypted room to be discarded", @@ -470,8 +486,10 @@ "Displays information about a user": "Displays information about a user", "Send a bug report with logs": "Send a bug report with logs", "Opens chat with the given user": "Opens chat with the given user", + "Unable to find Matrix ID for phone number": "Unable to find Matrix ID for phone number", "Sends a message to the given user": "Sends a message to the given user", "Places the call in the current room on hold": "Places the call in the current room on hold", + "No active call in this room": "No active call in this room", "Takes the call in the current room off hold": "Takes the call in the current room off hold", "Converts the room to a DM": "Converts the room to a DM", "Converts the DM to a room": "Converts the DM to a room",