diff --git a/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.test.jsx b/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.test.jsx index 90ac1c634b..7fd923328d 100644 --- a/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.test.jsx +++ b/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.test.jsx @@ -311,9 +311,8 @@ describe('components/AdvancedCreateComment', () => { expect(wrapper.state().serverError.message).toBe(testError1); expect(wrapper.state().draft.uploadsInProgress).toEqual([2, 3]); - // clientId = -1 const testError2 = 'test error 2'; - instance.handleUploadError(testError2, -1, null, props.rootId); + instance.handleUploadError(testError2, '', null, props.rootId); // should not call onUpdateCommentDraft expect(updateCommentDraftWithRootId.mock.calls.length).toBe(1); diff --git a/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.tsx b/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.tsx index 6db290a676..a8b32c762d 100644 --- a/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.tsx +++ b/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.tsx @@ -1116,8 +1116,8 @@ class AdvancedCreateComment extends React.PureComponent { } }; - handleUploadError = (err: string | ServerError | null, clientId: string | number = -1, _?: string, rootId = '') => { - if (clientId !== -1) { + handleUploadError = (uploadError: string | ServerError | null, clientId?: string, _?: string, rootId = '') => { + if (clientId) { const draft = {...this.draftsForPost[rootId]!}; const uploadsInProgress = [...draft.uploadsInProgress]; @@ -1137,16 +1137,13 @@ class AdvancedCreateComment extends React.PureComponent { } } - let serverError = err; - if (typeof serverError === 'string') { - serverError = new Error(serverError); - } - - this.setState({serverError}, () => { - if (serverError && this.props.scrollToBottom) { - this.props.scrollToBottom(); + if (typeof uploadError === 'string') { + if (uploadError.length !== 0) { + this.setState({serverError: new Error(uploadError)}); } - }); + } else { + this.setState({serverError: uploadError}); + } }; removePreview = (id: string) => { diff --git a/webapp/channels/src/components/advanced_create_post/advanced_create_post.tsx b/webapp/channels/src/components/advanced_create_post/advanced_create_post.tsx index 4cda2c0e8c..32d5ee2a85 100644 --- a/webapp/channels/src/components/advanced_create_post/advanced_create_post.tsx +++ b/webapp/channels/src/components/advanced_create_post/advanced_create_post.tsx @@ -1038,34 +1038,32 @@ class AdvancedCreatePost extends React.PureComponent { this.handleDraftChange(draft, true); }; - handleUploadError = (err: string | ServerError, clientId?: string, channelId?: string) => { - let serverError = err; - if (typeof serverError === 'string') { - serverError = new Error(serverError); - } + handleUploadError = (uploadError: string | ServerError | null, clientId?: string, channelId?: string) => { + if (clientId && channelId) { + const draft = {...this.draftsForChannel[channelId]!}; - if (!channelId || !clientId) { - this.setState({serverError}); - return; - } + if (draft.uploadsInProgress) { + const index = draft.uploadsInProgress.indexOf(clientId); - const draft = {...this.draftsForChannel[channelId]!}; - - if (draft.uploadsInProgress) { - const index = draft.uploadsInProgress.indexOf(clientId); - - if (index !== -1) { - const uploadsInProgress = draft.uploadsInProgress.filter((item, itemIndex) => index !== itemIndex); - const modifiedDraft = { - ...draft, - uploadsInProgress, - }; - this.props.actions.setDraft(StoragePrefixes.DRAFT + channelId, modifiedDraft, channelId); - this.draftsForChannel[channelId] = modifiedDraft; + if (index !== -1) { + const uploadsInProgress = draft.uploadsInProgress.filter((item, itemIndex) => index !== itemIndex); + const modifiedDraft = { + ...draft, + uploadsInProgress, + }; + this.props.actions.setDraft(StoragePrefixes.DRAFT + channelId, modifiedDraft, channelId); + this.draftsForChannel[channelId] = modifiedDraft; + } } } - this.setState({serverError}); + if (typeof uploadError === 'string') { + if (uploadError.length !== 0) { + this.setState({serverError: new Error(uploadError)}); + } + } else { + this.setState({serverError: uploadError}); + } }; removePreview = (id: string) => { diff --git a/webapp/channels/src/components/advanced_text_editor/advanced_text_editor.tsx b/webapp/channels/src/components/advanced_text_editor/advanced_text_editor.tsx index dfdc290b5d..41c8a67b3b 100644 --- a/webapp/channels/src/components/advanced_text_editor/advanced_text_editor.tsx +++ b/webapp/channels/src/components/advanced_text_editor/advanced_text_editor.tsx @@ -88,7 +88,7 @@ type Props = { hideEmojiPicker: () => void; toggleAdvanceTextEditor: () => void; handleUploadProgress: (filePreviewInfo: FilePreviewInfo) => void; - handleUploadError: (err: string | ServerError, clientId?: string, channelId?: string) => void; + handleUploadError: (err: string | ServerError | null, clientId?: string, channelId?: string) => void; handleFileUploadComplete: (fileInfos: FileInfo[], clientIds: string[], channelId: string, rootId?: string) => void; handleUploadStart: (clientIds: string[], channelId: string) => void; handleFileUploadChange: () => void; @@ -199,17 +199,6 @@ const AdvanceTextEditor = ({ setKeepEditorInFocus(true); }, []); - let serverErrorJsx = null; - if (serverError) { - serverErrorJsx = ( - - ); - } - let attachmentPreview = null; if (!readOnlyChannel && (draft.fileInfos.length > 0 || draft.uploadsInProgress.length > 0)) { attachmentPreview = ( @@ -551,12 +540,20 @@ const AdvanceTextEditor = ({
- {postError && } - {serverErrorJsx} + {postError && ( + + )} + {serverError && ( + + )} { ); expect(baseProps.onUploadError).toHaveBeenCalledTimes(1); - expect(baseProps.onUploadError).toHaveBeenCalledWith(''); + expect(baseProps.onUploadError).toHaveBeenCalledWith(null); }); test('should error max upload files', () => { @@ -286,7 +284,7 @@ describe('components/FileUpload', () => { expect(baseProps.onUploadStart).toBeCalledWith([], props.channelId); expect(baseProps.onUploadError).toHaveBeenCalledTimes(2); - expect(baseProps.onUploadError.mock.calls[0][0]).toEqual(''); + expect(baseProps.onUploadError.mock.calls[0][0]).toEqual(null); }); test('should error max upload files', () => { @@ -306,7 +304,7 @@ describe('components/FileUpload', () => { expect(baseProps.onUploadStart).toBeCalledWith([], props.channelId); expect(baseProps.onUploadError).toHaveBeenCalledTimes(2); - expect(baseProps.onUploadError.mock.calls[0][0]).toEqual(''); + expect(baseProps.onUploadError.mock.calls[0][0]).toEqual(null); }); test('should error max too large files', () => { @@ -324,7 +322,7 @@ describe('components/FileUpload', () => { expect(baseProps.onUploadStart).toBeCalledWith([], baseProps.channelId); expect(baseProps.onUploadError).toHaveBeenCalledTimes(2); - expect(baseProps.onUploadError.mock.calls[0][0]).toEqual(''); + expect(baseProps.onUploadError.mock.calls[0][0]).toEqual(null); }); test('should functions when handleChange is called', () => { @@ -358,7 +356,7 @@ describe('components/FileUpload', () => { instance.handleDrop(e); expect(baseProps.onUploadError).toBeCalled(); - expect(baseProps.onUploadError).toHaveBeenCalledWith(''); + expect(baseProps.onUploadError).toHaveBeenCalledWith(null); expect(instance.uploadFiles).toBeCalled(); expect(instance.uploadFiles).toHaveBeenCalledWith(e.dataTransfer.files); @@ -386,7 +384,7 @@ describe('components/FileUpload', () => { expect(baseProps.onUploadStart).toHaveBeenCalledTimes(0); expect(baseProps.onUploadError).toHaveBeenCalledTimes(1); - expect(baseProps.onUploadError).toHaveBeenCalledWith(''); + expect(baseProps.onUploadError).toHaveBeenCalledWith(null); }); test('FilesWillUploadHook - should reject one file and allow one file', () => { @@ -409,6 +407,6 @@ describe('components/FileUpload', () => { expect(baseProps.onUploadStart).toHaveBeenCalledWith([expect.stringMatching(generatedIdRegex)], props.channelId); expect(baseProps.onUploadError).toHaveBeenCalledTimes(1); - expect(baseProps.onUploadError).toHaveBeenCalledWith(''); + expect(baseProps.onUploadError).toHaveBeenCalledWith(null); }); }); diff --git a/webapp/channels/src/components/file_upload/file_upload.tsx b/webapp/channels/src/components/file_upload/file_upload.tsx index db03376790..a41f617af5 100644 --- a/webapp/channels/src/components/file_upload/file_upload.tsx +++ b/webapp/channels/src/components/file_upload/file_upload.tsx @@ -120,7 +120,7 @@ export type Props = { /** * Function to be called when upload fails */ - onUploadError: (err: string | ServerError, clientId?: string, channelId?: string, currentRootId?: string) => void; + onUploadError: (err: string | ServerError | null, clientId?: string, channelId?: string, currentRootId?: string) => void; /** * Function to be called when file upload starts @@ -222,13 +222,13 @@ export class FileUpload extends PureComponent { pluginUploadFiles = (files: File[]) => { // clear any existing errors - this.props.onUploadError(''); + this.props.onUploadError(null); this.uploadFiles(files); }; checkPluginHooksAndUploadFiles = (files: FileList | File[]) => { // clear any existing errors - this.props.onUploadError(''); + this.props.onUploadError(null); let sortedFiles = Array.from(files).sort((a, b) => a.name.localeCompare(b.name, this.props.locale, {numeric: true})); @@ -335,7 +335,7 @@ export class FileUpload extends PureComponent { return; } - this.props.onUploadError(''); + this.props.onUploadError(null); const items = e.dataTransfer.items || []; const droppedFiles = e.dataTransfer.files; @@ -460,7 +460,7 @@ export class FileUpload extends PureComponent { return; } - this.props.onUploadError(''); + this.props.onUploadError(null); const items = []; for (let i = 0; i < e.clipboardData.items.length; i++) { diff --git a/webapp/channels/src/components/message_submit_error.tsx b/webapp/channels/src/components/message_submit_error.tsx index 1de774514c..bb8c5075dd 100644 --- a/webapp/channels/src/components/message_submit_error.tsx +++ b/webapp/channels/src/components/message_submit_error.tsx @@ -1,68 +1,56 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {ReactFragment} from 'react'; +import React, {MouseEventHandler} from 'react'; import {FormattedMessage} from 'react-intl'; import {ServerError} from '@mattermost/types/errors'; import {isErrorInvalidSlashCommand} from 'utils/post_utils'; -interface MessageSubmitErrorProps { +interface Props { error: ServerError; - handleSubmit: (e: React.MouseEvent) => void; + handleSubmit: MouseEventHandler; submittedMessage?: string; } -class MessageSubmitError extends React.PureComponent { - public renderSlashCommandError = (): string | ReactFragment => { - if (!this.props.submittedMessage) { - return this.props.error.message; - } - - const command = this.props.submittedMessage.split(' ')[0]; - return ( - - - - - - - ); - }; - - public render(): JSX.Element | null { - const error = this.props.error; - - if (!error) { - return null; - } - - let errorContent: string | ReactFragment = error.message; - if (isErrorInvalidSlashCommand(error)) { - errorContent = this.renderSlashCommandError(); - } +function MessageSubmitError(props: Props) { + if (isErrorInvalidSlashCommand(props.error)) { + const slashCommand = props.submittedMessage?.split(' ')[0]; return (
); } + + if (props.error?.message?.trim()?.length === 0) { + return null; + } + + return ( +
+ +
+ ); } export default MessageSubmitError;