@gitlab/ui 66.23.0 → 66.24.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 +14 -0
- package/dist/components/base/new_dropdowns/disclosure/disclosure_dropdown_group.js +2 -2
- package/dist/components/base/new_dropdowns/listbox/listbox.js +1 -1
- package/dist/components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader.js +100 -0
- package/dist/components/experimental/duo/chat/constants.js +2 -1
- package/dist/components/experimental/duo/user_feedback/user_feedback.js +1 -1
- 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 +2 -2
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown_group.vue +2 -2
- package/src/components/base/new_dropdowns/listbox/listbox.stories.js +1 -1
- package/src/components/base/new_dropdowns/listbox/listbox.vue +1 -1
- package/src/components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader.md +1 -0
- package/src/components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader.scss +67 -0
- package/src/components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader.spec.js +70 -0
- package/src/components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader.stories.js +31 -0
- package/src/components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader.vue +94 -0
- package/src/components/experimental/duo/chat/constants.js +2 -0
- package/src/components/experimental/duo/user_feedback/user_feedback.vue +1 -0
- package/src/scss/components.scss +1 -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": "66.
|
|
3
|
+
"version": "66.24.0",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"@gitlab/eslint-plugin": "19.0.0",
|
|
95
95
|
"@gitlab/fonts": "^1.2.0",
|
|
96
96
|
"@gitlab/stylelint-config": "5.0.0",
|
|
97
|
-
"@gitlab/svgs": "3.
|
|
97
|
+
"@gitlab/svgs": "3.65.0",
|
|
98
98
|
"@rollup/plugin-commonjs": "^11.1.0",
|
|
99
99
|
"@rollup/plugin-node-resolve": "^7.1.3",
|
|
100
100
|
"@rollup/plugin-replace": "^2.3.2",
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
} from './constants';
|
|
9
9
|
|
|
10
10
|
export const BORDER_CLASSES = {
|
|
11
|
-
[borderPositions.top]: 'gl-border-t gl-pt-2 gl-mt-2',
|
|
12
|
-
[borderPositions.bottom]: 'gl-border-b gl-pb-2 gl-mb-2',
|
|
11
|
+
[borderPositions.top]: 'gl-border-t gl-border-t-gray-200 gl-pt-2 gl-mt-2',
|
|
12
|
+
[borderPositions.bottom]: 'gl-border-b gl-border-b-gray-200 gl-pb-2 gl-mb-2',
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
export default {
|
|
@@ -199,7 +199,7 @@ export const HeaderAndFooter = (args, { argTypes }) => ({
|
|
|
199
199
|
template: template(
|
|
200
200
|
`
|
|
201
201
|
<template #footer>
|
|
202
|
-
<div class="gl-border-t-solid gl-border-t-1 gl-border-t-gray-
|
|
202
|
+
<div class="gl-border-t-solid gl-border-t-1 gl-border-t-gray-200 gl-display-flex gl-flex-direction-column gl-p-2! gl-pt-0!">
|
|
203
203
|
<gl-button @click="selectAllItems" category="tertiary" block class="gl-justify-content-start! gl-mt-2!">
|
|
204
204
|
Select all
|
|
205
205
|
</gl-button>
|
|
@@ -33,7 +33,7 @@ import { isOption, itemsValidator, flattenedOptions } from './utils';
|
|
|
33
33
|
|
|
34
34
|
export const ITEM_SELECTOR = '[role="option"]';
|
|
35
35
|
const HEADER_ITEMS_BORDER_CLASSES = ['gl-border-b-1', 'gl-border-b-solid', 'gl-border-b-gray-200'];
|
|
36
|
-
const GROUP_TOP_BORDER_CLASSES = ['gl-border-t', 'gl-pt-1', 'gl-mt-2'];
|
|
36
|
+
const GROUP_TOP_BORDER_CLASSES = ['gl-border-t', 'gl-border-t-gray-200', 'gl-pt-1', 'gl-mt-2'];
|
|
37
37
|
export const SEARCH_INPUT_SELECTOR = '.gl-listbox-search-input';
|
|
38
38
|
|
|
39
39
|
export default {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
The Duo Chat loader. Is shown while waiting for the chat response.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
.duo-chat-loader {
|
|
2
|
+
@include gl-py-3;
|
|
3
|
+
@include gl-px-4;
|
|
4
|
+
@include gl-mb-4;
|
|
5
|
+
@include gl-rounded-lg;
|
|
6
|
+
@include gl-rounded-bottom-left-none;
|
|
7
|
+
@include gl-display-flex;
|
|
8
|
+
@include gl-text-gray-500;
|
|
9
|
+
|
|
10
|
+
.transition {
|
|
11
|
+
transition: width 0.5s ease;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.text-enter {
|
|
15
|
+
@include gl-opacity-0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.text-enter-active {
|
|
19
|
+
transition: opacity 1s ease-in; // we intentionally overlap this transition with .text-leave-active by 200ms
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.text-enter-to {
|
|
23
|
+
@include gl-opacity-10;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.text-leave {
|
|
27
|
+
@include gl-opacity-10;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.text-leave-active {
|
|
31
|
+
transition: opacity 0.7s linear;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.text-leave-to {
|
|
35
|
+
@include gl-opacity-0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&__dot {
|
|
39
|
+
display: inline-block;
|
|
40
|
+
width: 0.3rem;
|
|
41
|
+
height: 0.3rem;
|
|
42
|
+
background-color: $gray-200;
|
|
43
|
+
border-radius: 100%;
|
|
44
|
+
animation: DuoChatLoading 1400ms ease-in-out infinite;
|
|
45
|
+
animation-fill-mode: both;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&__dot--1 {
|
|
49
|
+
animation-delay: -0.3s;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&__dot--2 {
|
|
53
|
+
animation-delay: -0.15s;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@keyframes DuoChatLoading {
|
|
58
|
+
0%,
|
|
59
|
+
80%,
|
|
60
|
+
100% {
|
|
61
|
+
transform: scale(0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
40% {
|
|
65
|
+
transform: scale(1);
|
|
66
|
+
}
|
|
67
|
+
}
|
package/src/components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader.spec.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { nextTick } from 'vue';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import { LOADING_TRANSITION_DURATION } from '../../constants';
|
|
4
|
+
import GlDuoChatLoader from './duo_chat_loader.vue';
|
|
5
|
+
|
|
6
|
+
jest.useFakeTimers();
|
|
7
|
+
|
|
8
|
+
describe('GlDuoChatLoader', () => {
|
|
9
|
+
let wrapper;
|
|
10
|
+
|
|
11
|
+
const createComponent = ({ propsData = {} } = {}) => {
|
|
12
|
+
wrapper = mount(GlDuoChatLoader, {
|
|
13
|
+
propsData,
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const transition = async () => {
|
|
18
|
+
jest.advanceTimersByTime(LOADING_TRANSITION_DURATION);
|
|
19
|
+
await nextTick();
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const findTransitionText = () => wrapper.find('[data-testid="current-transition"]').text();
|
|
23
|
+
const findToolText = () => wrapper.find('[data-testid="tool"]');
|
|
24
|
+
|
|
25
|
+
describe('rendering', () => {
|
|
26
|
+
const defaultTool = GlDuoChatLoader.props.toolName.default;
|
|
27
|
+
|
|
28
|
+
it('displays a default tool', async () => {
|
|
29
|
+
createComponent();
|
|
30
|
+
await nextTick();
|
|
31
|
+
|
|
32
|
+
expect(findToolText().text()).toBe(defaultTool);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('shows the `toolName` when it is passed', async () => {
|
|
36
|
+
createComponent({
|
|
37
|
+
propsData: {
|
|
38
|
+
toolName: 'foo',
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
await nextTick();
|
|
42
|
+
|
|
43
|
+
expect(findToolText().text()).toBe('foo');
|
|
44
|
+
expect(findToolText().text()).not.toBe(defaultTool);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('cycles through transition texts', async () => {
|
|
48
|
+
createComponent();
|
|
49
|
+
await nextTick();
|
|
50
|
+
|
|
51
|
+
expect(findTransitionText()).toEqual('finding');
|
|
52
|
+
|
|
53
|
+
await transition();
|
|
54
|
+
|
|
55
|
+
expect(findTransitionText()).toEqual('working on');
|
|
56
|
+
|
|
57
|
+
await transition();
|
|
58
|
+
|
|
59
|
+
expect(findTransitionText()).toEqual('generating');
|
|
60
|
+
|
|
61
|
+
await transition();
|
|
62
|
+
|
|
63
|
+
expect(findTransitionText()).toEqual('producing');
|
|
64
|
+
|
|
65
|
+
await transition();
|
|
66
|
+
|
|
67
|
+
expect(findTransitionText()).toEqual('finding');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
package/src/components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader.stories.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import GlDuoChatLoader from './duo_chat_loader.vue';
|
|
2
|
+
import readme from './duo_chat_loader.md';
|
|
3
|
+
|
|
4
|
+
const defaultValue = (prop) => GlDuoChatLoader.props[prop].default;
|
|
5
|
+
|
|
6
|
+
const generateProps = ({ toolName = defaultValue('toolName') } = {}) => ({
|
|
7
|
+
toolName,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const Template = (args, { argTypes }) => ({
|
|
11
|
+
components: { GlDuoChatLoader },
|
|
12
|
+
props: Object.keys(argTypes),
|
|
13
|
+
template: `
|
|
14
|
+
<gl-duo-chat-loader :tool-name="toolName" />
|
|
15
|
+
`,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const Default = Template.bind({});
|
|
19
|
+
Default.args = generateProps();
|
|
20
|
+
|
|
21
|
+
export default {
|
|
22
|
+
title: 'experimental/duo/chat/duo_chat_loader',
|
|
23
|
+
component: GlDuoChatLoader,
|
|
24
|
+
parameters: {
|
|
25
|
+
docs: {
|
|
26
|
+
description: {
|
|
27
|
+
component: readme,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import GlSprintf from '../../../../../utilities/sprintf/sprintf.vue';
|
|
3
|
+
import { LOADING_TRANSITION_DURATION } from '../../constants';
|
|
4
|
+
|
|
5
|
+
export const i18n = {
|
|
6
|
+
LOADER_LOADING_MESSAGE: '%{tool} is %{transition} an answer',
|
|
7
|
+
LOADER_LOADING_TRANSITIONS: ['finding', 'working on', 'generating', 'producing'],
|
|
8
|
+
GITLAB_DUO: 'GitLab Duo',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
name: 'GlDuoChatLoader',
|
|
13
|
+
components: {
|
|
14
|
+
GlSprintf,
|
|
15
|
+
},
|
|
16
|
+
i18n,
|
|
17
|
+
props: {
|
|
18
|
+
/**
|
|
19
|
+
* The message containing the name of the current AI tool working on the answer.
|
|
20
|
+
*/
|
|
21
|
+
toolName: {
|
|
22
|
+
type: String,
|
|
23
|
+
required: false,
|
|
24
|
+
default: i18n.GITLAB_DUO,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
data() {
|
|
28
|
+
return {
|
|
29
|
+
loadingSequence: 0,
|
|
30
|
+
timeout: null,
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
beforeDestroy() {
|
|
34
|
+
clearTimeout(this.timeout);
|
|
35
|
+
},
|
|
36
|
+
mounted() {
|
|
37
|
+
this.computeTransitionWidth();
|
|
38
|
+
this.enter();
|
|
39
|
+
},
|
|
40
|
+
methods: {
|
|
41
|
+
computeTransitionWidth() {
|
|
42
|
+
const container = this.$refs.transition;
|
|
43
|
+
const active = this.$refs.currentTransition[0]; // There's only one `currentTransition` ref at a time, but refs in v-for loops are always Arrays
|
|
44
|
+
const { width, height } = active.getBoundingClientRect();
|
|
45
|
+
container.$el.style.width = `${width}px`;
|
|
46
|
+
container.$el.style.height = `${height}px`;
|
|
47
|
+
},
|
|
48
|
+
enter() {
|
|
49
|
+
clearTimeout(this.timeout);
|
|
50
|
+
this.timeout = setTimeout(() => {
|
|
51
|
+
this.loadingSequence =
|
|
52
|
+
(this.loadingSequence + 1) % this.$options.i18n.LOADER_LOADING_TRANSITIONS.length;
|
|
53
|
+
this.enter();
|
|
54
|
+
}, LOADING_TRANSITION_DURATION);
|
|
55
|
+
},
|
|
56
|
+
isCurrentTransition(index) {
|
|
57
|
+
return index === this.loadingSequence;
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<template>
|
|
64
|
+
<div class="duo-chat-loader">
|
|
65
|
+
<div class="gl-display-flex gl-align-items-center gl-mr-3">
|
|
66
|
+
<div class="duo-chat-loader__dot duo-chat-loader__dot--1"></div>
|
|
67
|
+
<div class="duo-chat-loader__dot duo-chat-loader__dot--2"></div>
|
|
68
|
+
<div class="duo-chat-loader__dot duo-chat-loader__dot--3"></div>
|
|
69
|
+
</div>
|
|
70
|
+
<gl-sprintf :message="$options.i18n.LOADER_LOADING_MESSAGE">
|
|
71
|
+
<template #tool>
|
|
72
|
+
<strong class="gl-mr-2" data-testid="tool">{{ toolName }}</strong>
|
|
73
|
+
</template>
|
|
74
|
+
<template #transition>
|
|
75
|
+
<transition-group
|
|
76
|
+
ref="transition"
|
|
77
|
+
name="text"
|
|
78
|
+
class="transition gl-display-inline-block gl-mx-2"
|
|
79
|
+
@after-leave="computeTransitionWidth"
|
|
80
|
+
>
|
|
81
|
+
<span
|
|
82
|
+
v-for="(message, index) in $options.i18n.LOADER_LOADING_TRANSITIONS"
|
|
83
|
+
v-show="isCurrentTransition(index)"
|
|
84
|
+
:ref="isCurrentTransition(index) ? 'currentTransition' : ''"
|
|
85
|
+
:key="message"
|
|
86
|
+
:data-testid="isCurrentTransition(index) ? 'current-transition' : ''"
|
|
87
|
+
class="gl-white-space-nowrap"
|
|
88
|
+
>{{ message }}</span
|
|
89
|
+
>
|
|
90
|
+
</transition-group>
|
|
91
|
+
</template>
|
|
92
|
+
</gl-sprintf>
|
|
93
|
+
</div>
|
|
94
|
+
</template>
|
package/src/scss/components.scss
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// @import '../components/base/dropdown/dropdown'
|
|
4
4
|
//
|
|
5
5
|
// ADD COMPONENT IMPORTS - needed for yarn generate:component. Do not remove
|
|
6
|
+
@import '../components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader';
|
|
6
7
|
@import '../components/base/new_dropdowns/disclosure/disclosure_dropdown';
|
|
7
8
|
@import '../components/base/keyset_pagination/keyset_pagination';
|
|
8
9
|
@import '../components/charts/gauge/gauge';
|