@quidgest/chatbot 0.5.1 → 0.5.3-dev.0
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.
- package/README.md +1 -2
- package/dist/components/ChatBot/ChatBot.vue.d.ts +2 -0
- package/dist/components/ChatBot/types.d.ts +2 -1
- package/dist/components/ChatBotInput/ChatBotInput.vue.d.ts +2 -2
- package/dist/components/ChatBotInput/__tests__/ChatBotInput.spec.d.ts +1 -0
- package/dist/components/ChatBotMessage/ChatBotMessage.vue.d.ts +3 -1
- package/dist/components/ChatBotMessage/__tests__/ChatBotMessageButtons.spec.d.ts +1 -0
- package/dist/components/ChatToolBar/__tests__/ChatToolBar.spec.d.ts +1 -0
- package/dist/components/FieldPreview/FieldPreview.vue.d.ts +2 -0
- package/dist/components/FieldPreview/__tests__/FieldPreview.spec.d.ts +1 -0
- package/dist/components/MarkdownRender/__tests__/MarkdownRender.spec.d.ts +1 -0
- package/dist/components/PulseDots/__tests__/PulseDots.spec.d.ts +1 -0
- package/dist/composables/__tests__/useChatMessages.spec.d.ts +1 -0
- package/dist/composables/__tests__/useSSE.spec.d.ts +1 -0
- package/dist/composables/useChatApi.d.ts +1 -1
- package/dist/composables/useChatMessages.d.ts +2 -1
- package/dist/composables/useSSE.d.ts +1 -2
- package/dist/composables/useTexts.d.ts +5 -0
- package/dist/index.js +25 -25
- package/dist/index.mjs +2319 -1812
- package/dist/style.css +1 -1
- package/dist/test/setup.d.ts +1 -0
- package/dist/utils/__tests__/parseFieldValue.spec.d.ts +1 -0
- package/package.json +27 -6
- package/src/assets/styles/styles.scss +212 -220
- package/src/components/ChatBot/ChatBot.vue +346 -368
- package/src/components/ChatBot/types.ts +34 -33
- package/src/components/ChatBotInput/ChatBotInput.vue +181 -190
- package/src/components/ChatBotInput/__tests__/ChatBotInput.spec.ts +292 -0
- package/src/components/ChatBotInput/__tests__/__snapshots__/ChatBotInput.spec.ts.snap +25 -0
- package/src/components/ChatBotInput/types.ts +24 -24
- package/src/components/ChatBotMessage/ChatBotMessage.vue +133 -134
- package/src/components/ChatBotMessage/ChatBotMessageButtons.vue +179 -164
- package/src/components/ChatBotMessage/__tests__/ChatBotMessageButtons.spec.ts +199 -0
- package/src/components/ChatBotMessage/__tests__/__snapshots__/ChatBotMessageButtons.spec.ts.snap +25 -0
- package/src/components/ChatBotMessage/types.ts +52 -52
- package/src/components/ChatToolBar/ChatToolBar.vue +69 -64
- package/src/components/ChatToolBar/__tests__/ChatToolBar.spec.ts +138 -0
- package/src/components/ChatToolBar/__tests__/__snapshots__/ChatToolBar.spec.ts.snap +11 -0
- package/src/components/ChatToolBar/types.ts +12 -12
- package/src/components/FieldPreview/FieldPreview.vue +83 -63
- package/src/components/FieldPreview/__tests__/FieldPreview.spec.ts +72 -0
- package/src/components/FieldPreview/__tests__/__snapshots__/FieldPreview.spec.ts.snap +19 -0
- package/src/components/FieldPreview/field-preview.scss +28 -24
- package/src/components/FieldPreview/types.ts +5 -5
- package/src/components/MarkdownRender/MarkdownRender.vue +16 -15
- package/src/components/MarkdownRender/__tests__/MarkdownRender.spec.ts +68 -0
- package/src/components/MarkdownRender/__tests__/__snapshots__/MarkdownRender.spec.ts.snap +8 -0
- package/src/components/MarkdownRender/markdown-render.scss +19 -20
- package/src/components/MarkdownRender/types.ts +3 -3
- package/src/components/PulseDots/PulseDots.vue +17 -17
- package/src/components/PulseDots/__tests__/PulseDots.spec.ts +35 -0
- package/src/components/PulseDots/__tests__/__snapshots__/PulseDots.spec.ts.snap +7 -0
- package/src/components/PulseDots/__tests__/__snapshots__/pulse-dots.spec.ts.snap +7 -0
- package/src/components/PulseDots/pulse-dots.scss +24 -23
- package/src/composables/__tests__/useChatMessages.spec.ts +64 -0
- package/src/composables/__tests__/useSSE.spec.ts +132 -0
- package/src/composables/useChatApi.ts +132 -134
- package/src/composables/useChatMessages.ts +50 -48
- package/src/composables/useSSE.ts +75 -76
- package/src/composables/useTexts.ts +33 -30
- package/src/test/setup.ts +41 -0
- package/src/utils/__tests__/parseFieldValue.spec.ts +27 -0
- package/src/utils/parseFieldValue.ts +12 -0
- package/src/utils/helper.ts +0 -12
- /package/dist/utils/{helper.d.ts → parseFieldValue.d.ts} +0 -0
|
@@ -1,70 +1,70 @@
|
|
|
1
1
|
import { ChatBotMessageSender, FieldData } from '@/components/ChatBot/types'
|
|
2
2
|
|
|
3
3
|
export type ChatBotMessageProps = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
/*
|
|
5
|
+
* Sender of the message
|
|
6
|
+
*/
|
|
7
|
+
sender?: ChatBotMessageSender
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
/*
|
|
10
|
+
* Message to be displayed
|
|
11
|
+
*/
|
|
12
|
+
message?: string
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
/*
|
|
15
|
+
* Date of when the message was sent
|
|
16
|
+
*/
|
|
17
|
+
date?: Date
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
/*
|
|
20
|
+
* If the message is loading
|
|
21
|
+
*/
|
|
22
|
+
loading?: boolean
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Project locale
|
|
26
|
+
*/
|
|
27
|
+
dateFormat: string
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Image preview URL
|
|
31
|
+
*/
|
|
32
|
+
imagePreviewUrl?: string
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Default api endpoint
|
|
36
|
+
*/
|
|
37
|
+
apiEndpoint: string
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Session ID
|
|
41
|
+
*/
|
|
42
|
+
sessionID?: string
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
/**
|
|
45
|
+
* User image
|
|
46
|
+
*/
|
|
47
|
+
userImage: string
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Chatbot image
|
|
51
|
+
*/
|
|
52
|
+
chatbotImage: string
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Flag to mark welcome messages
|
|
56
|
+
*/
|
|
57
|
+
isWelcomeMessage?: boolean
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Additional fields for the message
|
|
61
|
+
*/
|
|
62
|
+
fields?: FieldData[]
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
export type ChatBotMessageButtonsProps = {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
loading: boolean
|
|
67
|
+
showButtons: boolean
|
|
68
|
+
dateFormat: string
|
|
69
|
+
date?: Date
|
|
70
70
|
}
|
|
@@ -1,82 +1,87 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
<div class="q-chatbot__tools">
|
|
3
|
+
<div class="q-chatbot__tools__select">
|
|
4
|
+
<q-select
|
|
5
|
+
v-if="hasAgents"
|
|
6
|
+
v-model="selectedChat"
|
|
7
|
+
inline
|
|
8
|
+
class="q-chatbot__tools-select-input"
|
|
9
|
+
size="medium"
|
|
10
|
+
:items="availableChats"
|
|
11
|
+
@update:model-value="changeChat" />
|
|
12
|
+
</div>
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
<q-button
|
|
15
|
+
:title="clearChat"
|
|
16
|
+
:disabled="props.disabled"
|
|
17
|
+
class="q-chatbot__tools-clear"
|
|
18
|
+
borderless
|
|
19
|
+
@click="clear">
|
|
20
|
+
<q-icon icon="bin" />
|
|
21
|
+
</q-button>
|
|
22
|
+
</div>
|
|
20
23
|
</template>
|
|
21
24
|
|
|
22
25
|
<script setup lang="ts">
|
|
23
|
-
|
|
24
|
-
import { ChatToolBarProps } from './types'
|
|
25
|
-
import { computed, ref, watch } from 'vue'
|
|
26
|
+
import { QButton, QIcon } from '@quidgest/ui/components'
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
import { useTexts } from '@/composables/useTexts'
|
|
29
|
+
import { ChatToolBarProps } from './types'
|
|
30
|
+
import { computed, ref, watch } from 'vue'
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
formId: ''
|
|
33
|
-
}
|
|
32
|
+
const props = withDefaults(defineProps<ChatToolBarProps>(), {
|
|
33
|
+
availableAgents: () => []
|
|
34
|
+
})
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const emit = defineEmits<{
|
|
37
|
+
(e: 'clear'): void
|
|
38
|
+
(e: 'change-chat', value: { key: string; formId: string }): void
|
|
39
|
+
}>()
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
(e: 'clear'): void
|
|
41
|
-
(e: 'change-chat', value: { key: string; formId: string }): void
|
|
42
|
-
}>()
|
|
41
|
+
const { clearChat } = useTexts()
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const defaultChat = {
|
|
44
|
+
key: '',
|
|
45
|
+
value: 'Default Chat',
|
|
46
|
+
formId: ''
|
|
47
|
+
}
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
(newValue) => {
|
|
52
|
-
selectedChat.value = newValue || defaultChat.key
|
|
53
|
-
}
|
|
54
|
-
)
|
|
49
|
+
const hasAgents = computed(() => {
|
|
50
|
+
return props.availableAgents && props.availableAgents.length > 0
|
|
51
|
+
})
|
|
55
52
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
const selectedChat = ref(props.selectedAgentKey || defaultChat.key)
|
|
54
|
+
watch(
|
|
55
|
+
() => props.selectedAgentKey,
|
|
56
|
+
(newValue) => {
|
|
57
|
+
selectedChat.value = newValue || defaultChat.key
|
|
58
|
+
}
|
|
59
|
+
)
|
|
62
60
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
const availableChats = computed(() => {
|
|
62
|
+
const chats = props.availableAgents?.map((agent) => ({
|
|
63
|
+
key: agent.key,
|
|
64
|
+
value: agent.value,
|
|
65
|
+
formId: agent.formId
|
|
66
|
+
}))
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
chats?.push(defaultChat)
|
|
69
|
+
return chats || [defaultChat]
|
|
70
|
+
})
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
function clear() {
|
|
73
|
+
emit('clear')
|
|
74
|
+
}
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
76
|
+
function changeChat(value: string) {
|
|
77
|
+
const item = availableChats.value.find((chat) => chat.key === value)
|
|
78
|
+
if (!item) return
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
if (item.key === defaultChat.key) {
|
|
81
|
+
emit('change-chat', { key: '', formId: '' })
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
emit('change-chat', item)
|
|
86
|
+
}
|
|
82
87
|
</script>
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// Components
|
|
2
|
+
import { ChatToolBar } from '..'
|
|
3
|
+
|
|
4
|
+
// Utils
|
|
5
|
+
import { describe, it, expect } from 'vitest'
|
|
6
|
+
import { mount } from '@vue/test-utils'
|
|
7
|
+
|
|
8
|
+
// Types
|
|
9
|
+
import type { ChatToolBarProps } from '../'
|
|
10
|
+
import { nextTick } from 'vue'
|
|
11
|
+
|
|
12
|
+
describe('ChatToolBar', () => {
|
|
13
|
+
const props: ChatToolBarProps = {
|
|
14
|
+
disabled: false,
|
|
15
|
+
availableAgents: [],
|
|
16
|
+
selectedAgentKey: ''
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
it('should render the component', () => {
|
|
20
|
+
const wrapper = mount(ChatToolBar, { props })
|
|
21
|
+
expect(wrapper.html()).toMatchSnapshot()
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('should emit clear event when clear button is clicked', async () => {
|
|
25
|
+
const wrapper = mount(ChatToolBar, { props })
|
|
26
|
+
const button = wrapper.find('.q-chatbot__tools-clear')
|
|
27
|
+
|
|
28
|
+
await button.trigger('click')
|
|
29
|
+
expect(wrapper.emitted()['clear']).toBeTruthy()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should disable the clear button when disabled prop is true', () => {
|
|
33
|
+
const wrapper = mount(ChatToolBar, { props: { ...props, disabled: true } })
|
|
34
|
+
const button = wrapper.find<HTMLButtonElement>('.q-chatbot__tools-clear')
|
|
35
|
+
expect(button.element.disabled).toBe(true)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should not render the select when no agents are provided', () => {
|
|
39
|
+
const wrapper = mount(ChatToolBar, { props })
|
|
40
|
+
expect(wrapper.find('.q-chatbot__tools-select-input').exists()).toBe(false)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('should render the select when agents are provided', () => {
|
|
44
|
+
const wrapper = mount(ChatToolBar, {
|
|
45
|
+
props: {
|
|
46
|
+
...props,
|
|
47
|
+
availableAgents: [{ key: 'agent1', value: 'Agent 1', formId: 'key' }]
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
expect(wrapper.find('.q-chatbot__tools-select-input').exists()).toBe(true)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('should emit change-agent event when a new agent is selected', async () => {
|
|
54
|
+
const wrapper = mount(ChatToolBar, {
|
|
55
|
+
props: {
|
|
56
|
+
...props,
|
|
57
|
+
availableAgents: [{ key: 'agent1', value: 'Agent 1', formId: 'key' }],
|
|
58
|
+
selectedAgentKey: ''
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
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')
|
|
69
|
+
|
|
70
|
+
expect(wrapper.emitted()['change-chat']).toBeTruthy()
|
|
71
|
+
expect(wrapper.emitted()['change-chat'][0]).toEqual([
|
|
72
|
+
{
|
|
73
|
+
key: 'agent1',
|
|
74
|
+
formId: 'key',
|
|
75
|
+
value: 'Agent 1'
|
|
76
|
+
}
|
|
77
|
+
])
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('should not emit change-agent if it receive a non-existing agent key', async () => {
|
|
81
|
+
const wrapper = mount(ChatToolBar, {
|
|
82
|
+
props: {
|
|
83
|
+
...props,
|
|
84
|
+
availableAgents: [
|
|
85
|
+
{ key: 'agent1', value: 'Agent 1', formId: 'key' },
|
|
86
|
+
{ key: 'agent2', value: 'Agent 2', formId: 'key' }
|
|
87
|
+
],
|
|
88
|
+
selectedAgentKey: 'agent1'
|
|
89
|
+
}
|
|
90
|
+
})
|
|
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
|
+
|
|
106
|
+
expect(wrapper.emitted()['change-chat']).toBeFalsy()
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('shoudld emit change-agent when selecting the default option', async () => {
|
|
110
|
+
const wrapper = mount(ChatToolBar, {
|
|
111
|
+
props: {
|
|
112
|
+
...props,
|
|
113
|
+
availableAgents: [
|
|
114
|
+
{ key: 'agent1', value: 'Agent 1', formId: 'key' },
|
|
115
|
+
{ key: 'agent2', value: 'Agent 2', formId: 'key' }
|
|
116
|
+
],
|
|
117
|
+
selectedAgentKey: 'agent1'
|
|
118
|
+
}
|
|
119
|
+
})
|
|
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')
|
|
129
|
+
|
|
130
|
+
expect(wrapper.emitted()['change-chat']).toBeTruthy()
|
|
131
|
+
expect(wrapper.emitted()['change-chat'][0]).toEqual([
|
|
132
|
+
{
|
|
133
|
+
key: '',
|
|
134
|
+
formId: ''
|
|
135
|
+
}
|
|
136
|
+
])
|
|
137
|
+
})
|
|
138
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`ChatToolBar > should render the component 1`] = `
|
|
4
|
+
"<div class="q-chatbot__tools">
|
|
5
|
+
<div class="q-chatbot__tools__select">
|
|
6
|
+
<!--v-if-->
|
|
7
|
+
</div><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless q-chatbot__tools-clear" title="Clear chat">
|
|
8
|
+
<!--v-if--><span class="q-button__content"><span data-test="bin"></span> </span>
|
|
9
|
+
</button>
|
|
10
|
+
</div>"
|
|
11
|
+
`;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { AvailableAgents } from '../ChatBot/types'
|
|
2
2
|
|
|
3
3
|
export type ChatToolBarProps = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
/**
|
|
5
|
+
* If true, the toolbar will be disabled and not clickable.
|
|
6
|
+
*/
|
|
7
|
+
disabled?: boolean
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Availabe Agents to select from.
|
|
11
|
+
*/
|
|
12
|
+
availableAgents?: AvailableAgents[]
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The currently selected agent.
|
|
16
|
+
*/
|
|
17
|
+
selectedAgentKey?: string
|
|
18
18
|
}
|
|
@@ -1,78 +1,98 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
2
|
+
<div class="q-field-preview">
|
|
3
|
+
<div class="q-field-preview__toolbar">
|
|
4
|
+
<span>
|
|
5
|
+
{{ texts.suggestionsForField }} <b>{{ props.name }}</b>
|
|
6
|
+
</span>
|
|
7
|
+
</div>
|
|
8
|
+
<div :class="classes">
|
|
9
|
+
<component
|
|
10
|
+
:is="previewComponent"
|
|
11
|
+
v-bind="previewComponentProps" />
|
|
12
|
+
</div>
|
|
13
|
+
<div class="q-field-preview__footer">
|
|
14
|
+
<q-button-group borderless>
|
|
15
|
+
<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
|
+
data-testid="apply-button"
|
|
26
|
+
:disabled="blockApplyButton"
|
|
27
|
+
:readonly="blockApplyButton"
|
|
28
|
+
@click="emitApply">
|
|
29
|
+
<q-icon icon="apply" />
|
|
30
|
+
</q-button>
|
|
31
|
+
</q-button-group>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
32
34
|
</template>
|
|
33
35
|
|
|
34
36
|
<script setup lang="ts">
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
import { QButton, QIcon, QButtonGroup } from '@quidgest/ui/components'
|
|
38
|
+
import { MarkdownRender } from '@/components/MarkdownRender'
|
|
39
|
+
import { FieldPreviewProps } from './types'
|
|
40
|
+
import { useTexts } from '@/composables/useTexts'
|
|
41
|
+
import { computed, ref } from 'vue'
|
|
42
|
+
import { parseFieldValue } from '@/utils/parseFieldValue'
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
const props = defineProps<FieldPreviewProps>()
|
|
45
|
+
const emit = defineEmits<{
|
|
46
|
+
(e: 'apply', text: unknown): void
|
|
47
|
+
(e: 'regenerate', name: string): void
|
|
48
|
+
}>()
|
|
49
|
+
const texts = useTexts()
|
|
50
|
+
const blockApply = ref(props.applied)
|
|
51
|
+
const blockRegenerate = ref(false)
|
|
52
|
+
const blockApplyButton = computed(() => {
|
|
53
|
+
return props.disabled || blockApply.value
|
|
54
|
+
})
|
|
48
55
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
const blockRegenerateButton = computed(() => {
|
|
57
|
+
return props.disabled || blockRegenerate.value
|
|
58
|
+
})
|
|
52
59
|
|
|
53
|
-
|
|
54
|
-
|
|
60
|
+
const previewComponent = computed(() => {
|
|
61
|
+
if (props.type === 'text' || props.type === 'multiline_text') return MarkdownRender
|
|
55
62
|
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
return 'div'
|
|
64
|
+
})
|
|
58
65
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
else componentProps.innerHTML = props.text
|
|
66
|
+
const previewComponentProps = computed(() => {
|
|
67
|
+
const componentProps: Record<string, unknown> = {}
|
|
62
68
|
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
if (previewComponent.value === MarkdownRender) componentProps.source = props.text
|
|
70
|
+
else componentProps.innerHTML = props.text
|
|
65
71
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}>()
|
|
72
|
+
return componentProps
|
|
73
|
+
})
|
|
69
74
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
blockApply.value = true
|
|
75
|
+
const classes = computed(() => {
|
|
76
|
+
const classes = ['q-field-preview__content']
|
|
73
77
|
|
|
74
|
-
|
|
78
|
+
if (previewComponent.value !== MarkdownRender) classes.push('preserve-whitespace')
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
80
|
+
return classes
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
function emitApply() {
|
|
84
|
+
if (blockApply.value) return
|
|
85
|
+
blockApply.value = true
|
|
86
|
+
|
|
87
|
+
const text = parseFieldValue(props.type, props.text)
|
|
88
|
+
|
|
89
|
+
emit('apply', text)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function regenerate() {
|
|
93
|
+
if (blockRegenerate.value) return
|
|
94
|
+
blockRegenerate.value = true
|
|
95
|
+
|
|
96
|
+
emit('regenerate', props.name)
|
|
97
|
+
}
|
|
78
98
|
</script>
|