@gitlab/duo-ui 10.23.0 → 11.0.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/CHANGELOG.md +23 -0
- package/dist/components/agentic_chat/agentic_duo_chat.js +37 -18
- package/dist/components/agentic_chat/web_agentic_duo_chat.js +725 -0
- package/dist/components/chat/components/duo_chat_header/duo_chat_header.js +4 -4
- package/dist/components/chat/components/duo_chat_header/web_duo_chat_header.js +161 -0
- package/dist/components/chat/duo_chat.js +54 -35
- package/dist/components/chat/web_duo_chat.js +658 -0
- package/dist/components/ui/duo_layout/duo_layout.js +1 -1
- package/dist/components.css +1 -1
- package/dist/components.css.map +1 -1
- package/dist/index.js +3 -1
- package/dist/tailwind.css +1 -1
- package/dist/tailwind.css.map +1 -1
- package/package.json +1 -1
- package/src/components/agentic_chat/agentic_duo_chat.vue +244 -210
- package/src/components/agentic_chat/web_agentic_duo_chat.vue +978 -0
- package/src/components/chat/components/duo_chat_header/duo_chat_header.vue +22 -24
- package/src/components/chat/components/duo_chat_header/web_duo_chat_header.vue +274 -0
- package/src/components/chat/duo_chat.scss +2 -1
- package/src/components/chat/duo_chat.vue +238 -214
- package/src/components/chat/web_duo_chat.vue +891 -0
- package/src/components/ui/duo_layout/duo_layout.vue +2 -2
- package/src/index.js +5 -2
- package/translations.js +46 -5
|
@@ -3,10 +3,10 @@ import Vue from 'vue';
|
|
|
3
3
|
import {
|
|
4
4
|
GlAlert,
|
|
5
5
|
GlBadge,
|
|
6
|
-
GlAvatar,
|
|
7
6
|
GlButton,
|
|
8
7
|
GlDropdown,
|
|
9
8
|
GlDropdownItem,
|
|
9
|
+
GlExperimentBadge,
|
|
10
10
|
GlSafeHtmlDirective as SafeHtml,
|
|
11
11
|
GlTooltipDirective,
|
|
12
12
|
GlToast,
|
|
@@ -43,10 +43,10 @@ export default {
|
|
|
43
43
|
components: {
|
|
44
44
|
GlAlert,
|
|
45
45
|
GlBadge,
|
|
46
|
-
GlAvatar,
|
|
47
46
|
GlButton,
|
|
48
47
|
GlDropdown,
|
|
49
48
|
GlDropdownItem,
|
|
49
|
+
GlExperimentBadge,
|
|
50
50
|
GlDisclosureDropdown,
|
|
51
51
|
},
|
|
52
52
|
directives: {
|
|
@@ -140,31 +140,19 @@ export default {
|
|
|
140
140
|
|
|
141
141
|
<template>
|
|
142
142
|
<header data-testid="chat-header" class="gl-border-b gl-shrink-0 gl-bg-default gl-p-0">
|
|
143
|
-
<div class="gl-border-b gl-flex gl-w-full gl-items-center gl-px-5 gl-py-3">
|
|
144
|
-
<h4
|
|
145
|
-
v-if="subtitle"
|
|
146
|
-
class="gl-mb-0 gl-shrink-0 gl-overflow-hidden gl-text-ellipsis gl-whitespace-nowrap gl-pr-3 gl-text-sm gl-font-normal gl-text-subtle"
|
|
147
|
-
data-testid="chat-subtitle"
|
|
148
|
-
>
|
|
149
|
-
{{ subtitle }}
|
|
150
|
-
</h4>
|
|
151
|
-
<gl-button
|
|
152
|
-
category="tertiary"
|
|
153
|
-
variant="default"
|
|
154
|
-
icon="close"
|
|
155
|
-
size="small"
|
|
156
|
-
class="gl-ml-auto"
|
|
157
|
-
data-testid="chat-close-button"
|
|
158
|
-
:aria-label="$options.i18n.CHAT_CLOSE_LABEL"
|
|
159
|
-
@click="$emit('close')"
|
|
160
|
-
/>
|
|
161
|
-
</div>
|
|
162
143
|
<div class="drawer-title gl-flex gl-items-center gl-justify-start gl-p-5">
|
|
163
|
-
<div class="gl-flex
|
|
164
|
-
<gl-avatar :size="32" :entity-name="title" shape="circle" class="gl-mr-3" />
|
|
144
|
+
<div class="gl-flex-1 gl-overflow-hidden">
|
|
165
145
|
<div class="gl-flex gl-items-center">
|
|
166
|
-
<h3 class="gl-my-0 gl-text-
|
|
146
|
+
<h3 class="gl-my-0 gl-text-size-h2">{{ title }}</h3>
|
|
147
|
+
<gl-experiment-badge v-if="badgeType" :type="badgeType" container-id="chat-component" />
|
|
167
148
|
</div>
|
|
149
|
+
<h4
|
|
150
|
+
v-if="subtitle"
|
|
151
|
+
class="gl-mb-0 gl-overflow-hidden gl-text-ellipsis gl-whitespace-nowrap gl-pr-3 gl-text-sm gl-font-normal gl-text-subtle"
|
|
152
|
+
data-testid="chat-subtitle"
|
|
153
|
+
>
|
|
154
|
+
{{ subtitle }}
|
|
155
|
+
</h4>
|
|
168
156
|
</div>
|
|
169
157
|
|
|
170
158
|
<div class="gl-flex gl-gap-3">
|
|
@@ -254,6 +242,16 @@ export default {
|
|
|
254
242
|
</span>
|
|
255
243
|
</gl-dropdown-item>
|
|
256
244
|
</gl-dropdown>
|
|
245
|
+
<gl-button
|
|
246
|
+
category="tertiary"
|
|
247
|
+
variant="default"
|
|
248
|
+
icon="close"
|
|
249
|
+
size="small"
|
|
250
|
+
class="gl-ml-auto"
|
|
251
|
+
data-testid="chat-close-button"
|
|
252
|
+
:aria-label="$options.i18n.CHAT_CLOSE_LABEL"
|
|
253
|
+
@click="$emit('close')"
|
|
254
|
+
/>
|
|
257
255
|
</div>
|
|
258
256
|
</div>
|
|
259
257
|
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Vue from 'vue';
|
|
3
|
+
import {
|
|
4
|
+
GlAlert,
|
|
5
|
+
GlBadge,
|
|
6
|
+
GlAvatar,
|
|
7
|
+
GlButton,
|
|
8
|
+
GlDropdown,
|
|
9
|
+
GlDropdownItem,
|
|
10
|
+
GlSafeHtmlDirective as SafeHtml,
|
|
11
|
+
GlTooltipDirective,
|
|
12
|
+
GlToast,
|
|
13
|
+
GlDisclosureDropdown,
|
|
14
|
+
} from '@gitlab/ui';
|
|
15
|
+
import { translate } from '../../../../utils/i18n';
|
|
16
|
+
import { VIEW_TYPES } from './constants';
|
|
17
|
+
|
|
18
|
+
export const i18n = {
|
|
19
|
+
CHAT_BACK_LABEL: translate('WebDuoChat.chatBackLabel', 'Back to history'),
|
|
20
|
+
CHAT_CLOSE_LABEL: translate('WebDuoChat.closeChatHeaderLabel', 'Close chat'),
|
|
21
|
+
CHAT_NEW_LABEL: translate('WebDuoChat.chatNewLabel', 'New chat'),
|
|
22
|
+
CHAT_NEW_TOOLTIP: translate('WebDuoChat.chatNewToolTip', 'New chat'),
|
|
23
|
+
CHAT_HISTORY_TOOLTIP: translate('WebDuoChat.chatHistoryToolTip', 'Chat history'),
|
|
24
|
+
CHAT_BACK_TO_CHAT_TOOLTIP: translate('WebDuoChat.chatBackToChatToolTip', 'Back to chat'),
|
|
25
|
+
CHAT_TITLE: translate('WebDuoChat.chatTitle', 'GitLab Duo Chat'),
|
|
26
|
+
CHAT_DROPDOWN_MORE_OPTIONS: translate('WebDuoChat.chatDropdownMoreOptions', 'More options'),
|
|
27
|
+
CHAT_COPY_TOOLTIP: translate('WebDuoChat.copySessionIdTooltip', 'Copy session ID'),
|
|
28
|
+
CHAT_COPY_SUCCESS_TOAST: translate(
|
|
29
|
+
'WebDuoChat.copySessionIdSuccessToast',
|
|
30
|
+
'Session ID copied to clipboard'
|
|
31
|
+
),
|
|
32
|
+
CHAT_COPY_FAILED_TOAST: translate(
|
|
33
|
+
'WebDuoChat.copySessionIdFailedToast',
|
|
34
|
+
'Could not copy session ID'
|
|
35
|
+
),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
Vue.use(GlToast);
|
|
39
|
+
|
|
40
|
+
export default {
|
|
41
|
+
name: 'DuoChatHeader',
|
|
42
|
+
|
|
43
|
+
components: {
|
|
44
|
+
GlAlert,
|
|
45
|
+
GlBadge,
|
|
46
|
+
GlAvatar,
|
|
47
|
+
GlButton,
|
|
48
|
+
GlDropdown,
|
|
49
|
+
GlDropdownItem,
|
|
50
|
+
GlDisclosureDropdown,
|
|
51
|
+
},
|
|
52
|
+
directives: {
|
|
53
|
+
SafeHtml,
|
|
54
|
+
GlTooltip: GlTooltipDirective,
|
|
55
|
+
},
|
|
56
|
+
props: {
|
|
57
|
+
title: {
|
|
58
|
+
type: String,
|
|
59
|
+
required: false,
|
|
60
|
+
default: i18n.CHAT_TITLE,
|
|
61
|
+
},
|
|
62
|
+
subtitle: {
|
|
63
|
+
type: String,
|
|
64
|
+
required: false,
|
|
65
|
+
default: '',
|
|
66
|
+
},
|
|
67
|
+
sessionId: {
|
|
68
|
+
type: String,
|
|
69
|
+
required: false,
|
|
70
|
+
default: '',
|
|
71
|
+
},
|
|
72
|
+
error: {
|
|
73
|
+
type: String,
|
|
74
|
+
required: false,
|
|
75
|
+
default: '',
|
|
76
|
+
},
|
|
77
|
+
isMultithreaded: {
|
|
78
|
+
type: Boolean,
|
|
79
|
+
required: false,
|
|
80
|
+
default: false,
|
|
81
|
+
},
|
|
82
|
+
shouldRenderResizable: {
|
|
83
|
+
type: Boolean,
|
|
84
|
+
required: false,
|
|
85
|
+
default: false,
|
|
86
|
+
},
|
|
87
|
+
activeThreadId: {
|
|
88
|
+
type: String,
|
|
89
|
+
required: false,
|
|
90
|
+
default: null,
|
|
91
|
+
},
|
|
92
|
+
badgeType: {
|
|
93
|
+
type: String,
|
|
94
|
+
required: false,
|
|
95
|
+
default: null,
|
|
96
|
+
},
|
|
97
|
+
currentView: {
|
|
98
|
+
type: String,
|
|
99
|
+
required: true,
|
|
100
|
+
},
|
|
101
|
+
agents: {
|
|
102
|
+
type: Array,
|
|
103
|
+
required: false,
|
|
104
|
+
default: () => [],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
computed: {
|
|
108
|
+
VIEW_TYPES() {
|
|
109
|
+
return VIEW_TYPES;
|
|
110
|
+
},
|
|
111
|
+
hasManyAgents() {
|
|
112
|
+
return this.agents.length > 1;
|
|
113
|
+
},
|
|
114
|
+
hasAgents() {
|
|
115
|
+
return this.agents.length > 0;
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
methods: {
|
|
119
|
+
startNewChat(agent) {
|
|
120
|
+
if (agent) {
|
|
121
|
+
this.$emit('new-chat', agent);
|
|
122
|
+
} else if (this.hasAgents) {
|
|
123
|
+
this.$emit('new-chat', this.agents[0]);
|
|
124
|
+
} else {
|
|
125
|
+
this.$emit('new-chat');
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
async copySessionIdToClipboard() {
|
|
129
|
+
try {
|
|
130
|
+
await navigator.clipboard.writeText(this.sessionId);
|
|
131
|
+
this.$toast.show('Session ID copied to clipboard');
|
|
132
|
+
} catch {
|
|
133
|
+
this.$toast.show('Could not copy session ID');
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
i18n,
|
|
138
|
+
};
|
|
139
|
+
</script>
|
|
140
|
+
|
|
141
|
+
<template>
|
|
142
|
+
<header data-testid="chat-header" class="gl-border-b gl-shrink-0 gl-bg-default gl-p-0">
|
|
143
|
+
<div class="gl-border-b gl-flex gl-w-full gl-items-center gl-px-5 gl-py-3">
|
|
144
|
+
<h4
|
|
145
|
+
v-if="subtitle"
|
|
146
|
+
class="gl-mb-0 gl-shrink-0 gl-overflow-hidden gl-text-ellipsis gl-whitespace-nowrap gl-pr-3 gl-text-sm gl-font-normal gl-text-subtle"
|
|
147
|
+
data-testid="chat-subtitle"
|
|
148
|
+
>
|
|
149
|
+
{{ subtitle }}
|
|
150
|
+
</h4>
|
|
151
|
+
<gl-button
|
|
152
|
+
category="tertiary"
|
|
153
|
+
variant="default"
|
|
154
|
+
icon="close"
|
|
155
|
+
size="small"
|
|
156
|
+
class="gl-ml-auto"
|
|
157
|
+
data-testid="chat-close-button"
|
|
158
|
+
:aria-label="$options.i18n.CHAT_CLOSE_LABEL"
|
|
159
|
+
@click="$emit('close')"
|
|
160
|
+
/>
|
|
161
|
+
</div>
|
|
162
|
+
<div class="drawer-title gl-flex gl-items-center gl-justify-start gl-p-5">
|
|
163
|
+
<div class="gl-flex gl-flex-1 gl-overflow-hidden">
|
|
164
|
+
<gl-avatar :size="32" :entity-name="title" shape="circle" class="gl-mr-3" />
|
|
165
|
+
<div class="gl-flex gl-items-center">
|
|
166
|
+
<h3 class="gl-my-0 gl-text-[0.875rem]">{{ title }}</h3>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<div class="gl-flex gl-gap-3">
|
|
171
|
+
<template
|
|
172
|
+
v-if="
|
|
173
|
+
isMultithreaded && (activeThreadId || currentView === VIEW_TYPES.LIST || hasManyAgents)
|
|
174
|
+
"
|
|
175
|
+
>
|
|
176
|
+
<gl-disclosure-dropdown
|
|
177
|
+
v-if="hasManyAgents"
|
|
178
|
+
:title="$options.i18n.CHAT_NEW_TOOLTIP"
|
|
179
|
+
:toggle-text="$options.i18n.CHAT_NEW_TOOLTIP"
|
|
180
|
+
:items="agents"
|
|
181
|
+
data-testid="chat-new-button"
|
|
182
|
+
variant="confirm"
|
|
183
|
+
category="tertiary"
|
|
184
|
+
size="small"
|
|
185
|
+
icon="duo-chat-new"
|
|
186
|
+
text-sr-only
|
|
187
|
+
:aria-label="$options.i18n.CHAT_NEW_LABEL"
|
|
188
|
+
no-caret
|
|
189
|
+
@action="startNewChat"
|
|
190
|
+
>
|
|
191
|
+
<template #list-item="{ item }">
|
|
192
|
+
<span class="gl-flex gl-flex-col">
|
|
193
|
+
<span clas="gl-block">{{ item.name }}</span>
|
|
194
|
+
<span class="gl-overflow-hidden gl-text-ellipsis gl-whitespace-nowrap gl-text-sm">{{
|
|
195
|
+
item.description
|
|
196
|
+
}}</span>
|
|
197
|
+
</span>
|
|
198
|
+
</template>
|
|
199
|
+
</gl-disclosure-dropdown>
|
|
200
|
+
<gl-button
|
|
201
|
+
v-else
|
|
202
|
+
v-gl-tooltip
|
|
203
|
+
:title="$options.i18n.CHAT_NEW_TOOLTIP"
|
|
204
|
+
data-testid="chat-new-button"
|
|
205
|
+
variant="confirm"
|
|
206
|
+
category="tertiary"
|
|
207
|
+
size="small"
|
|
208
|
+
icon="duo-chat-new"
|
|
209
|
+
:aria-label="$options.i18n.CHAT_NEW_LABEL"
|
|
210
|
+
@click="startNewChat"
|
|
211
|
+
/>
|
|
212
|
+
</template>
|
|
213
|
+
<gl-button
|
|
214
|
+
v-if="isMultithreaded && currentView === VIEW_TYPES.CHAT"
|
|
215
|
+
v-gl-tooltip
|
|
216
|
+
:title="$options.i18n.CHAT_HISTORY_TOOLTIP"
|
|
217
|
+
data-testid="go-back-to-list-button"
|
|
218
|
+
category="tertiary"
|
|
219
|
+
size="small"
|
|
220
|
+
icon="history"
|
|
221
|
+
:aria-label="$options.i18n.CHAT_BACK_LABEL"
|
|
222
|
+
@click="$emit('go-back')"
|
|
223
|
+
/>
|
|
224
|
+
<gl-button
|
|
225
|
+
v-if="isMultithreaded && activeThreadId && currentView === VIEW_TYPES.LIST"
|
|
226
|
+
v-gl-tooltip
|
|
227
|
+
:title="$options.i18n.CHAT_BACK_TO_CHAT_TOOLTIP"
|
|
228
|
+
data-testid="go-back-to-chat-button"
|
|
229
|
+
category="tertiary"
|
|
230
|
+
size="small"
|
|
231
|
+
icon="go-back"
|
|
232
|
+
:aria-label="$options.i18n.CHAT_BACK_TO_CHAT_TOOLTIP"
|
|
233
|
+
@click="$emit('go-back-to-chat')"
|
|
234
|
+
/>
|
|
235
|
+
<gl-dropdown
|
|
236
|
+
v-if="sessionId"
|
|
237
|
+
v-gl-tooltip.hover
|
|
238
|
+
icon="ellipsis_v"
|
|
239
|
+
category="tertiary"
|
|
240
|
+
text-sr-only
|
|
241
|
+
size="small"
|
|
242
|
+
:text="$options.i18n.CHAT_DROPDOWN_MORE_OPTIONS"
|
|
243
|
+
:title="$options.i18n.CHAT_DROPDOWN_MORE_OPTIONS"
|
|
244
|
+
no-caret
|
|
245
|
+
>
|
|
246
|
+
<gl-dropdown-item @click="copySessionIdToClipboard()">
|
|
247
|
+
<span class="gl-flex gl-items-center gl-gap-2">
|
|
248
|
+
<span class="gl-flex-shrink-0">{{ $options.i18n.CHAT_COPY_TOOLTIP }}</span>
|
|
249
|
+
<gl-badge class="gl-flex-shrink">
|
|
250
|
+
<span class="gl-max-w-12 gl-truncate" :title="sessionId">
|
|
251
|
+
{{ sessionId }}
|
|
252
|
+
</span>
|
|
253
|
+
</gl-badge>
|
|
254
|
+
</span>
|
|
255
|
+
</gl-dropdown-item>
|
|
256
|
+
</gl-dropdown>
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
259
|
+
|
|
260
|
+
<slot name="subheader"></slot>
|
|
261
|
+
|
|
262
|
+
<gl-alert
|
|
263
|
+
v-if="error"
|
|
264
|
+
key="error"
|
|
265
|
+
:dismissible="false"
|
|
266
|
+
variant="danger"
|
|
267
|
+
class="!gl-pl-9"
|
|
268
|
+
role="alert"
|
|
269
|
+
data-testid="chat-error"
|
|
270
|
+
>
|
|
271
|
+
<span v-safe-html="error"></span>
|
|
272
|
+
</gl-alert>
|
|
273
|
+
</header>
|
|
274
|
+
</template>
|
|
@@ -141,6 +141,7 @@ $drawer-width: 400px;
|
|
|
141
141
|
overflow: hidden;
|
|
142
142
|
background: var(--gl-control-background-color-default);
|
|
143
143
|
box-shadow: inset 0 0 0 $gl-border-size-1 var(--gl-control-border-color-default);
|
|
144
|
+
border-radius: px-to-rem(20px);
|
|
144
145
|
|
|
145
146
|
&:focus-within {
|
|
146
147
|
@include gl-focus($color: var(--gl-control-border-color-focus));
|
|
@@ -151,6 +152,7 @@ $drawer-width: 400px;
|
|
|
151
152
|
resize: none;
|
|
152
153
|
max-height: 240px;
|
|
153
154
|
padding-right: 40px;
|
|
155
|
+
border-radius: px-to-rem(20px);
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
&::after {
|
|
@@ -158,7 +160,6 @@ $drawer-width: 400px;
|
|
|
158
160
|
@apply gl-invisible;
|
|
159
161
|
@apply gl-p-4;
|
|
160
162
|
@apply gl-font-regular;
|
|
161
|
-
@apply gl-absolute;
|
|
162
163
|
padding-right: 40px;
|
|
163
164
|
word-break: break-word;
|
|
164
165
|
}
|