Happily handle empty text messages (#6825)

This commig refactors the message-deletion modal and reuses it for case of removing
the entire message and trying to send it, which should trigger removal flow instead.

Fix vector-im/element-web#18873
This commit is contained in:
Dariusz Niemczyk 2021-09-28 16:04:25 +02:00 committed by GitHub
parent e95e59e2eb
commit 8331d4c7b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 31 deletions

View file

@ -34,8 +34,7 @@ import ForwardDialog from "../dialogs/ForwardDialog";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import ReportEventDialog from '../dialogs/ReportEventDialog'; import ReportEventDialog from '../dialogs/ReportEventDialog';
import ViewSource from '../../structures/ViewSource'; import ViewSource from '../../structures/ViewSource';
import ConfirmRedactDialog from '../dialogs/ConfirmRedactDialog'; import { createRedactEventDialog } from '../dialogs/ConfirmRedactDialog';
import ErrorDialog from '../dialogs/ErrorDialog';
import ShareDialog from '../dialogs/ShareDialog'; import ShareDialog from '../dialogs/ShareDialog';
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
import { IPosition, ChevronFace } from '../../structures/ContextMenu'; import { IPosition, ChevronFace } from '../../structures/ContextMenu';
@ -140,34 +139,11 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
}; };
private onRedactClick = (): void => { private onRedactClick = (): void => {
Modal.createTrackedDialog('Confirm Redact Dialog', '', ConfirmRedactDialog, { const { mxEvent, onCloseDialog } = this.props;
onFinished: async (proceed: boolean, reason?: string) => { createRedactEventDialog({
if (!proceed) return; mxEvent,
onCloseDialog,
const cli = MatrixClientPeg.get(); });
try {
this.props.onCloseDialog?.();
await cli.redactEvent(
this.props.mxEvent.getRoomId(),
this.props.mxEvent.getId(),
undefined,
reason ? { reason } : {},
);
} catch (e) {
const code = e.errcode || e.statusCode;
// only show the dialog if failing for something other than a network error
// (e.g. no errcode or statusCode) as in that case the redactions end up in the
// detached queue and we show the room status bar to allow retry
if (typeof code !== "undefined") {
// display error message stating you couldn't delete this.
Modal.createTrackedDialog('You cannot delete this message', '', ErrorDialog, {
title: _t('Error'),
description: _t('You cannot delete this message. (%(code)s)', { code }),
});
}
}
},
}, 'mx_Dialog_confirmredact');
this.closeMenu(); this.closeMenu();
}; };

View file

@ -14,9 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
import React from 'react'; import React from 'react';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import Modal from '../../../Modal';
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import ErrorDialog from './ErrorDialog';
import TextInputDialog from "./TextInputDialog"; import TextInputDialog from "./TextInputDialog";
interface IProps { interface IProps {
@ -42,3 +46,40 @@ export default class ConfirmRedactDialog extends React.Component<IProps> {
); );
} }
} }
export function createRedactEventDialog({
mxEvent,
onCloseDialog = () => {},
}: {
mxEvent: MatrixEvent;
onCloseDialog?: () => void;
}) {
Modal.createTrackedDialog('Confirm Redact Dialog', '', ConfirmRedactDialog, {
onFinished: async (proceed: boolean, reason?: string) => {
if (!proceed) return;
const cli = MatrixClientPeg.get();
try {
onCloseDialog?.();
await cli.redactEvent(
mxEvent.getRoomId(),
mxEvent.getId(),
undefined,
reason ? { reason } : {},
);
} catch (e) {
const code = e.errcode || e.statusCode;
// only show the dialog if failing for something other than a network error
// (e.g. no errcode or statusCode) as in that case the redactions end up in the
// detached queue and we show the room status bar to allow retry
if (typeof code !== "undefined") {
// display error message stating you couldn't delete this.
Modal.createTrackedDialog('You cannot delete this message', '', ErrorDialog, {
title: _t('Error'),
description: _t('You cannot delete this message. (%(code)s)', { code }),
});
}
}
},
}, 'mx_Dialog_confirmredact');
}

View file

@ -42,6 +42,7 @@ import ErrorDialog from "../dialogs/ErrorDialog";
import QuestionDialog from "../dialogs/QuestionDialog"; import QuestionDialog from "../dialogs/QuestionDialog";
import { ActionPayload } from "../../../dispatcher/payloads"; import { ActionPayload } from "../../../dispatcher/payloads";
import AccessibleButton from '../elements/AccessibleButton'; import AccessibleButton from '../elements/AccessibleButton';
import { createRedactEventDialog } from '../dialogs/ConfirmRedactDialog';
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
@ -331,6 +332,14 @@ export default class EditMessageComposer extends React.Component<IProps, IState>
let shouldSend = true; let shouldSend = true;
if (newContent?.body === '') {
this.cancelPreviousPendingEdit();
createRedactEventDialog({
mxEvent: editedEvent,
});
return;
}
// If content is modified then send an updated event into the room // If content is modified then send an updated event into the room
if (this.isContentModified(newContent)) { if (this.isContentModified(newContent)) {
const roomId = editedEvent.getRoomId(); const roomId = editedEvent.getRoomId();

View file

@ -185,7 +185,7 @@ export function startsWith(model: EditorModel, prefix: string, caseSensitive = t
const firstPart = model.parts[0]; const firstPart = model.parts[0];
// part type will be "plain" while editing, // part type will be "plain" while editing,
// and "command" while composing a message. // and "command" while composing a message.
let text = firstPart && firstPart.text; let text = firstPart?.text || '';
if (!caseSensitive) { if (!caseSensitive) {
prefix = prefix.toLowerCase(); prefix = prefix.toLowerCase();
text = text.toLowerCase(); text = text.toLowerCase();