@gitlab/duo-ui 10.23.1 → 11.0.1

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.
@@ -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>