diff --git a/cypress/pages/features/ai-assistant.ts b/cypress/pages/features/ai-assistant.ts index ea77724dcf..b97f020ccf 100644 --- a/cypress/pages/features/ai-assistant.ts +++ b/cypress/pages/features/ai-assistant.ts @@ -37,7 +37,7 @@ export class AIAssistant extends BasePage { cy.getByTestId('node-error-view-ask-assistant-button').find('button').first(), credentialEditAssistantButton: () => cy.getByTestId('credentail-edit-ask-assistant-button').find('button').first(), - codeSnippet: () => cy.getByTestId('assistant-code-snippet'), + codeSnippet: () => cy.getByTestId('assistant-code-snippet-content'), }; actions = { diff --git a/packages/design-system/src/components/AskAssistantChat/AskAssistantChat.stories.ts b/packages/design-system/src/components/AskAssistantChat/AskAssistantChat.stories.ts index aa0e2bd19f..d87e41e1ed 100644 --- a/packages/design-system/src/components/AskAssistantChat/AskAssistantChat.stories.ts +++ b/packages/design-system/src/components/AskAssistantChat/AskAssistantChat.stories.ts @@ -268,3 +268,107 @@ WithCodeSnippet.args = { }, ]), }; + +export const RichTextMessage = Template.bind({}); +RichTextMessage.args = { + user: { + firstName: 'Kobi', + lastName: 'Dog', + }, + messages: getMessages([ + { + id: '29083188', + role: 'user', + type: 'text', + content: 'Hey', + read: true, + }, + { + id: '29083188', + type: 'text', + role: 'assistant', + content: 'Hello Kobi! How can I assist you with n8n today?', + read: true, + }, + { + id: '21514129', + role: 'user', + type: 'text', + content: 'Can you show me a message example with paragraphs, lists and links?', + read: true, + }, + { + id: '21514129', + type: 'text', + role: 'assistant', + content: + "Sure: \n\nTo connect your Slack account to n8n, follow these steps:\n\n1. Open your [Slack API Apps](https://api.slack.com/apps) page.\n2. Select **Create New App > From scratch**.\n3. Enter an **App Name**.\n4. Select the **Workspace** where you'll be developing your app.\n5. Select **Create App**.\n6. In **Basic Information**, open the **App Credentials** section.\n7. Copy the **Client ID** and **Client Secret**. Paste these into the corresponding fields in n8n.\n8. In **Basic Information > Building Apps for Slack**, select **Add features and functionality**.\n9. Select **Permissions**.\n10. In the **Redirect URLs** section, select **Add New Redirect URL**.\n\nFor more details, you can refer to the [Slack API Quickstart](https://api.slack.com/quickstart) and the [Installing with OAuth](https://api.slack.com/authentication/oauth-v2) documentation.", + codeSnippet: '', + read: true, + }, + { + id: '86572001', + role: 'user', + type: 'text', + content: 'Can you show me an example of a table?', + read: true, + }, + { + id: '86572001', + type: 'text', + role: 'assistant', + content: + 'Sure, here it is:\n\n| **Scope name** | **Notes** |\n| --- | --- |\n| `channels:read` | |\n| `channels:write` | Not available as a bot token scope |\n| `stars:read`| Not available as a bot token scope |\n| `stars:write` | Not available as a bot token scope |\n| `users.profile:write` | Not available as a bot token scope |\n| `users:read` | |', + read: true, + }, + { + id: '86572001', + role: 'user', + type: 'text', + content: 'Thanks, can you send me another one with more columns?', + read: true, + }, + { + id: '86572001', + type: 'text', + role: 'assistant', + content: + 'Yup:\n\n| **Scope name** | **Notes** | **One More Column** |\n| --- | --- | --- |\n| `channels:read` | | Something else |\n| `channels:write` | Not available as a bot token scope | Something else |\n| `stars:read`| Not available as a bot token scope |\n| `stars:write` | Not available as a bot token scope |\n| `users.profile:write` | Not available as a bot token scope |\n| `users:read` | |', + read: true, + }, + { + id: '2556642', + role: 'user', + type: 'text', + content: 'Great', + read: true, + }, + { + id: '2556642', + type: 'text', + role: 'assistant', + content: + "I'm glad you found the information helpful! If you have any more questions about n8n or need further assistance, feel free to ask.", + read: true, + }, + { + id: '2556642', + type: 'text', + role: 'assistant', + content: 'Did this answer solve your question?', + quickReplies: [ + { + text: 'Yes, thanks', + type: 'all-good', + isFeedback: true, + }, + { + text: 'No, I am still stuck', + type: 'still-stuck', + isFeedback: true, + }, + ], + read: true, + }, + ]), +}; diff --git a/packages/design-system/src/components/AskAssistantChat/AskAssistantChat.vue b/packages/design-system/src/components/AskAssistantChat/AskAssistantChat.vue index 3b52dd54d8..1acffa82fa 100644 --- a/packages/design-system/src/components/AskAssistantChat/AskAssistantChat.vue +++ b/packages/design-system/src/components/AskAssistantChat/AskAssistantChat.vue @@ -18,12 +18,21 @@ const { t } = useI18n(); const md = new Markdown({ breaks: true, -}).use(markdownLink, { +}); +md.use(markdownLink, { attrs: { target: '_blank', rel: 'noopener', }, }); +// Wrap tables in div +md.renderer.rules.table_open = function () { + return '
Hi Max! Here is my top solution to fix the error in your @@ -434,7 +434,9 @@ exports[`AskAssistantChat > renders chat with messages correctly 1`] = `
Give it to me
@@ -511,7 +513,9 @@ exports[`AskAssistantChat > renders chat with messages correctly 1`] = `
Solution steps:
Hi Max! Here is my top solution to fix the error in your
@@ -1300,7 +1304,7 @@ exports[`AskAssistantChat > renders message with code snippet 1`] = `
class="textMessage"
>
Hi Max! Here is my top solution to fix the error in your
@@ -1316,66 +1320,72 @@ exports[`AskAssistantChat > renders message with code snippet 1`] = `
class="code-snippet"
data-test-id="assistant-code-snippet"
>
-
- node.on('input', function(msg) {
-
+ node.on('input', function(msg) {
+
Hi Max! Here is my top solution to fix the error in your
diff --git a/packages/design-system/src/directives/n8n-html.ts b/packages/design-system/src/directives/n8n-html.ts
index 875905d1d9..9ce3aa8439 100644
--- a/packages/design-system/src/directives/n8n-html.ts
+++ b/packages/design-system/src/directives/n8n-html.ts
@@ -24,6 +24,7 @@ const configuredSanitize = (html: string) =>
input: ['type', 'id', 'checked'],
code: ['class'],
a: sanitize.defaults.allowedAttributes.a.concat(['data-*']),
+ div: ['class'],
},
});
diff --git a/packages/design-system/src/locale/lang/en.ts b/packages/design-system/src/locale/lang/en.ts
index 45caa4071e..e6163b2d38 100644
--- a/packages/design-system/src/locale/lang/en.ts
+++ b/packages/design-system/src/locale/lang/en.ts
@@ -44,5 +44,7 @@ export default {
'assistantChat.placeholder.3': 'button in the UI.',
'assistantChat.placeholder.4': 'How can I help?',
'assistantChat.inputPlaceholder': 'Enter your response...',
+ 'assistantChat.copy': 'Copy',
+ 'assistantChat.copied': 'Copied',
'inlineAskAssistantButton.asked': 'Asked',
} as N8nLocale;
-
+
+
+
if (msg.seed) { dummyjson.seed = msg.seed; }
-
-
+
+
try {
-
-
+
+
var value = dummyjson.parse(node.template, {mockdata: msg});
-
-
+
+
if (node.syntax === 'json') {
-
-
+
+
try { value = JSON.parse(value); }
-
-
+
+
catch(e) { node.error(RED._('datagen.errors.json-error')); }
-
-
+
+
}
-
-
+
+
if (node.fieldType === 'msg') {
-
-
+
+
RED.util.setMessageProperty(msg,node.field,value);
-
-
+
+
}
-
-
+
+
else if (node.fieldType === 'flow') {
-
-
+
+
node.context().flow.set(node.field,value);
-
-
+
+
}
-
-
+
+
else if (node.fieldType === 'global') {
-
-
+
+
node.context().global.set(node.field,value);
-
-
+
+
}
-
-
+
+
node.send(msg);
-
-
+
+
}
-
-
+
+
catch(e) {
-