chore: insert resolved variable value in reply editor (#14921)
# Pull Request Template
## Description
This PR makes reply editor variables insert their resolved value (for
example, the contact's name) instead of the raw `{{contact.name}}`
placeholder, matching canned response behavior. This works both when
picking a variable from the `{{` menu and when an agent manually types
out `{{contact.name}}` — it resolves the moment the closing `}}` is
typed.
If a variable has no value, the `{{placeholder}}` is kept so the backend
can still resolve it when the message is sent. Private notes are left
untouched.
For safety, a resolved value that itself contains Liquid syntax `({{ }}`
or `{% %})` also keeps its placeholder, so customer-controlled fields
can never inject Liquid into the outgoing message.
Fixes
https://linear.app/chatwoot/issue/CW-7528/reply-editor-inserts-variable-placeholder-instead-of-the-value
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
1. Open a conversation and add a reply.
2. Type `{{` and pick a variable that has a value (e.g. Contact name) →
it inserts the actual value.
3. Manually type `{{contact.name}}` and close the braces → it
auto-resolves to the value.
4. Insert/type a variable with no value → the `{{placeholder}}` stays;
confirm it resolves correctly on send.
5. Repeat in a private note → placeholders are left as-is.
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
This commit is contained in:
@@ -62,6 +62,7 @@ import {
|
||||
calculateMenuPosition,
|
||||
getEffectiveChannelType,
|
||||
stripUnsupportedFormatting,
|
||||
createVariableInputRule,
|
||||
} from 'dashboard/helper/editorHelper';
|
||||
import {
|
||||
hasPressedEnterAndNotCmdOrShift,
|
||||
@@ -306,6 +307,10 @@ const plugins = computed(() => {
|
||||
searchTerm: variableSearchTerm,
|
||||
isAllowed: () => !props.isPrivate,
|
||||
}),
|
||||
createVariableInputRule({
|
||||
isPrivate: () => props.isPrivate,
|
||||
getVariables: () => props.variables,
|
||||
}),
|
||||
createSuggestionPlugin({
|
||||
trigger: ':',
|
||||
minChars: 2,
|
||||
|
||||
@@ -48,6 +48,8 @@ import {
|
||||
appendSignature,
|
||||
removeSignature,
|
||||
getEffectiveChannelType,
|
||||
getAgentVariables,
|
||||
getContactVariables,
|
||||
} from 'dashboard/helper/editorHelper';
|
||||
import { useCopilotReply } from 'dashboard/composables/useCopilotReply';
|
||||
import { useKbd } from 'dashboard/composables/utils/useKbd';
|
||||
@@ -393,7 +395,13 @@ export default {
|
||||
contact: this.currentContact,
|
||||
inbox: this.inbox,
|
||||
});
|
||||
return variables;
|
||||
// Match the backend drops: names are Ruby-capitalized and
|
||||
// {{agent.*}} is the message sender, not the assignee.
|
||||
return {
|
||||
...variables,
|
||||
...getContactVariables(this.currentContact),
|
||||
...getAgentVariables(this.currentUser),
|
||||
};
|
||||
},
|
||||
connectedPortalSlug() {
|
||||
const { help_center: portal = {} } = this.inbox;
|
||||
|
||||
Reference in New Issue
Block a user