From 57ff3cc27b9470bfbe2486c3c1831c57f5a4075f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milorad=20FIlipovi=C4=87?= Date: Mon, 23 Sep 2024 13:05:15 +0200 Subject: [PATCH] fix(editor): Fix styling and typography in AI Assistant chat (#10895) --- cypress/pages/features/ai-assistant.ts | 2 +- .../AskAssistantChat.stories.ts | 104 ++++++++++++++ .../AskAssistantChat/AskAssistantChat.vue | 130 ++++++++++++++++-- .../AskAssistantChat.spec.ts.snap | 104 +++++++------- .../design-system/src/directives/n8n-html.ts | 1 + packages/design-system/src/locale/lang/en.ts | 2 + 6 files changed, 284 insertions(+), 59 deletions(-) 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 '
'; +}; + +md.renderer.rules.table_close = function () { + return '
'; +}; const MAX_CHAT_INPUT_HEIGHT = 100; @@ -65,6 +74,10 @@ const showPlaceholder = computed(() => { return !props.messages?.length && !props.loadingMessage && !props.sessionId; }); +const isClipboardSupported = computed(() => { + return navigator.clipboard?.writeText; +}); + function isEndOfSessionEvent(event?: ChatUI.AssistantMessage) { return event?.type === 'event' && event?.eventName === 'end-session'; } @@ -97,6 +110,15 @@ function growInput() { const scrollHeight = chatInput.value.scrollHeight; chatInput.value.style.height = `${Math.min(scrollHeight, MAX_CHAT_INPUT_HEIGHT)}px`; } + +async function onCopyButtonClick(content: string, e: MouseEvent) { + const button = e.target as HTMLButtonElement; + await navigator.clipboard.writeText(content); + button.innerText = t('assistantChat.copied'); + setTimeout(() => { + button.innerText = t('assistantChat.copy'); + }, 2000); +}