@gitlab/ui 78.1.2 → 78.2.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.
- package/CHANGELOG.md +14 -0
- package/dist/components/experimental/duo/chat/constants.js +2 -1
- package/dist/components/experimental/duo/chat/duo_chat.js +2 -5
- package/dist/components/experimental/duo/chat/mock_data.js +20 -2
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/tokens/css/tokens.css +1 -1
- package/dist/tokens/css/tokens.dark.css +1 -1
- package/dist/tokens/js/tokens.dark.js +1 -1
- package/dist/tokens/js/tokens.js +1 -1
- package/dist/tokens/scss/_tokens.dark.scss +1 -1
- package/dist/tokens/scss/_tokens.scss +1 -1
- package/package.json +4 -4
- package/src/components/base/table/table.scss +1 -6
- package/src/components/experimental/duo/chat/constants.js +1 -0
- package/src/components/experimental/duo/chat/duo_chat.spec.js +27 -37
- package/src/components/experimental/duo/chat/duo_chat.stories.js +11 -22
- package/src/components/experimental/duo/chat/duo_chat.vue +2 -5
- package/src/components/experimental/duo/chat/mock_data.js +31 -1
- package/src/scss/variables.scss +5 -0
package/dist/tokens/js/tokens.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "78.1
|
|
3
|
+
"version": "78.2.1",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
"@storybook/addon-viewport": "^7.6.17",
|
|
114
114
|
"@storybook/builder-webpack5": "^7.6.17",
|
|
115
115
|
"@storybook/test": "^7.6.17",
|
|
116
|
-
"@storybook/test-runner": "0.
|
|
116
|
+
"@storybook/test-runner": "0.17.0",
|
|
117
117
|
"@storybook/theming": "^7.6.17",
|
|
118
118
|
"@storybook/vue": "^7.6.17",
|
|
119
119
|
"@storybook/vue-webpack5": "^7.6.17",
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"babel-jest": "29.0.1",
|
|
132
132
|
"babel-loader": "^8.0.5",
|
|
133
133
|
"bootstrap": "4.6.2",
|
|
134
|
-
"cypress": "13.
|
|
134
|
+
"cypress": "13.7.0",
|
|
135
135
|
"cypress-axe": "^1.4.0",
|
|
136
136
|
"cypress-real-events": "^1.11.0",
|
|
137
137
|
"dompurify": "^3.0.0",
|
|
@@ -171,7 +171,7 @@
|
|
|
171
171
|
"sass-true": "^6.1.0",
|
|
172
172
|
"start-server-and-test": "^1.10.6",
|
|
173
173
|
"storybook": "^7.6.17",
|
|
174
|
-
"storybook-dark-mode": "
|
|
174
|
+
"storybook-dark-mode": "4.0.0",
|
|
175
175
|
"style-dictionary": "^3.8.0",
|
|
176
176
|
"stylelint": "15.10.2",
|
|
177
177
|
"tailwind-config-viewer": "1.7.3",
|
|
@@ -20,14 +20,9 @@ table.gl-table {
|
|
|
20
20
|
|
|
21
21
|
&.gl-text-right > span {
|
|
22
22
|
@include gl-display-flex;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
span:first-of-type {
|
|
26
|
-
order: 1;
|
|
27
|
-
}
|
|
23
|
+
flex-direction: row-reverse;
|
|
28
24
|
|
|
29
25
|
span:nth-of-type(2) {
|
|
30
|
-
order: 0;
|
|
31
26
|
@include gl-ml-0;
|
|
32
27
|
@include gl-mr-3;
|
|
33
28
|
}
|
|
@@ -8,30 +8,14 @@ import DuoChatLoader from './components/duo_chat_loader/duo_chat_loader.vue';
|
|
|
8
8
|
import DuoChatPredefinedPrompts from './components/duo_chat_predefined_prompts/duo_chat_predefined_prompts.vue';
|
|
9
9
|
import DuoChatConversation from './components/duo_chat_conversation/duo_chat_conversation.vue';
|
|
10
10
|
import GlDuoChat from './duo_chat.vue';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
MOCK_RESPONSE_MESSAGE,
|
|
13
|
+
MOCK_USER_PROMPT_MESSAGE,
|
|
14
|
+
SLASH_COMMANDS as slashCommands,
|
|
15
|
+
} from './mock_data';
|
|
12
16
|
|
|
13
17
|
import { MESSAGE_MODEL_ROLES, CHAT_RESET_MESSAGE } from './constants';
|
|
14
18
|
|
|
15
|
-
const slashCommands = [
|
|
16
|
-
{
|
|
17
|
-
name: '/reset',
|
|
18
|
-
shouldSubmit: true,
|
|
19
|
-
description: 'Reset conversation, ignore the previous messages.',
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
name: '/tests',
|
|
23
|
-
description: 'Write tests for the selected snippet.',
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
name: '/refactor',
|
|
27
|
-
description: 'Refactor the selected snippet.',
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: '/explain',
|
|
31
|
-
description: 'Explain the selected snippet.',
|
|
32
|
-
},
|
|
33
|
-
];
|
|
34
|
-
|
|
35
19
|
const invalidSlashCommands = [
|
|
36
20
|
{
|
|
37
21
|
name: '/foo',
|
|
@@ -373,6 +357,28 @@ describe('GlDuoChat', () => {
|
|
|
373
357
|
clickSubmit();
|
|
374
358
|
expect(wrapper.emitted('send-chat-prompt')).toBe(undefined);
|
|
375
359
|
});
|
|
360
|
+
|
|
361
|
+
it('resets the prompt after form submission', async () => {
|
|
362
|
+
const prompt = 'foo';
|
|
363
|
+
createComponent({ data: { prompt } });
|
|
364
|
+
expect(findChatInput().props('value')).toBe(prompt);
|
|
365
|
+
clickSubmit();
|
|
366
|
+
await nextTick();
|
|
367
|
+
expect(findChatInput().props('value')).toBe('');
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it('focuses on prompt after form submission', async () => {
|
|
371
|
+
const focusSpy = jest.fn();
|
|
372
|
+
jest.spyOn(HTMLElement.prototype, 'focus').mockImplementation(function focusMockImpl() {
|
|
373
|
+
focusSpy(this);
|
|
374
|
+
});
|
|
375
|
+
createComponent({ data: { prompt: 'TEST!' } });
|
|
376
|
+
|
|
377
|
+
clickSubmit();
|
|
378
|
+
await nextTick();
|
|
379
|
+
|
|
380
|
+
expect(focusSpy).toHaveBeenCalledWith(findChatInput().element);
|
|
381
|
+
});
|
|
376
382
|
});
|
|
377
383
|
|
|
378
384
|
describe('reset', () => {
|
|
@@ -456,20 +462,6 @@ describe('GlDuoChat', () => {
|
|
|
456
462
|
expect(findChatComponent().exists()).toBe(true);
|
|
457
463
|
});
|
|
458
464
|
|
|
459
|
-
it('resets the prompt when a message is loaded', async () => {
|
|
460
|
-
const prompt = 'foo';
|
|
461
|
-
createComponent({ data: { prompt } });
|
|
462
|
-
expect(findChatInput().props('value')).toBe(prompt);
|
|
463
|
-
// setProps is justified here because we are testing the component's
|
|
464
|
-
// reactive behavior which consistutes an exception
|
|
465
|
-
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
466
|
-
wrapper.setProps({
|
|
467
|
-
isLoading: true,
|
|
468
|
-
});
|
|
469
|
-
await nextTick();
|
|
470
|
-
expect(findChatInput().props('value')).toBe('');
|
|
471
|
-
});
|
|
472
|
-
|
|
473
465
|
it('renders custom loader when isLoading', () => {
|
|
474
466
|
createComponent({ propsData: { isLoading: true } });
|
|
475
467
|
expect(findCustomLoader().exists()).toBe(true);
|
|
@@ -773,7 +765,6 @@ describe('GlDuoChat', () => {
|
|
|
773
765
|
expect(findSelectedSlashCommand().text()).toContain(command);
|
|
774
766
|
findChatInput().trigger('keyup', { key: 'Enter' });
|
|
775
767
|
await nextTick();
|
|
776
|
-
expect(findChatInput().props('value')).toBe(`${command}`);
|
|
777
768
|
expect(wrapper.emitted('send-chat-prompt')).toEqual([[command]]);
|
|
778
769
|
});
|
|
779
770
|
});
|
|
@@ -827,7 +818,6 @@ describe('GlDuoChat', () => {
|
|
|
827
818
|
findSelectedSlashCommand().vm.$emit('click');
|
|
828
819
|
await nextTick();
|
|
829
820
|
|
|
830
|
-
expect(findChatInput().props('value')).toBe(slashCommandsNames[commandIndex]);
|
|
831
821
|
expect(wrapper.emitted('send-chat-prompt')).toEqual([
|
|
832
822
|
[slashCommandsNames[commandIndex]],
|
|
833
823
|
]);
|
|
@@ -3,33 +3,15 @@ import GlAlert from '../../../base/alert/alert.vue';
|
|
|
3
3
|
import { makeContainer } from '../../../../utils/story_decorators/container';
|
|
4
4
|
import GlDuoChat from './duo_chat.vue';
|
|
5
5
|
import readme from './duo_chat.md';
|
|
6
|
+
import { CHAT_CLEAN_MESSAGE } from './constants';
|
|
6
7
|
import {
|
|
7
8
|
MOCK_RESPONSE_MESSAGE,
|
|
8
9
|
MOCK_USER_PROMPT_MESSAGE,
|
|
10
|
+
SLASH_COMMANDS as slashCommands,
|
|
9
11
|
generateMockResponseChunks,
|
|
10
12
|
renderGFM,
|
|
11
13
|
} from './mock_data';
|
|
12
14
|
|
|
13
|
-
const slashCommands = [
|
|
14
|
-
{
|
|
15
|
-
name: '/reset',
|
|
16
|
-
shouldSubmit: true,
|
|
17
|
-
description: 'Reset conversation, ignore the previous messages.',
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
name: '/tests',
|
|
21
|
-
description: 'Write tests for the selected snippet.',
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
name: '/refactor',
|
|
25
|
-
description: 'Refactor the selected snippet.',
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
name: '/explain',
|
|
29
|
-
description: 'Explain the selected snippet.',
|
|
30
|
-
},
|
|
31
|
-
];
|
|
32
|
-
|
|
33
15
|
const defaultValue = (prop) =>
|
|
34
16
|
typeof GlDuoChat.props[prop].default === 'function'
|
|
35
17
|
? GlDuoChat.props[prop].default()
|
|
@@ -120,8 +102,12 @@ export const Interactive = (args, { argTypes }) => ({
|
|
|
120
102
|
requestId: this.requestId,
|
|
121
103
|
};
|
|
122
104
|
this.loggerInfo += `New prompt: ${JSON.stringify(newPrompt)}\n\n`;
|
|
123
|
-
|
|
124
|
-
|
|
105
|
+
if (prompt === CHAT_CLEAN_MESSAGE) {
|
|
106
|
+
this.msgs = [];
|
|
107
|
+
} else {
|
|
108
|
+
this.msgs.push(newPrompt);
|
|
109
|
+
this.promptInFlight = true;
|
|
110
|
+
}
|
|
125
111
|
},
|
|
126
112
|
onChatHidden() {
|
|
127
113
|
this.isHidden = true;
|
|
@@ -204,6 +190,8 @@ export const Interactive = (args, { argTypes }) => ({
|
|
|
204
190
|
:empty-state-title="emptyStateTitle"
|
|
205
191
|
:empty-state-description="emptyStateDescription"
|
|
206
192
|
:chat-prompt-placeholder="chatPromptPlaceholder"
|
|
193
|
+
:slash-commands="slashCommands"
|
|
194
|
+
class="gl-drawer-default"
|
|
207
195
|
@send-chat-prompt="onSendChatPrompt"
|
|
208
196
|
@chat-hidden="onChatHidden"
|
|
209
197
|
/>
|
|
@@ -253,6 +241,7 @@ export const Slots = (args, { argTypes }) => ({
|
|
|
253
241
|
</div>
|
|
254
242
|
`,
|
|
255
243
|
});
|
|
244
|
+
Slots.args = generateProps();
|
|
256
245
|
Slots.decorators = [makeContainer({ height: '800px' })];
|
|
257
246
|
|
|
258
247
|
export default {
|
|
@@ -253,13 +253,9 @@ export default {
|
|
|
253
253
|
},
|
|
254
254
|
},
|
|
255
255
|
watch: {
|
|
256
|
-
isLoading(
|
|
256
|
+
isLoading() {
|
|
257
257
|
this.isHidden = false;
|
|
258
258
|
this.scrollToBottom();
|
|
259
|
-
if (newVal) {
|
|
260
|
-
// We reset the prompt when we start getting the response and focus in the prompt field
|
|
261
|
-
this.setPromptAndFocus();
|
|
262
|
-
}
|
|
263
259
|
},
|
|
264
260
|
},
|
|
265
261
|
created() {
|
|
@@ -290,6 +286,7 @@ export default {
|
|
|
290
286
|
* @param {String} prompt The user prompt to send.
|
|
291
287
|
*/
|
|
292
288
|
this.$emit('send-chat-prompt', this.prompt);
|
|
289
|
+
this.setPromptAndFocus();
|
|
293
290
|
}
|
|
294
291
|
},
|
|
295
292
|
sendPredefinedPrompt(prompt) {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { setStoryTimeout } from '../../../../utils/test_utils';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
DOCUMENTATION_SOURCE_TYPES,
|
|
4
|
+
MESSAGE_MODEL_ROLES,
|
|
5
|
+
CHAT_RESET_MESSAGE,
|
|
6
|
+
CHAT_CLEAN_MESSAGE,
|
|
7
|
+
} from './constants';
|
|
3
8
|
|
|
4
9
|
const MOCK_SOURCES = [
|
|
5
10
|
{
|
|
@@ -119,3 +124,28 @@ export const renderGFM = (el) => {
|
|
|
119
124
|
block?.classList.add('gl-markdown', 'gl-compact-markdown');
|
|
120
125
|
});
|
|
121
126
|
};
|
|
127
|
+
|
|
128
|
+
export const SLASH_COMMANDS = [
|
|
129
|
+
{
|
|
130
|
+
name: CHAT_RESET_MESSAGE,
|
|
131
|
+
shouldSubmit: true,
|
|
132
|
+
description: 'Reset conversation, ignore the previous messages.',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: CHAT_CLEAN_MESSAGE,
|
|
136
|
+
shouldSubmit: true,
|
|
137
|
+
description: 'Delete all messages in this conversation.',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: '/tests',
|
|
141
|
+
description: 'Write tests for the selected snippet.',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: '/refactor',
|
|
145
|
+
description: 'Refactor the selected snippet.',
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: '/explain',
|
|
149
|
+
description: 'Explain the selected snippet.',
|
|
150
|
+
},
|
|
151
|
+
];
|
package/src/scss/variables.scss
CHANGED
|
@@ -213,6 +213,11 @@ $gl-transition-duration-slow: 0.4s;
|
|
|
213
213
|
$gl-transition-duration-medium: 0.2s;
|
|
214
214
|
$gl-transition-duration-fast: 0.1s;
|
|
215
215
|
|
|
216
|
+
// Animation easings
|
|
217
|
+
$gl-easing-linear: linear;
|
|
218
|
+
$gl-easing-default: ease;
|
|
219
|
+
$gl-easing-out-cubic: cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
220
|
+
|
|
216
221
|
// Focus ring
|
|
217
222
|
$outline-offset: 1px;
|
|
218
223
|
$outline-width: 2px;
|