@quidgest/chatbot 0.5.3-dev.0 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/components/ChatBot/ChatBot.vue.d.ts +0 -2
  2. package/dist/components/ChatBot/types.d.ts +4 -3
  3. package/dist/components/ChatBotInput/ChatBotInput.vue.d.ts +3 -3
  4. package/dist/components/ChatBotInput/index.d.ts +2 -2
  5. package/dist/components/ChatBotInput/types.d.ts +4 -4
  6. package/dist/components/ChatBotMessage/ChatBotMessage.vue.d.ts +1 -3
  7. package/dist/components/ChatBotMessage/__tests__/ChatBotMessage.spec.d.ts +1 -0
  8. package/dist/components/ChatBotMessage/types.d.ts +3 -2
  9. package/dist/components/FieldPreview/FieldPreview.vue.d.ts +0 -2
  10. package/dist/composables/useChatApi.d.ts +1 -1
  11. package/dist/composables/useChatMessages.d.ts +2 -2
  12. package/dist/composables/useTexts.d.ts +1 -4
  13. package/dist/index.js +25 -25
  14. package/dist/index.mjs +2308 -1661
  15. package/dist/style.css +1 -1
  16. package/package.json +3 -2
  17. package/src/assets/styles/preview-file.scss +70 -0
  18. package/src/assets/styles/styles.scss +9 -33
  19. package/src/components/ChatBot/ChatBot.vue +70 -71
  20. package/src/components/ChatBot/types.ts +4 -3
  21. package/src/components/ChatBotInput/ChatBotInput.vue +81 -74
  22. package/src/components/ChatBotInput/__tests__/ChatBotInput.spec.ts +29 -42
  23. package/src/components/ChatBotInput/__tests__/__snapshots__/ChatBotInput.spec.ts.snap +5 -5
  24. package/src/components/ChatBotInput/index.ts +2 -2
  25. package/src/components/ChatBotInput/types.ts +4 -4
  26. package/src/components/ChatBotMessage/ChatBotMessage.vue +34 -8
  27. package/src/components/ChatBotMessage/__tests__/ChatBotMessage.spec.ts +256 -0
  28. package/src/components/ChatBotMessage/__tests__/ChatBotMessageButtons.spec.ts +4 -4
  29. package/src/components/ChatBotMessage/__tests__/__snapshots__/ChatBotMessage.spec.ts.snap +35 -0
  30. package/src/components/ChatBotMessage/types.ts +4 -3
  31. package/src/components/ChatToolBar/ChatToolBar.vue +1 -2
  32. package/src/components/ChatToolBar/__tests__/ChatToolBar.spec.ts +18 -38
  33. package/src/components/FieldPreview/FieldPreview.vue +9 -31
  34. package/src/components/FieldPreview/__tests__/__snapshots__/FieldPreview.spec.ts.snap +11 -5
  35. package/src/components/FieldPreview/field-preview.scss +0 -4
  36. package/src/components/MarkdownRender/MarkdownRender.vue +0 -1
  37. package/src/composables/__tests__/useChatMessages.spec.ts +1 -14
  38. package/src/composables/useChatApi.ts +53 -57
  39. package/src/composables/useChatMessages.ts +4 -8
  40. package/src/composables/useTexts.ts +2 -5
  41. package/src/test/setup.ts +0 -5
@@ -0,0 +1,256 @@
1
+ // Components
2
+ import { ChatBotMessage, ChatBotMessageButtons } from '..'
3
+ import PulseDots from '@/components/PulseDots/PulseDots.vue'
4
+ import { FieldPreview } from '@/components/FieldPreview/'
5
+ import { MarkdownRender } from '@/components/MarkdownRender/'
6
+
7
+ // Utils
8
+ import { mount } from '@vue/test-utils'
9
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
10
+ import { parseFieldValue } from '@/utils/parseFieldValue'
11
+
12
+ // Types
13
+ import type { ChatBotMessageProps } from '..'
14
+
15
+ // Composable
16
+ import { useChatMessages } from '@/composables/useChatMessages'
17
+ import { ChatBotFile } from '@/components/ChatBotInput'
18
+
19
+ describe('ChatBotMessage', () => {
20
+ const fixedDate = new Date('2025-01-01T11:47:00')
21
+ const { clearMessages, addChatMessage } = useChatMessages()
22
+
23
+ beforeEach(() => {
24
+ vi.useFakeTimers()
25
+ vi.setSystemTime(fixedDate)
26
+
27
+ navigator.clipboard.writeText('')
28
+
29
+ clearMessages()
30
+ })
31
+
32
+ afterEach(() => {
33
+ vi.useRealTimers()
34
+ })
35
+
36
+ const props: ChatBotMessageProps = {
37
+ sender: 'bot',
38
+ message: 'Hello, this is a test message.',
39
+ date: fixedDate,
40
+ loading: false,
41
+ dateFormat: 'HH:mm',
42
+ apiEndpoint: 'https://api.example.com/chat',
43
+ fields: [],
44
+ userImage: '',
45
+ chatbotImage: '',
46
+ file: undefined
47
+ }
48
+
49
+ it('renders the component with default props', () => {
50
+ const wrapper = mount(ChatBotMessage, { props })
51
+ expect(wrapper.html()).toMatchSnapshot()
52
+ })
53
+
54
+ it('renders the image preview when imagePreviewUrl is provided', () => {
55
+ const file: ChatBotFile = {
56
+ fileData: new File(['dummy content'], 'example.png', { type: 'image/png' }),
57
+ previewUrl: 'tottaly-legit-image.png'
58
+ }
59
+ const wrapper = mount(ChatBotMessage, {
60
+ props: { ...props, file }
61
+ })
62
+
63
+ const img = wrapper.find('.q-chatbot__image-preview img')
64
+ expect(img.exists()).toBe(true)
65
+ expect(img.attributes('src')).toBe('tottaly-legit-image.png')
66
+ })
67
+
68
+ it('shows loading state when loading is true', () => {
69
+ const wrapper = mount(ChatBotMessage, {
70
+ props: { ...props, loading: true }
71
+ })
72
+
73
+ const pulseDots = wrapper.findComponent(PulseDots)
74
+ expect(pulseDots.exists()).toBe(true)
75
+ })
76
+
77
+ it('renders the field preview component when fields are provided and the sender is bot', () => {
78
+ const wrapper = mount(ChatBotMessage, {
79
+ props: {
80
+ ...props,
81
+ sender: 'bot',
82
+ fields: [
83
+ {
84
+ type: 'text',
85
+ text: 'Sample Field',
86
+ name: 'This is a sample field value'
87
+ }
88
+ ]
89
+ }
90
+ })
91
+
92
+ const fieldPreview = wrapper.findComponent(FieldPreview)
93
+ expect(fieldPreview.exists()).toBe(true)
94
+ })
95
+
96
+ it('renders a normal when no fields are provided and the sender is user', () => {
97
+ const wrapper = mount(ChatBotMessage, {
98
+ props: { ...props, sender: 'user' }
99
+ })
100
+
101
+ const fieldPreview = wrapper.findComponent(FieldPreview)
102
+ expect(fieldPreview.exists()).toBe(false)
103
+
104
+ const markdownRender = wrapper.findComponent(MarkdownRender)
105
+ expect(markdownRender.exists()).toBe(false)
106
+
107
+ const messageDiv = wrapper.find('.q-chatbot__user-text')
108
+ expect(messageDiv.exists()).toBe(true)
109
+ expect(messageDiv.text()).toBe(props.message)
110
+ })
111
+
112
+ it('renders markdown-render when no fields are provided', () => {
113
+ const wrapper = mount(ChatBotMessage, { props })
114
+
115
+ const markdownRender = wrapper.findComponent(MarkdownRender)
116
+ expect(markdownRender.exists()).toBe(true)
117
+ })
118
+
119
+ it('adds the text to the clipboard when copy event is emmited', async () => {
120
+ const wrapper = mount(ChatBotMessage, { props })
121
+
122
+ const messageButtons = wrapper.findComponent(ChatBotMessageButtons)
123
+ const copyButton = messageButtons.find('.q-chatbot__copy-button')
124
+
125
+ await copyButton.trigger('click')
126
+ const clipboardText = await navigator.clipboard.readText()
127
+
128
+ expect(navigator.clipboard).toBeDefined()
129
+ expect(clipboardText).toBe(props.message)
130
+ })
131
+
132
+ it('does not add the text to the clipboard if message is empty', async () => {
133
+ const wrapper = mount(ChatBotMessage, { props: { ...props, message: '' } })
134
+ const messageButtons = wrapper.findComponent(ChatBotMessageButtons)
135
+ const copyButton = messageButtons.find('.q-chatbot__copy-button')
136
+
137
+ await copyButton.trigger('click')
138
+ const clipboardText = await navigator.clipboard.readText()
139
+
140
+ expect(navigator.clipboard).toBeDefined()
141
+ expect(clipboardText).toBe('')
142
+ })
143
+
144
+ it('catchs errors when trying to copy to clipboard', async () => {
145
+ const wrapper = mount(ChatBotMessage, { props })
146
+ const messageButtons = wrapper.findComponent(ChatBotMessageButtons)
147
+ const copyButton = messageButtons.find('.q-chatbot__copy-button')
148
+
149
+ vi.spyOn(navigator.clipboard, 'writeText').mockRejectedValueOnce(
150
+ new Error('Clipboard error')
151
+ )
152
+ // Suppress console.error for this test
153
+ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
154
+
155
+ await copyButton.trigger('click')
156
+ const clipboardText = await navigator.clipboard.readText()
157
+
158
+ expect(navigator.clipboard).toBeDefined()
159
+ expect(clipboardText).toBe('')
160
+ consoleErrorSpy.mockRestore()
161
+ })
162
+
163
+ it('emits apply-fields event with fields when apply all button is clicked', async () => {
164
+ const testFields = [
165
+ {
166
+ type: 'text',
167
+ text: 'Sample Field',
168
+ name: 'This is a sample field value'
169
+ },
170
+ {
171
+ type: 'number',
172
+ text: 'Number Field',
173
+ name: '42'
174
+ }
175
+ ]
176
+ addChatMessage('Test message 1', 'bot').fields = testFields
177
+
178
+ const wrapper = mount(ChatBotMessage, {
179
+ props: { ...props, sender: 'bot', fields: testFields }
180
+ })
181
+
182
+ const messageButtons = wrapper.findComponent(ChatBotMessageButtons)
183
+ const applyAllButton = messageButtons.find('.q-chatbot__apply-all-button')
184
+
185
+ expect(applyAllButton.exists()).toBe(true)
186
+ await applyAllButton.trigger('click')
187
+
188
+ const fieldsToApply = testFields.map((field) => {
189
+ return {
190
+ name: field.name,
191
+ text: parseFieldValue(field.type, field.text)
192
+ }
193
+ })
194
+
195
+ expect(wrapper.emitted('apply-fields')).toBeTruthy()
196
+ expect(wrapper.emitted('apply-fields')?.[0]).toEqual([fieldsToApply])
197
+ })
198
+
199
+ it('emits apply-fieldd when a single field is applied', async () => {
200
+ const testFields = [
201
+ {
202
+ type: 'text',
203
+ text: 'Sample Field',
204
+ name: 'This is a sample field value'
205
+ }
206
+ ]
207
+
208
+ addChatMessage('Test message 1', 'bot').fields = testFields
209
+
210
+ const wrapper = mount(ChatBotMessage, {
211
+ props: { ...props, sender: 'bot', fields: testFields }
212
+ })
213
+ const fieldPreview = wrapper.findComponent(FieldPreview)
214
+ expect(fieldPreview.exists()).toBe(true)
215
+
216
+ const applyButton = fieldPreview.find("[data-testid='apply-button']")
217
+ expect(applyButton.exists()).toBe(true)
218
+
219
+ await applyButton.trigger('click')
220
+
221
+ const fieldToApply = [
222
+ {
223
+ name: testFields[0].name,
224
+ text: parseFieldValue(testFields[0].type, testFields[0].text)
225
+ }
226
+ ]
227
+
228
+ expect(wrapper.emitted('apply-fields')).toBeTruthy()
229
+ expect(wrapper.emitted('apply-fields')?.[0]).toEqual([fieldToApply])
230
+ })
231
+
232
+ it('renders a different preview when the file is not an image', async () => {
233
+ const file: ChatBotFile = {
234
+ fileData: new File(['dummy content'], 'example.pdf', { type: 'application/pdf' }),
235
+ previewUrl: ''
236
+ }
237
+
238
+ const wrapper = mount(ChatBotMessage, {
239
+ props: { ...props, file }
240
+ })
241
+
242
+ const img = wrapper.find('.q-chatbot__image-preview img')
243
+ expect(img.exists()).toBe(false)
244
+
245
+ const filePreview = wrapper.find('.q-chatbot__file-preview-container')
246
+ expect(filePreview.exists()).toBe(true)
247
+
248
+ const fileName = wrapper.find('.q-chatbot__file-name')
249
+ expect(fileName.exists()).toBe(true)
250
+ expect(fileName.text()).toBe(file.fileData.name)
251
+
252
+ const fileExtension = wrapper.find('.q-chatbot__file-extension')
253
+ expect(fileExtension.exists()).toBe(true)
254
+ expect(fileExtension.text()).toBe('PDF')
255
+ })
256
+ })
@@ -85,8 +85,8 @@ describe('ChatBotMessageButtons', () => {
85
85
  const message = addChatMessage('Test message 1', 'bot')
86
86
 
87
87
  message.fields = [
88
- { name: 'field1', text: 'value1', type: 'text', id: '1' },
89
- { name: 'field2', text: 'value2', type: 'text', id: '2' }
88
+ { name: 'field1', text: 'value1', type: 'text' },
89
+ { name: 'field2', text: 'value2', type: 'text' }
90
90
  ]
91
91
 
92
92
  const wrapper = mount(ChatBotMessageButtons, {
@@ -104,8 +104,8 @@ describe('ChatBotMessageButtons', () => {
104
104
  const message = addChatMessage('Test message 1', 'bot')
105
105
 
106
106
  message.fields = [
107
- { name: 'field1', text: 'value1', type: 'text', id: '1' },
108
- { name: 'field2', text: 'value2', type: 'text', id: '2' }
107
+ { name: 'field1', text: 'value1', type: 'text' },
108
+ { name: 'field2', text: 'value2', type: 'text' }
109
109
  ]
110
110
 
111
111
  const wrapper = mount(ChatBotMessageButtons, {
@@ -0,0 +1,35 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`ChatBotMessage > renders the component with default props 1`] = `
4
+ "<div class="q-chatbot__message-container"><span data-test="" type="img" alt="Sender Image" class="q-chatbot__profile"></span>
5
+ <div class="q-chatbot__message-wrapper">
6
+ <!--v-if-->
7
+ <div class="q-chatbot__message">
8
+ <div class="markdown-renderer q-chatbot__text">
9
+ <p>Hello, this is a test message.</p>
10
+ </div>
11
+ </div>
12
+ </div>
13
+ <!--teleport start-->
14
+ <transition-stub name="fade" appear="true" persisted="false" css="true">
15
+ <!--v-if-->
16
+ </transition-stub>
17
+ <transition-stub name="fade" appear="true" persisted="false" css="true">
18
+ <!--v-if-->
19
+ </transition-stub>
20
+ <!--teleport end-->
21
+ <!--v-if-->
22
+ <div class="q-chatbot__feedback-buttons">
23
+ <div class="q-button-group" role="group"><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless q-chatbot__good-response-button" title="Good response">
24
+ <!--v-if--><span class="q-button__content"><span data-test="thumb-up"></span> </span>
25
+ </button><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless q-chatbot__bad-response-button" title="Bad response">
26
+ <!--v-if--><span class="q-button__content"><span data-test="thumb-down"></span> </span>
27
+ </button><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless q-chatbot__copy-button" title="Copy response">
28
+ <!--v-if--><span class="q-button__content"><span data-test="copy-content"></span> </span>
29
+ </button>
30
+ <!--v-if-->
31
+ </div>
32
+ </div>
33
+ <div class="q-chatbot__sender">11:47</div>
34
+ </div>"
35
+ `;
@@ -1,4 +1,5 @@
1
- import { ChatBotMessageSender, FieldData } from '@/components/ChatBot/types'
1
+ import type { ChatBotMessageSender, FieldData } from '@/components/ChatBot/types'
2
+ import type { ChatBotFile } from '../ChatBotInput'
2
3
 
3
4
  export type ChatBotMessageProps = {
4
5
  /*
@@ -27,9 +28,9 @@ export type ChatBotMessageProps = {
27
28
  dateFormat: string
28
29
 
29
30
  /**
30
- * Image preview URL
31
+ * File Preview
31
32
  */
32
- imagePreviewUrl?: string
33
+ file?: ChatBotFile
33
34
 
34
35
  /**
35
36
  * Default api endpoint
@@ -4,7 +4,6 @@
4
4
  <q-select
5
5
  v-if="hasAgents"
6
6
  v-model="selectedChat"
7
- inline
8
7
  class="q-chatbot__tools-select-input"
9
8
  size="medium"
10
9
  :items="availableChats"
@@ -23,7 +22,7 @@
23
22
  </template>
24
23
 
25
24
  <script setup lang="ts">
26
- import { QButton, QIcon } from '@quidgest/ui/components'
25
+ import { QButton, QSelect, QIcon } from '@quidgest/ui/components'
27
26
 
28
27
  import { useTexts } from '@/composables/useTexts'
29
28
  import { ChatToolBarProps } from './types'
@@ -7,7 +7,6 @@ import { mount } from '@vue/test-utils'
7
7
 
8
8
  // Types
9
9
  import type { ChatToolBarProps } from '../'
10
- import { nextTick } from 'vue'
11
10
 
12
11
  describe('ChatToolBar', () => {
13
12
  const props: ChatToolBarProps = {
@@ -54,25 +53,24 @@ describe('ChatToolBar', () => {
54
53
  const wrapper = mount(ChatToolBar, {
55
54
  props: {
56
55
  ...props,
57
- availableAgents: [{ key: 'agent1', value: 'Agent 1', formId: 'key' }],
58
- selectedAgentKey: ''
56
+ availableAgents: [
57
+ { key: 'agent1', value: 'Agent 1', formId: 'key' },
58
+ { key: 'agent2', value: 'Agent 2', formId: 'key' }
59
+ ],
60
+ selectedAgentKey: 'agent1'
59
61
  }
60
62
  })
61
63
 
62
- const select = wrapper.find('.q-field__control')
63
- await select.trigger('click')
64
-
65
- const overlay = wrapper.find('.q-overlay__content')
66
-
67
- const item = overlay.find('.q-list-item')
68
- await item.trigger('click')
64
+ const select = wrapper.findComponent({ name: 'QSelect' })
65
+ // Simulate selecting a new agent
66
+ await select.vm.$emit('update:modelValue', 'agent2')
69
67
 
70
68
  expect(wrapper.emitted()['change-chat']).toBeTruthy()
71
- expect(wrapper.emitted()['change-chat'][0]).toEqual([
69
+ expect(wrapper.emitted()['change-chat']?.[0]).toEqual([
72
70
  {
73
- key: 'agent1',
71
+ key: 'agent2',
74
72
  formId: 'key',
75
- value: 'Agent 1'
73
+ value: 'Agent 2'
76
74
  }
77
75
  ])
78
76
  })
@@ -88,21 +86,9 @@ describe('ChatToolBar', () => {
88
86
  selectedAgentKey: 'agent1'
89
87
  }
90
88
  })
91
-
92
- const select = wrapper.find('.q-field__control')
93
- await select.trigger('click')
94
-
95
- const overlay = wrapper.find('.q-overlay__content')
96
-
97
- // Manually add a fake item that does not exist in the options
98
- const fakeItem = document.createElement('div')
99
- fakeItem.setAttribute('data-key', 'agent3')
100
- overlay.element.appendChild(fakeItem)
101
-
102
- await nextTick()
103
- const item = overlay.find('[data-key="agent3"]')
104
- await item.trigger('click')
105
-
89
+ const select = wrapper.findComponent({ name: 'QSelect' })
90
+ // Simulate selecting a new agent
91
+ await select.vm.$emit('update:modelValue', 'agent3')
106
92
  expect(wrapper.emitted()['change-chat']).toBeFalsy()
107
93
  })
108
94
 
@@ -117,18 +103,12 @@ describe('ChatToolBar', () => {
117
103
  selectedAgentKey: 'agent1'
118
104
  }
119
105
  })
120
- const select = wrapper.find('.q-field__control')
121
- await select.trigger('click')
122
-
123
- const overlay = wrapper.find('.q-overlay__content')
124
- const items = overlay.findAll('.q-list-item')
125
-
126
- // Default options is always the last one
127
- const defaultOption = items[items.length - 1]
128
- await defaultOption.trigger('click')
106
+ const select = wrapper.findComponent({ name: 'QSelect' })
107
+ // Simulate selecting a new agent
108
+ await select.vm.$emit('update:modelValue', '')
129
109
 
130
110
  expect(wrapper.emitted()['change-chat']).toBeTruthy()
131
- expect(wrapper.emitted()['change-chat'][0]).toEqual([
111
+ expect(wrapper.emitted()['change-chat']?.[0]).toEqual([
132
112
  {
133
113
  key: '',
134
114
  formId: ''
@@ -5,24 +5,23 @@
5
5
  {{ texts.suggestionsForField }} <b>{{ props.name }}</b>
6
6
  </span>
7
7
  </div>
8
- <div :class="classes">
8
+ <div class="q-field-preview__content">
9
9
  <component
10
10
  :is="previewComponent"
11
11
  v-bind="previewComponentProps" />
12
12
  </div>
13
13
  <div class="q-field-preview__footer">
14
14
  <q-button-group borderless>
15
+ <!-- <q-button
16
+ :title="texts.regenerateResponse"
17
+ :disabled="props.disabled"
18
+ borderless
19
+ @click="console.log('Regenerate response')">
20
+ <q-icon icon="reset" />
21
+ </q-button> -->
15
22
  <q-button
16
- :title="texts.regenerateResponse"
17
- :disabled="blockRegenerateButton"
18
- :readonly="blockRegenerateButton"
19
- borderless
20
- @click="regenerate">
21
- <q-icon icon="reset" />
22
- </q-button>
23
- <q-button
24
- :label="texts.apply"
25
23
  data-testid="apply-button"
24
+ :label="texts.apply"
26
25
  :disabled="blockApplyButton"
27
26
  :readonly="blockApplyButton"
28
27
  @click="emitApply">
@@ -44,19 +43,13 @@
44
43
  const props = defineProps<FieldPreviewProps>()
45
44
  const emit = defineEmits<{
46
45
  (e: 'apply', text: unknown): void
47
- (e: 'regenerate', name: string): void
48
46
  }>()
49
47
  const texts = useTexts()
50
48
  const blockApply = ref(props.applied)
51
- const blockRegenerate = ref(false)
52
49
  const blockApplyButton = computed(() => {
53
50
  return props.disabled || blockApply.value
54
51
  })
55
52
 
56
- const blockRegenerateButton = computed(() => {
57
- return props.disabled || blockRegenerate.value
58
- })
59
-
60
53
  const previewComponent = computed(() => {
61
54
  if (props.type === 'text' || props.type === 'multiline_text') return MarkdownRender
62
55
 
@@ -72,14 +65,6 @@
72
65
  return componentProps
73
66
  })
74
67
 
75
- const classes = computed(() => {
76
- const classes = ['q-field-preview__content']
77
-
78
- if (previewComponent.value !== MarkdownRender) classes.push('preserve-whitespace')
79
-
80
- return classes
81
- })
82
-
83
68
  function emitApply() {
84
69
  if (blockApply.value) return
85
70
  blockApply.value = true
@@ -88,11 +73,4 @@
88
73
 
89
74
  emit('apply', text)
90
75
  }
91
-
92
- function regenerate() {
93
- if (blockRegenerate.value) return
94
- blockRegenerate.value = true
95
-
96
- emit('regenerate', props.name)
97
- }
98
76
  </script>
@@ -2,18 +2,24 @@
2
2
 
3
3
  exports[`FieldPreview > renders correctly with default props 1`] = `
4
4
  "<div class="q-field-preview">
5
- <div class="q-field-preview__toolbar"><span>Suggestions for field <b>Test Field</b></span></div>
5
+ <div class="q-field-preview__toolbar"><span>Suggestions for field: <b>Test Field</b></span></div>
6
6
  <div class="q-field-preview__content">
7
7
  <div class="markdown-renderer">
8
8
  <p>Hello, World!</p>
9
9
  </div>
10
10
  </div>
11
11
  <div class="q-field-preview__footer">
12
- <div class="q-button-group" role="group"><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless" title="Regenerate response">
13
- <!--v-if--><span class="q-button__content"><span data-test="reset"></span> </span>
14
- </button><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless" data-testid="apply-button">
12
+ <div class="q-button-group" role="group">
13
+ <!-- <q-button
14
+ :title="texts.regenerateResponse"
15
+ :disabled="props.disabled"
16
+ borderless
17
+ @click="console.log('Regenerate response')">
18
+ <q-icon icon="reset" />
19
+ </q-button> --><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless" data-testid="apply-button">
15
20
  <!--v-if--><span class="q-button__content"><span data-test="apply"></span> Apply</span>
16
- </button></div>
21
+ </button>
22
+ </div>
17
23
  </div>
18
24
  </div>"
19
25
  `;
@@ -20,10 +20,6 @@
20
20
  border-radius: 6px;
21
21
  padding: 0.75rem 1rem;
22
22
  font-size: 0.875rem;
23
-
24
- &.preserve-whitespace {
25
- white-space: pre-wrap;
26
- }
27
23
  }
28
24
 
29
25
  &__footer {
@@ -15,7 +15,6 @@
15
15
  const md = ref(
16
16
  new MarkdownIt({
17
17
  html: true,
18
- breaks: true,
19
18
  ...(props.options ?? {})
20
19
  })
21
20
  )
@@ -4,8 +4,7 @@ import { useChatMessages } from '../useChatMessages'
4
4
  // Utils
5
5
  import { describe, it, expect, beforeEach } from 'vitest'
6
6
 
7
- const { addChatMessage, clearMessages, getMessages, getLastMessage, deleteMessageById } =
8
- useChatMessages()
7
+ const { addChatMessage, clearMessages, getMessages, getLastMessage } = useChatMessages()
9
8
 
10
9
  beforeEach(() => {
11
10
  // Reset chat messages before each test
@@ -49,16 +48,4 @@ describe('useChatMessages', () => {
49
48
  expect(messages).toEqual([])
50
49
  expect(messages.length).toBe(0)
51
50
  })
52
-
53
- it('should delete a message by ID', () => {
54
- const msg1 = addChatMessage('First message', 'bot')
55
- const msg2 = addChatMessage('Second message', 'user')
56
-
57
- expect(getMessages().length).toBe(2)
58
- deleteMessageById(msg1.id)
59
-
60
- const messages = getMessages()
61
- expect(messages.length).toBe(1)
62
- expect(messages[0].id).toBe(msg2.id)
63
- })
64
51
  })