From 45c4090e3183df95b1e80057af92e1bf838eadfa Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 19 Apr 2022 10:44:54 -0600 Subject: [PATCH 1/7] skip parser for long comments --- src/libs/actions/Report.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index eb01d496f6a3..0ebbc291001a 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1081,9 +1081,11 @@ function fetchAllReports( * @param {File} [file] */ function addAction(reportID, text, file) { - // Convert the comment from MD into HTML because that's how it is stored in the database + // For comments shorter than 10k chars, convert the comment from MD into HTML because that's how it is stored in the database + // For longer comments, skip parsing and display plaintext for performance reasons. It takes over 40s to parse a 100k long string!! const parser = new ExpensiMark(); - const commentText = parser.replace(text); + const commentText = text.length < 10000 ? parser.replace(text) : text; + const isAttachment = _.isEmpty(text) && file !== undefined; const attachmentInfo = isAttachment ? file : {}; From 75074d02b6b86ef9fc04c171dc7e0db898da7a8e Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 20 Apr 2022 12:34:28 -0600 Subject: [PATCH 2/7] display char limit error and disable send --- src/languages/en.js | 1 + src/libs/actions/Report.js | 1 - src/pages/home/report/ReportActionCompose.js | 50 ++++++++++++------- .../home/report/ReportTypingIndicator.js | 24 ++++----- 4 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index bae9a50e62ee..f44c75826643 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -159,6 +159,7 @@ export default { blockedFromConcierge: 'Communication is barred', youAppearToBeOffline: 'You appear to be offline.', fileUploadFailed: 'Upload failed. File is not supported.', + charLimitReached: ({commentLength}) => `You have reached the character limit (${commentLength}/60000)`, localTime: ({user, time}) => `It's ${time} for ${user}`, edited: '(edited)', emoji: 'Emoji', diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 0ebbc291001a..76c4c80d565f 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1085,7 +1085,6 @@ function addAction(reportID, text, file) { // For longer comments, skip parsing and display plaintext for performance reasons. It takes over 40s to parse a 100k long string!! const parser = new ExpensiMark(); const commentText = text.length < 10000 ? parser.replace(text) : text; - const isAttachment = _.isEmpty(text) && file !== undefined; const attachmentInfo = isAttachment ? file : {}; diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 6517fef5d24a..ca4a61503b8d 100755 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -401,6 +401,10 @@ class ReportActionCompose extends React.Component { const isComposeDisabled = this.props.isDrawerOpen && this.props.isSmallScreenWidth; const isBlockedFromConcierge = ReportUtils.chatIncludesConcierge(this.props.report) && User.isBlockedFromConcierge(this.props.blockedFromConcierge); const inputPlaceholder = this.getInputPlaceholder(); + + const commentLength = this.props.comment.length; + const hasReachedCharLimit = commentLength > 3; + return ( {shouldShowReportRecipientLocalTime @@ -411,6 +415,7 @@ class ReportActionCompose extends React.Component { : styles.chatItemComposeBoxColor, styles.chatItemComposeBox, styles.flexRow, + hasReachedCharLimit && styles.borderColorDanger, ]} > e.preventDefault()} - disabled={this.state.isCommentEmpty || isBlockedFromConcierge} + disabled={this.state.isCommentEmpty || isBlockedFromConcierge || hasReachedCharLimit} hitSlop={{ top: 3, right: 3, bottom: 3, left: 3, }} @@ -583,24 +588,31 @@ class ReportActionCompose extends React.Component { - {this.props.network.isOffline ? ( - - - - - {this.props.translate('reportActionCompose.youAppearToBeOffline')} - - + + + {this.props.network.isOffline ? ( + + + + {this.props.translate('reportActionCompose.youAppearToBeOffline')} + + + ) : } - ) : } + {hasReachedCharLimit && ( + + {this.props.translate('reportActionCompose.charLimitReached', {commentLength})} + + )} + ); } diff --git a/src/pages/home/report/ReportTypingIndicator.js b/src/pages/home/report/ReportTypingIndicator.js index aea493cadeb3..8bc2c53ee3ec 100755 --- a/src/pages/home/report/ReportTypingIndicator.js +++ b/src/pages/home/report/ReportTypingIndicator.js @@ -50,7 +50,7 @@ class ReportTypingIndicator extends React.Component { // Decide on the Text element that will hold the display based on the number of users that are typing. switch (numUsersTyping) { case 0: - return ; + return <>; case 1: return ( - - {this.props.translate('reportTypingIndicator.multipleUsers')} - {` ${this.props.translate('reportTypingIndicator.areTyping')}`} - - + + {this.props.translate('reportTypingIndicator.multipleUsers')} + {` ${this.props.translate('reportTypingIndicator.areTyping')}`} + ); } } From cae1ad7a56addf85d1347bf9b1a88c6393c7c40d Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 20 Apr 2022 13:24:42 -0600 Subject: [PATCH 3/7] add copy and styles --- src/languages/en.js | 2 +- src/languages/es.js | 1 + src/pages/home/report/ReportActionCompose.js | 19 +++++++++---------- .../home/report/ReportTypingIndicator.js | 1 - 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index f44c75826643..790f6538d3b4 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -159,7 +159,7 @@ export default { blockedFromConcierge: 'Communication is barred', youAppearToBeOffline: 'You appear to be offline.', fileUploadFailed: 'Upload failed. File is not supported.', - charLimitReached: ({commentLength}) => `You have reached the character limit (${commentLength}/60000)`, + maxCommentLengthReached: 'Limit of 60000 characters exceeded', localTime: ({user, time}) => `It's ${time} for ${user}`, edited: '(edited)', emoji: 'Emoji', diff --git a/src/languages/es.js b/src/languages/es.js index cbcae7c6b619..093324a18791 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -159,6 +159,7 @@ export default { blockedFromConcierge: 'Comunicación no permitida', youAppearToBeOffline: 'Parece que estás desconectado.', fileUploadFailed: 'Subida fallida. El archivo no es compatible.', + maxCommentLengthReached: 'Límite de 60000 caracteres excedido', localTime: ({user, time}) => `Son las ${time} para ${user}`, edited: '(editado)', emoji: 'Emoji', diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index ca4a61503b8d..ccedfa4bc956 100755 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -128,6 +128,7 @@ class ReportActionCompose extends React.Component { this.onSelectionChange = this.onSelectionChange.bind(this); this.setTextInputRef = this.setTextInputRef.bind(this); this.getInputPlaceholder = this.getInputPlaceholder.bind(this); + this.maxCommentLength = 60_000; this.state = { isFocused: this.shouldFocusInputOnScreenFocus, @@ -370,8 +371,8 @@ class ReportActionCompose extends React.Component { const trimmedComment = this.comment.trim(); - // Don't submit empty comments - if (!trimmedComment) { + // Don't submit empty comments or comments that exceed the character limit + if (!trimmedComment || trimmedComment.length > this.maxCommentLength) { return; } @@ -401,9 +402,7 @@ class ReportActionCompose extends React.Component { const isComposeDisabled = this.props.isDrawerOpen && this.props.isSmallScreenWidth; const isBlockedFromConcierge = ReportUtils.chatIncludesConcierge(this.props.report) && User.isBlockedFromConcierge(this.props.blockedFromConcierge); const inputPlaceholder = this.getInputPlaceholder(); - - const commentLength = this.props.comment.length; - const hasReachedCharLimit = commentLength > 3; + const hasExceededMaxCommentLength = this.comment.length > this.maxCommentLength; return ( @@ -415,7 +414,7 @@ class ReportActionCompose extends React.Component { : styles.chatItemComposeBoxColor, styles.chatItemComposeBox, styles.flexRow, - hasReachedCharLimit && styles.borderColorDanger, + hasExceededMaxCommentLength && styles.borderColorDanger, ]} > e.preventDefault()} - disabled={this.state.isCommentEmpty || isBlockedFromConcierge || hasReachedCharLimit} + disabled={this.state.isCommentEmpty || isBlockedFromConcierge || hasExceededMaxCommentLength} hitSlop={{ top: 3, right: 3, bottom: 3, left: 3, }} @@ -607,9 +606,9 @@ class ReportActionCompose extends React.Component { ) : } - {hasReachedCharLimit && ( + {hasExceededMaxCommentLength && ( - {this.props.translate('reportActionCompose.charLimitReached', {commentLength})} + {this.props.translate('reportActionCompose.maxCommentLengthReached')} )} diff --git a/src/pages/home/report/ReportTypingIndicator.js b/src/pages/home/report/ReportTypingIndicator.js index 8bc2c53ee3ec..ee43a3a004ff 100755 --- a/src/pages/home/report/ReportTypingIndicator.js +++ b/src/pages/home/report/ReportTypingIndicator.js @@ -1,5 +1,4 @@ import React from 'react'; -import {View} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; import {withOnyx} from 'react-native-onyx'; From f4fca97f685cd22d4c2ee8e10910cc13b7518e68 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 20 Apr 2022 13:36:22 -0600 Subject: [PATCH 4/7] add comment --- src/pages/home/report/ReportActionCompose.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index ccedfa4bc956..d28891311121 100755 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -128,6 +128,8 @@ class ReportActionCompose extends React.Component { this.onSelectionChange = this.onSelectionChange.bind(this); this.setTextInputRef = this.setTextInputRef.bind(this); this.getInputPlaceholder = this.getInputPlaceholder.bind(this); + + // There's a limit of 60k characters in Auth - https://github.com/Expensify/Auth/blob/198d59547f71fdee8121325e8bc9241fc9c3236a/auth/lib/Request.h#L28 this.maxCommentLength = 60_000; this.state = { From d27212e6111ca7179e5e9f0f7273f94b776d0ef5 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 20 Apr 2022 14:54:35 -0600 Subject: [PATCH 5/7] add styles --- src/pages/home/report/ReportActionCompose.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index d28891311121..a50fd6df6518 100755 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -609,7 +609,7 @@ class ReportActionCompose extends React.Component { ) : } {hasExceededMaxCommentLength && ( - + {this.props.translate('reportActionCompose.maxCommentLengthReached')} )} From 1ef69a13bdd6cff0dfceeaf32ad2db664f7d5e57 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 20 Apr 2022 15:37:03 -0600 Subject: [PATCH 6/7] rm copy --- src/languages/en.js | 1 - src/languages/es.js | 1 - src/pages/home/report/ReportActionCompose.js | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index 790f6538d3b4..bae9a50e62ee 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -159,7 +159,6 @@ export default { blockedFromConcierge: 'Communication is barred', youAppearToBeOffline: 'You appear to be offline.', fileUploadFailed: 'Upload failed. File is not supported.', - maxCommentLengthReached: 'Limit of 60000 characters exceeded', localTime: ({user, time}) => `It's ${time} for ${user}`, edited: '(edited)', emoji: 'Emoji', diff --git a/src/languages/es.js b/src/languages/es.js index 093324a18791..cbcae7c6b619 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -159,7 +159,6 @@ export default { blockedFromConcierge: 'Comunicación no permitida', youAppearToBeOffline: 'Parece que estás desconectado.', fileUploadFailed: 'Subida fallida. El archivo no es compatible.', - maxCommentLengthReached: 'Límite de 60000 caracteres excedido', localTime: ({user, time}) => `Son las ${time} para ${user}`, edited: '(editado)', emoji: 'Emoji', diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index a50fd6df6518..e163a3c3c7f8 100755 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -610,7 +610,7 @@ class ReportActionCompose extends React.Component { {hasExceededMaxCommentLength && ( - {this.props.translate('reportActionCompose.maxCommentLengthReached')} + {`${this.comment.length}/${this.maxCommentLength}`} )} From 2517acafa15d0212e5ea0e40c35b9092eefc0e30 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 20 Apr 2022 16:49:46 -0600 Subject: [PATCH 7/7] move limit to const --- src/CONST.js | 3 +++ src/pages/home/report/ReportActionCompose.js | 9 +++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index de79fdcb71cc..4d3c9a80f79c 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -657,6 +657,9 @@ const CONST = { this.EMAIL.ADMIN, ]; }, + + // There's a limit of 60k characters in Auth - https://github.com/Expensify/Auth/blob/198d59547f71fdee8121325e8bc9241fc9c3236a/auth/lib/Request.h#L28 + MAX_COMMENT_LENGTH: 60_000, }; export default CONST; diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index e163a3c3c7f8..94baafa5bd59 100755 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -129,9 +129,6 @@ class ReportActionCompose extends React.Component { this.setTextInputRef = this.setTextInputRef.bind(this); this.getInputPlaceholder = this.getInputPlaceholder.bind(this); - // There's a limit of 60k characters in Auth - https://github.com/Expensify/Auth/blob/198d59547f71fdee8121325e8bc9241fc9c3236a/auth/lib/Request.h#L28 - this.maxCommentLength = 60_000; - this.state = { isFocused: this.shouldFocusInputOnScreenFocus, textInputShouldClear: false, @@ -374,7 +371,7 @@ class ReportActionCompose extends React.Component { const trimmedComment = this.comment.trim(); // Don't submit empty comments or comments that exceed the character limit - if (!trimmedComment || trimmedComment.length > this.maxCommentLength) { + if (!trimmedComment || trimmedComment.length > CONST.MAX_COMMENT_LENGTH) { return; } @@ -404,7 +401,7 @@ class ReportActionCompose extends React.Component { const isComposeDisabled = this.props.isDrawerOpen && this.props.isSmallScreenWidth; const isBlockedFromConcierge = ReportUtils.chatIncludesConcierge(this.props.report) && User.isBlockedFromConcierge(this.props.blockedFromConcierge); const inputPlaceholder = this.getInputPlaceholder(); - const hasExceededMaxCommentLength = this.comment.length > this.maxCommentLength; + const hasExceededMaxCommentLength = this.comment.length > CONST.MAX_COMMENT_LENGTH; return ( @@ -610,7 +607,7 @@ class ReportActionCompose extends React.Component { {hasExceededMaxCommentLength && ( - {`${this.comment.length}/${this.maxCommentLength}`} + {`${this.comment.length}/${CONST.MAX_COMMENT_LENGTH}`} )}