Compare commits
3
Commits
develop
...
fix/CW-6110
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df7ec0ca60 | ||
|
|
d67d8b373f | ||
|
|
3809d44d29 |
@@ -12,6 +12,23 @@ import {
|
|||||||
} from 'dashboard/constants/editor';
|
} from 'dashboard/constants/editor';
|
||||||
import camelcaseKeys from 'camelcase-keys';
|
import camelcaseKeys from 'camelcase-keys';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes zero-width spaces and related invisible characters from text.
|
||||||
|
* Also handles backslash-newline patterns from hard breaks (Shift+Enter).
|
||||||
|
* These characters can interfere with signature detection and content handling.
|
||||||
|
*
|
||||||
|
* @param {string} text - The text to clean
|
||||||
|
* @returns {string} - The cleaned text without zero-width spaces
|
||||||
|
*/
|
||||||
|
export function removeZeroWidthSpaces(text) {
|
||||||
|
if (!text) return '';
|
||||||
|
return text
|
||||||
|
.replace(/\u200B\\\n/g, '\n') // Remove zero-width space + backslash + newline, keep newline
|
||||||
|
.replace(/\u200B\n/g, '\n') // Remove zero-width space + newline, keep newline
|
||||||
|
.replace(/\\\n/g, '\n') // Remove backslash before newline (hard break), keep newline
|
||||||
|
.replace(/\u200B/g, ''); // Remove standalone zero-width spaces
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract text from markdown, and remove all images, code blocks, links, headers, bold, italic, lists etc.
|
* Extract text from markdown, and remove all images, code blocks, links, headers, bold, italic, lists etc.
|
||||||
* Links will be converted to text, and not removed.
|
* Links will be converted to text, and not removed.
|
||||||
@@ -46,6 +63,9 @@ export const SIGNATURE_DELIMITER = '--';
|
|||||||
*/
|
*/
|
||||||
export function cleanSignature(signature) {
|
export function cleanSignature(signature) {
|
||||||
try {
|
try {
|
||||||
|
// Remove zero-width spaces before processing
|
||||||
|
signature = removeZeroWidthSpaces(signature);
|
||||||
|
|
||||||
// remove any horizontal rule tokens
|
// remove any horizontal rule tokens
|
||||||
signature = signature
|
signature = signature
|
||||||
.replace(/^( *\* *){3,} *$/gm, '')
|
.replace(/^( *\* *){3,} *$/gm, '')
|
||||||
@@ -55,14 +75,17 @@ export function cleanSignature(signature) {
|
|||||||
const nodes = new MessageMarkdownTransformer(messageSchema).parse(
|
const nodes = new MessageMarkdownTransformer(messageSchema).parse(
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
return MessageMarkdownSerializer.serialize(nodes);
|
let result = MessageMarkdownSerializer.serialize(nodes);
|
||||||
|
|
||||||
|
// Remove zero-width spaces after serialization as well
|
||||||
|
return removeZeroWidthSpaces(result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
Sentry.captureException(e);
|
Sentry.captureException(e);
|
||||||
// The parser can break on some cases
|
// The parser can break on some cases
|
||||||
// for example, Token type `hr` not supported by Markdown parser
|
// for example, Token type `hr` not supported by Markdown parser
|
||||||
return signature;
|
return removeZeroWidthSpaces(signature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +108,8 @@ function appendDelimiter(signature) {
|
|||||||
* @returns {number} - The index of the last occurrence of the signature in the body, or -1 if not found.
|
* @returns {number} - The index of the last occurrence of the signature in the body, or -1 if not found.
|
||||||
*/
|
*/
|
||||||
export function findSignatureInBody(body, signature) {
|
export function findSignatureInBody(body, signature) {
|
||||||
const trimmedBody = body.trimEnd();
|
// Remove zero-width spaces from body before comparison
|
||||||
|
const trimmedBody = removeZeroWidthSpaces(body).trimEnd();
|
||||||
const cleanedSignature = cleanSignature(signature);
|
const cleanedSignature = cleanSignature(signature);
|
||||||
|
|
||||||
// check if body ends with signature
|
// check if body ends with signature
|
||||||
@@ -116,6 +140,9 @@ export function supportsImageSignature(channelType) {
|
|||||||
* @returns {string} - The body with the signature appended.
|
* @returns {string} - The body with the signature appended.
|
||||||
*/
|
*/
|
||||||
export function appendSignature(body, signature, channelType) {
|
export function appendSignature(body, signature, channelType) {
|
||||||
|
// Remove zero-width spaces from body before processing
|
||||||
|
const cleanedBody = removeZeroWidthSpaces(body);
|
||||||
|
|
||||||
// For channels that don't support images, strip markdown formatting
|
// For channels that don't support images, strip markdown formatting
|
||||||
const shouldStripImages = channelType && !supportsImageSignature(channelType);
|
const shouldStripImages = channelType && !supportsImageSignature(channelType);
|
||||||
const preparedSignature = shouldStripImages
|
const preparedSignature = shouldStripImages
|
||||||
@@ -123,11 +150,11 @@ export function appendSignature(body, signature, channelType) {
|
|||||||
: signature;
|
: signature;
|
||||||
const cleanedSignature = cleanSignature(preparedSignature);
|
const cleanedSignature = cleanSignature(preparedSignature);
|
||||||
// if signature is already present, return body
|
// if signature is already present, return body
|
||||||
if (findSignatureInBody(body, cleanedSignature) > -1) {
|
if (findSignatureInBody(cleanedBody, cleanedSignature) > -1) {
|
||||||
return body;
|
return cleanedBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${body.trimEnd()}\n\n${appendDelimiter(cleanedSignature)}`;
|
return `${cleanedBody.trimEnd()}\n\n${appendDelimiter(cleanedSignature)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,6 +166,9 @@ export function appendSignature(body, signature, channelType) {
|
|||||||
* @returns {string} - The body with the signature removed.
|
* @returns {string} - The body with the signature removed.
|
||||||
*/
|
*/
|
||||||
export function removeSignature(body, signature) {
|
export function removeSignature(body, signature) {
|
||||||
|
// Remove zero-width spaces from body before processing
|
||||||
|
let newBody = removeZeroWidthSpaces(body);
|
||||||
|
|
||||||
// Build list of signatures to try: original first, then stripped version
|
// Build list of signatures to try: original first, then stripped version
|
||||||
// Always try both to handle cases where channelType is unknown or inbox is being removed
|
// Always try both to handle cases where channelType is unknown or inbox is being removed
|
||||||
const cleanedSignature = cleanSignature(signature);
|
const cleanedSignature = cleanSignature(signature);
|
||||||
@@ -150,13 +180,10 @@ export function removeSignature(body, signature) {
|
|||||||
|
|
||||||
// Find the first matching signature
|
// Find the first matching signature
|
||||||
const signatureIndex = signaturesToTry.reduce(
|
const signatureIndex = signaturesToTry.reduce(
|
||||||
(index, sig) => (index === -1 ? findSignatureInBody(body, sig) : index),
|
(index, sig) => (index === -1 ? findSignatureInBody(newBody, sig) : index),
|
||||||
-1
|
-1
|
||||||
);
|
);
|
||||||
|
|
||||||
// no need to trim the ends here, because it will simply be removed in the next method
|
|
||||||
let newBody = body;
|
|
||||||
|
|
||||||
// if signature is present, remove it and trim it
|
// if signature is present, remove it and trim it
|
||||||
// trimming will ensure any spaces or new lines before the signature are removed
|
// trimming will ensure any spaces or new lines before the signature are removed
|
||||||
// This means we will have the delimiter at the end
|
// This means we will have the delimiter at the end
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@breezystack/lamejs": "^1.2.7",
|
"@breezystack/lamejs": "^1.2.7",
|
||||||
"@chatwoot/ninja-keys": "1.2.3",
|
"@chatwoot/ninja-keys": "1.2.3",
|
||||||
"@chatwoot/prosemirror-schema": "1.2.6",
|
"@chatwoot/prosemirror-schema": "1.2.9",
|
||||||
"@chatwoot/utils": "^0.0.51",
|
"@chatwoot/utils": "^0.0.51",
|
||||||
"@formkit/core": "^1.6.7",
|
"@formkit/core": "^1.6.7",
|
||||||
"@formkit/vue": "^1.6.7",
|
"@formkit/vue": "^1.6.7",
|
||||||
|
|||||||
Generated
+5
-5
@@ -20,8 +20,8 @@ importers:
|
|||||||
specifier: 1.2.3
|
specifier: 1.2.3
|
||||||
version: 1.2.3
|
version: 1.2.3
|
||||||
'@chatwoot/prosemirror-schema':
|
'@chatwoot/prosemirror-schema':
|
||||||
specifier: 1.2.6
|
specifier: 1.2.9
|
||||||
version: 1.2.6
|
version: 1.2.9
|
||||||
'@chatwoot/utils':
|
'@chatwoot/utils':
|
||||||
specifier: ^0.0.51
|
specifier: ^0.0.51
|
||||||
version: 0.0.51
|
version: 0.0.51
|
||||||
@@ -421,8 +421,8 @@ packages:
|
|||||||
'@chatwoot/ninja-keys@1.2.3':
|
'@chatwoot/ninja-keys@1.2.3':
|
||||||
resolution: {integrity: sha512-xM8d9P5ikDMZm2WbaCTk/TW5HFauylrU3cJ75fq5je6ixKwyhl/0kZbVN/vbbZN4+AUX/OaSIn6IJbtCgIF67g==}
|
resolution: {integrity: sha512-xM8d9P5ikDMZm2WbaCTk/TW5HFauylrU3cJ75fq5je6ixKwyhl/0kZbVN/vbbZN4+AUX/OaSIn6IJbtCgIF67g==}
|
||||||
|
|
||||||
'@chatwoot/prosemirror-schema@1.2.6':
|
'@chatwoot/prosemirror-schema@1.2.9':
|
||||||
resolution: {integrity: sha512-ej60kU3m/tP0VoGkOJhj0X+Mxt7fEX5DSEE4IibCZnTM4kMewkMxSYyPu0AXqaA4nKX1hTMrwcbv1t7gVQttWQ==}
|
resolution: {integrity: sha512-RTxjyoVTkvigt5wtInLD5apxErJwlsxepQBjB80QYmJD5x/RPNwMpnK1+xT+4yaNxVCnumNgIzSnFd4OpWaJgw==}
|
||||||
|
|
||||||
'@chatwoot/utils@0.0.51':
|
'@chatwoot/utils@0.0.51':
|
||||||
resolution: {integrity: sha512-WlEmWfOTzR7YZRUWzn5Wpm15/BRudpwqoNckph8TohyDbiim1CP4UZGa+qjajxTbNGLLhtKlm0Xl+X16+5Wceg==}
|
resolution: {integrity: sha512-WlEmWfOTzR7YZRUWzn5Wpm15/BRudpwqoNckph8TohyDbiim1CP4UZGa+qjajxTbNGLLhtKlm0Xl+X16+5Wceg==}
|
||||||
@@ -4862,7 +4862,7 @@ snapshots:
|
|||||||
hotkeys-js: 3.8.7
|
hotkeys-js: 3.8.7
|
||||||
lit: 2.2.6
|
lit: 2.2.6
|
||||||
|
|
||||||
'@chatwoot/prosemirror-schema@1.2.6':
|
'@chatwoot/prosemirror-schema@1.2.9':
|
||||||
dependencies:
|
dependencies:
|
||||||
markdown-it-sup: 2.0.0
|
markdown-it-sup: 2.0.0
|
||||||
prosemirror-commands: 1.6.0
|
prosemirror-commands: 1.6.0
|
||||||
|
|||||||
Reference in New Issue
Block a user