@gitlab/ui 90.5.0 → 91.1.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 +20 -0
- package/dist/components/base/path/path.js +2 -15
- package/dist/components/experimental/duo/chat/components/duo_chat_context/constants.js +5 -0
- package/dist/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_popover/duo_chat_context_item_popover.js +93 -0
- package/dist/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_selections/duo_chat_context_item_selections.js +91 -0
- package/dist/components/experimental/duo/chat/components/duo_chat_context/mock_context_data.js +121 -0
- package/dist/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.js +24 -1
- package/dist/components/experimental/duo/chat/mock_data.js +9 -3
- package/dist/index.css +2 -2
- package/dist/index.css.map +1 -1
- package/dist/tailwind.css +1 -1
- package/dist/tailwind.css.map +1 -1
- package/dist/tokens/build/js/tokens.dark.js +13 -1
- package/dist/tokens/build/js/tokens.js +13 -1
- package/dist/tokens/css/tokens.css +12 -0
- package/dist/tokens/css/tokens.dark.css +12 -0
- package/dist/tokens/js/tokens.dark.js +12 -0
- package/dist/tokens/js/tokens.js +12 -0
- package/dist/tokens/json/tokens.dark.json +278 -0
- package/dist/tokens/json/tokens.json +278 -0
- package/dist/tokens/scss/_tokens.dark.scss +12 -0
- package/dist/tokens/scss/_tokens.scss +12 -0
- package/dist/tokens/scss/_tokens_custom_properties.scss +12 -0
- package/dist/utils/constants.js +1 -2
- package/package.json +1 -1
- package/src/components/base/path/path.scss +44 -62
- package/src/components/base/path/path.vue +2 -15
- package/src/components/experimental/duo/chat/components/duo_chat_context/constants.js +3 -0
- package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_popover/duo_chat_context_item_popover.vue +111 -0
- package/src/components/experimental/duo/chat/components/duo_chat_context/duo_chat_context_item_selections/duo_chat_context_item_selections.vue +94 -0
- package/src/components/experimental/duo/chat/components/duo_chat_context/mock_context_data.js +137 -0
- package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.md +5 -0
- package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.vue +43 -0
- package/src/components/experimental/duo/chat/mock_data.js +8 -2
- package/src/tokens/action.tokens.json +86 -0
- package/src/tokens/build/css/tokens.css +12 -0
- package/src/tokens/build/css/tokens.dark.css +12 -0
- package/src/tokens/build/js/tokens.dark.js +12 -0
- package/src/tokens/build/js/tokens.js +12 -0
- package/src/tokens/build/json/tokens.dark.json +278 -0
- package/src/tokens/build/json/tokens.json +278 -0
- package/src/tokens/build/scss/_tokens.dark.scss +12 -0
- package/src/tokens/build/scss/_tokens.scss +12 -0
- package/src/tokens/build/scss/_tokens_custom_properties.scss +12 -0
- package/src/utils/constants.js +0 -2
- package/translations.js +3 -0
package/dist/utils/constants.js
CHANGED
|
@@ -26,7 +26,6 @@ const CONTRAST_LEVELS = [{
|
|
|
26
26
|
}];
|
|
27
27
|
const HEX_REGEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
28
28
|
const LEFT_MOUSE_BUTTON = 0;
|
|
29
|
-
const glThemes = ['indigo', 'blue', 'light-blue', 'green', 'red', 'light-red'];
|
|
30
29
|
const variantOptions = {
|
|
31
30
|
primary: 'primary',
|
|
32
31
|
secondary: 'secondary',
|
|
@@ -306,4 +305,4 @@ const loadingIconVariants = {
|
|
|
306
305
|
dots: 'dots'
|
|
307
306
|
};
|
|
308
307
|
|
|
309
|
-
export { COMMA, CONTRAST_LEVELS, HEX_REGEX, LEFT_MOUSE_BUTTON, alertVariantIconMap, alertVariantOptions, alignOptions, avatarShapeOptions, avatarSizeOptions, avatarsInlineSizeOptions, badgeForButtonOptions, badgeIconSizeOptions, badgeSizeOptions, badgeVariantOptions, bannerVariants, buttonCategoryOptions, buttonSizeOptions, buttonVariantOptions, colorThemes, columnOptions, datepickerWidthOptionsMap, defaultDateFormat, drawerVariants, dropdownAllowedAutoPlacements, dropdownPlacements, dropdownVariantOptions, focusableTags, formInputWidths, formStateOptions,
|
|
308
|
+
export { COMMA, CONTRAST_LEVELS, HEX_REGEX, LEFT_MOUSE_BUTTON, alertVariantIconMap, alertVariantOptions, alignOptions, avatarShapeOptions, avatarSizeOptions, avatarsInlineSizeOptions, badgeForButtonOptions, badgeIconSizeOptions, badgeSizeOptions, badgeVariantOptions, bannerVariants, buttonCategoryOptions, buttonSizeOptions, buttonVariantOptions, colorThemes, columnOptions, datepickerWidthOptionsMap, defaultDateFormat, drawerVariants, dropdownAllowedAutoPlacements, dropdownPlacements, dropdownVariantOptions, focusableTags, formInputWidths, formStateOptions, iconSizeOptions, iconVariantOptions, keyboard, labelColorOptions, loadingIconSizes, loadingIconVariants, maxZIndex, modalButtonDefaults, modalSizeOptions, popoverPlacements, resizeDebounceTime, tabsButtonDefaults, targetOptions, toggleLabelPosition, tokenVariants, tooltipActionEvents, tooltipDelay, tooltipPlacements, triggerVariantOptions, truncateOptions, variantCssColorMap, variantOptions, variantOptionsWithNoDefault, viewModeOptions };
|
package/package.json
CHANGED
|
@@ -6,25 +6,14 @@ $path-chevron-dimension: px-to-rem(24px);
|
|
|
6
6
|
$path-chevron-border-radius: px-to-rem(10px);
|
|
7
7
|
$path-chevron-tip-border-radius: px-to-rem(2px);
|
|
8
8
|
$path-button-right-padding: 1.25 * $grid-size;
|
|
9
|
-
$path-chevron-drop-shadow: drop-shadow(0 0 px-to-rem(1px) $white)
|
|
10
|
-
drop-shadow(0 0 px-to-rem(2px) $blue-500);
|
|
11
9
|
$path-chevron-transformation: rotate(45deg) skew(14deg, 14deg);
|
|
12
10
|
$path-chevron-right-margin: px-to-rem(14px);
|
|
13
11
|
|
|
14
12
|
// Mixins
|
|
15
|
-
@mixin gl-path-active-item-color($color) {
|
|
16
|
-
@include gl-text-contrast-light;
|
|
17
|
-
background-color: $color;
|
|
18
|
-
|
|
19
|
-
&::after {
|
|
20
|
-
background-color: $color;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
13
|
@mixin gl-path-chevron {
|
|
14
|
+
@include gl-reset-bg;
|
|
25
15
|
content: '';
|
|
26
16
|
position: absolute;
|
|
27
|
-
@include gl-reset-bg;
|
|
28
17
|
top: $path-chevron-top;
|
|
29
18
|
right: $path-chevron-right;
|
|
30
19
|
width: $path-chevron-dimension;
|
|
@@ -34,6 +23,7 @@ $path-chevron-right-margin: px-to-rem(14px);
|
|
|
34
23
|
border-top-left-radius: $path-chevron-border-radius;
|
|
35
24
|
border-bottom-right-radius: $path-chevron-border-radius;
|
|
36
25
|
border-top-right-radius: $path-chevron-tip-border-radius;
|
|
26
|
+
clip-path: polygon(100% 0, 0 0, 100% 100%);
|
|
37
27
|
}
|
|
38
28
|
|
|
39
29
|
.gl-path-nav {
|
|
@@ -43,11 +33,11 @@ $path-chevron-right-margin: px-to-rem(14px);
|
|
|
43
33
|
.gl-path-nav-list {
|
|
44
34
|
@include gl-p-1;
|
|
45
35
|
@include gl-m-0;
|
|
46
|
-
position: relative;
|
|
47
36
|
@include gl-list-style-none;
|
|
48
37
|
@include gl-display-inline-flex;
|
|
49
38
|
@include gl-overflow-hidden;
|
|
50
39
|
margin-left: -1px;
|
|
40
|
+
position: relative;
|
|
51
41
|
}
|
|
52
42
|
|
|
53
43
|
.gl-path-nav-list-item {
|
|
@@ -65,18 +55,18 @@ $path-chevron-right-margin: px-to-rem(14px);
|
|
|
65
55
|
@include gl-pl-5;
|
|
66
56
|
@include gl-py-3;
|
|
67
57
|
@include gl-display-flex;
|
|
68
|
-
position: relative;
|
|
69
58
|
@include gl-font-base;
|
|
70
59
|
@include gl-z-index-0;
|
|
71
|
-
@apply gl-border-none;
|
|
72
|
-
@include gl-text-gray-500;
|
|
73
60
|
@include gl-font-weight-bold;
|
|
74
61
|
@include gl-line-height-normal;
|
|
75
62
|
@include gl-rounded-top-left-base;
|
|
76
63
|
@include gl-rounded-bottom-left-base;
|
|
77
|
-
|
|
78
|
-
|
|
64
|
+
@apply gl-border-none;
|
|
65
|
+
background-color: var(--gl-action-neutral-background-color-default);
|
|
66
|
+
color: var(--gl-action-neutral-foreground-color-default);
|
|
79
67
|
margin-right: $path-chevron-right-margin;
|
|
68
|
+
padding-right: $path-button-right-padding;
|
|
69
|
+
position: relative;
|
|
80
70
|
|
|
81
71
|
&::before,
|
|
82
72
|
&::after {
|
|
@@ -85,47 +75,69 @@ $path-chevron-right-margin: px-to-rem(14px);
|
|
|
85
75
|
|
|
86
76
|
// Pseudo focus element
|
|
87
77
|
&::before {
|
|
78
|
+
background-color: var(--gl-color-alpha-0);
|
|
88
79
|
display: none;
|
|
89
80
|
z-index: 2;
|
|
90
81
|
right: calc(-0.75rem + 1px);
|
|
91
|
-
box-shadow: 0 0 0 1px
|
|
82
|
+
box-shadow: 0 0 0 1px var(--gl-focus-ring-inner-color), 0.5px -0.5px 0 2.5px var(--gl-focus-ring-outer-color);
|
|
92
83
|
clip-path: polygon(0% 0%, 0% -30%, 160% 0%, 75% 130%, 100% 100%);
|
|
93
84
|
transform: rotate(45deg) skew(14deg, 14deg) scale(0.99);
|
|
94
85
|
}
|
|
95
86
|
|
|
96
|
-
|
|
97
|
-
color:
|
|
98
|
-
|
|
87
|
+
&:hover {
|
|
88
|
+
background-color: var(--gl-action-neutral-background-color-hover);
|
|
89
|
+
color: var(--gl-action-neutral-foreground-color-hover);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
&:focus {
|
|
93
|
+
background-color: var(--gl-action-neutral-background-color-focus);
|
|
94
|
+
color: var(--gl-action-neutral-foreground-color-focus);
|
|
99
95
|
}
|
|
100
96
|
|
|
101
|
-
&:
|
|
102
|
-
|
|
103
|
-
color:
|
|
97
|
+
&:active {
|
|
98
|
+
background-color: var(--gl-action-neutral-background-color-active);
|
|
99
|
+
color: var(--gl-action-neutral-foreground-color-active);
|
|
104
100
|
}
|
|
105
101
|
|
|
106
102
|
&:active,
|
|
107
103
|
&:focus,
|
|
108
104
|
&:focus:active {
|
|
109
|
-
// Custom focus
|
|
105
|
+
// Custom focus to account for path shape
|
|
106
|
+
box-shadow: 5px -3px 0 -2px var(--gl-focus-ring-inner-color), 5px 3px 0 -2px var(--gl-focus-ring-inner-color), 0 0 0 1px var(--gl-focus-ring-inner-color),
|
|
107
|
+
0 0 0 3px var(--gl-focus-ring-outer-color);
|
|
108
|
+
outline: none;
|
|
110
109
|
border-top-right-radius: 1px;
|
|
111
110
|
border-bottom-right-radius: 1px;
|
|
112
|
-
box-shadow: 5px -3px 0 -2px $white, 5px 3px 0 -2px $white, 0 0 0 1px $white,
|
|
113
|
-
0 0 0 3px $blue-400;
|
|
114
|
-
outline: none;
|
|
115
111
|
|
|
116
112
|
&::before {
|
|
117
113
|
display: block;
|
|
118
114
|
}
|
|
119
115
|
}
|
|
116
|
+
|
|
117
|
+
&.gl-path-active-item {
|
|
118
|
+
background-color: var(--gl-action-selected-background-color-default);
|
|
119
|
+
color: var(--gl-action-selected-foreground-color-default);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
&:disabled {
|
|
123
|
+
@include gl-cursor-not-allowed;
|
|
124
|
+
background-color: var(--gl-color-alpha-0);
|
|
125
|
+
box-shadow: none;
|
|
126
|
+
color: var(--gl-action-disabled-foreground-color);
|
|
127
|
+
|
|
128
|
+
&::before {
|
|
129
|
+
box-shadow: none;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
120
132
|
}
|
|
121
133
|
|
|
122
134
|
.gl-path-fade {
|
|
123
135
|
@include gl-w-8;
|
|
124
136
|
@include gl-h-full;
|
|
137
|
+
@include gl-z-index-2;
|
|
125
138
|
bottom: 0;
|
|
139
|
+
color: var(--gl-text-color-subtle);
|
|
126
140
|
position: absolute;
|
|
127
|
-
@include gl-z-index-2;
|
|
128
|
-
@include gl-text-gray-500;
|
|
129
141
|
|
|
130
142
|
&-left {
|
|
131
143
|
left: 0;
|
|
@@ -141,41 +153,11 @@ $path-chevron-right-margin: px-to-rem(14px);
|
|
|
141
153
|
|
|
142
154
|
.gl-clear-icon-button {
|
|
143
155
|
@include gl-p-0;
|
|
144
|
-
@include gl-text-gray-400;
|
|
145
156
|
@include gl-h-full;
|
|
157
|
+
color: var(--gl-icon-color-subtle);
|
|
146
158
|
|
|
147
159
|
.gl-icon {
|
|
148
160
|
@include gl-vertical-align-middle;
|
|
149
161
|
}
|
|
150
162
|
}
|
|
151
|
-
|
|
152
|
-
.gl-path-active-item-indigo,
|
|
153
|
-
.gl-path-active-item-indigo:hover {
|
|
154
|
-
@include gl-path-active-item-color($theme-indigo-700);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
.gl-path-active-item-blue,
|
|
158
|
-
.gl-path-active-item-blue:hover {
|
|
159
|
-
@include gl-path-active-item-color($theme-blue-500);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
.gl-path-active-item-light-blue,
|
|
163
|
-
.gl-path-active-item-light-blue:hover {
|
|
164
|
-
@include gl-path-active-item-color($theme-light-blue-500);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
.gl-path-active-item-red,
|
|
168
|
-
.gl-path-active-item-red:hover {
|
|
169
|
-
@include gl-path-active-item-color($theme-red-500);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
.gl-path-active-item-light-red,
|
|
173
|
-
.gl-path-active-item-light-red:hover {
|
|
174
|
-
@include gl-path-active-item-color($theme-light-red-500);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
.gl-path-active-item-green,
|
|
178
|
-
.gl-path-active-item-green:hover {
|
|
179
|
-
@include gl-path-active-item-color($theme-green-500);
|
|
180
|
-
}
|
|
181
163
|
}
|
|
@@ -4,12 +4,11 @@ import iconSpriteInfo from '@gitlab/svgs/dist/icons.json';
|
|
|
4
4
|
import uniqueId from 'lodash/uniqueId';
|
|
5
5
|
import findLast from 'lodash/findLast';
|
|
6
6
|
import { GlResizeObserverDirective } from '../../../directives/resize_observer/resize_observer';
|
|
7
|
-
import { glThemes } from '../../../utils/constants';
|
|
8
7
|
import GlIcon from '../icon/icon.vue';
|
|
9
8
|
|
|
10
9
|
const BOUNDARY_WIDTH = 40;
|
|
11
10
|
const PATH_ITEM_CLASS = 'gl-path-button';
|
|
12
|
-
const
|
|
11
|
+
const PATH_ACTIVE_ITEM_CLASS = 'gl-path-active-item';
|
|
13
12
|
|
|
14
13
|
export default {
|
|
15
14
|
name: 'GlPath',
|
|
@@ -36,15 +35,6 @@ export default {
|
|
|
36
35
|
required: false,
|
|
37
36
|
default: () => [],
|
|
38
37
|
},
|
|
39
|
-
/**
|
|
40
|
-
* The color theme to be used.
|
|
41
|
-
*/
|
|
42
|
-
theme: {
|
|
43
|
-
type: String,
|
|
44
|
-
required: false,
|
|
45
|
-
default: 'indigo',
|
|
46
|
-
validator: (theme) => glThemes.includes(theme),
|
|
47
|
-
},
|
|
48
38
|
/**
|
|
49
39
|
* The items' background color.
|
|
50
40
|
*/
|
|
@@ -62,9 +52,6 @@ export default {
|
|
|
62
52
|
};
|
|
63
53
|
},
|
|
64
54
|
computed: {
|
|
65
|
-
activeClass() {
|
|
66
|
-
return `${PATH_ACTIVE_ITEM_PREFIX}-${this.theme}`;
|
|
67
|
-
},
|
|
68
55
|
entireListVisible() {
|
|
69
56
|
return this.width >= this.getScrollWidth();
|
|
70
57
|
},
|
|
@@ -97,7 +84,7 @@ export default {
|
|
|
97
84
|
methods: {
|
|
98
85
|
pathItemClass(index) {
|
|
99
86
|
return index === this.selectedIndex
|
|
100
|
-
? `${PATH_ITEM_CLASS} ${
|
|
87
|
+
? `${PATH_ITEM_CLASS} ${PATH_ACTIVE_ITEM_CLASS}`
|
|
101
88
|
: PATH_ITEM_CLASS;
|
|
102
89
|
},
|
|
103
90
|
onItemClicked(selectedIndex) {
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import GlPopover from '../../../../../../base/popover/popover.vue';
|
|
3
|
+
import { translate } from '../../../../../../../utils/i18n';
|
|
4
|
+
import {
|
|
5
|
+
CONTEXT_ITEM_TYPE_ISSUE,
|
|
6
|
+
CONTEXT_ITEM_TYPE_MERGE_REQUEST,
|
|
7
|
+
CONTEXT_ITEM_TYPE_PROJECT_FILE,
|
|
8
|
+
} from '../constants';
|
|
9
|
+
|
|
10
|
+
const ID_PREFIXES = {
|
|
11
|
+
issue: '#',
|
|
12
|
+
merge_request: '!',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
name: 'DuoChatContextItemPopover',
|
|
17
|
+
components: {
|
|
18
|
+
GlPopover,
|
|
19
|
+
},
|
|
20
|
+
props: {
|
|
21
|
+
item: {
|
|
22
|
+
type: Object,
|
|
23
|
+
required: true,
|
|
24
|
+
},
|
|
25
|
+
target: {
|
|
26
|
+
type: String,
|
|
27
|
+
required: true,
|
|
28
|
+
},
|
|
29
|
+
placement: {
|
|
30
|
+
type: String,
|
|
31
|
+
default: 'bottom',
|
|
32
|
+
required: false,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
computed: {
|
|
36
|
+
itemInfo() {
|
|
37
|
+
return this.item.metadata?.info || {};
|
|
38
|
+
},
|
|
39
|
+
id() {
|
|
40
|
+
const isIssuable =
|
|
41
|
+
this.item.type === CONTEXT_ITEM_TYPE_ISSUE ||
|
|
42
|
+
this.item.type === CONTEXT_ITEM_TYPE_MERGE_REQUEST;
|
|
43
|
+
return isIssuable ? this.itemInfo.iid || '' : null;
|
|
44
|
+
},
|
|
45
|
+
idPrefix() {
|
|
46
|
+
return ID_PREFIXES[this.item.type] || '';
|
|
47
|
+
},
|
|
48
|
+
filePath() {
|
|
49
|
+
return this.item.type === CONTEXT_ITEM_TYPE_PROJECT_FILE
|
|
50
|
+
? this.itemInfo.relFilePath || ''
|
|
51
|
+
: null;
|
|
52
|
+
},
|
|
53
|
+
isEnabled() {
|
|
54
|
+
return this.item.isEnabled !== false;
|
|
55
|
+
},
|
|
56
|
+
disabledMessage() {
|
|
57
|
+
return Array.isArray(this.item.disabledReasons) && this.item.disabledReasons.length > 0
|
|
58
|
+
? this.item.disabledReasons.join(', ')
|
|
59
|
+
: translate('DuoChatContextItemPopover.DisabledReason', 'This item is disabled');
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
methods: {
|
|
63
|
+
translate,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
</script>
|
|
67
|
+
<template>
|
|
68
|
+
<gl-popover
|
|
69
|
+
:target="target"
|
|
70
|
+
triggers="hover focus"
|
|
71
|
+
:placement="placement"
|
|
72
|
+
:title="item.metadata.name"
|
|
73
|
+
custom-class="gl-duo-chat-item-popover"
|
|
74
|
+
>
|
|
75
|
+
<template #title>
|
|
76
|
+
<span class="gl-text-sm gl-text-gray-500" data-testid="chat-context-popover-title">{{
|
|
77
|
+
item.metadata.name
|
|
78
|
+
}}</span>
|
|
79
|
+
</template>
|
|
80
|
+
<div class="gl-p-3">
|
|
81
|
+
<div class="gl-mb-2">
|
|
82
|
+
<strong class="gl-mr-1">{{
|
|
83
|
+
translate('DuoChatContextItemPopover.ProjectLabel', 'Project:')
|
|
84
|
+
}}</strong>
|
|
85
|
+
<span>{{ itemInfo.project }}</span>
|
|
86
|
+
</div>
|
|
87
|
+
<div v-if="filePath !== null" class="gl-mb-2">
|
|
88
|
+
<strong class="gl-mr-1">{{
|
|
89
|
+
translate('DuoChatContextItemPopover.PathLabel', 'Path:')
|
|
90
|
+
}}</strong>
|
|
91
|
+
<span>{{ filePath }}</span>
|
|
92
|
+
</div>
|
|
93
|
+
<div v-if="id !== null" class="gl-mb-2">
|
|
94
|
+
<strong class="gl-mr-1">{{ translate('DuoChatContextItemPopover.IdLabel', 'ID:') }}</strong>
|
|
95
|
+
<span>{{ idPrefix }}{{ id }}</span>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="gl-mb-2">
|
|
98
|
+
<strong class="gl-mr-1">{{
|
|
99
|
+
translate('DuoChatContextItemPopover.TypeLabel', 'Type:')
|
|
100
|
+
}}</strong>
|
|
101
|
+
<span>{{ item.type }}</span>
|
|
102
|
+
</div>
|
|
103
|
+
<div v-if="!isEnabled" class="gl-text-red-500" data-testid="chat-context-popover-disabled">
|
|
104
|
+
<strong class="gl-mr-1">{{
|
|
105
|
+
translate('DuoChatContextItemPopover.DisabledMessageLabel', 'Note:')
|
|
106
|
+
}}</strong>
|
|
107
|
+
<span>{{ disabledMessage }}</span>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</gl-popover>
|
|
111
|
+
</template>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import uniqueId from 'lodash/uniqueId';
|
|
3
|
+
import GlIcon from '../../../../../../base/icon/icon.vue';
|
|
4
|
+
import GlToken from '../../../../../../base/token/token.vue';
|
|
5
|
+
import GlDuoChatContextItemPopover from '../duo_chat_context_item_popover/duo_chat_context_item_popover.vue';
|
|
6
|
+
import {
|
|
7
|
+
CONTEXT_ITEM_TYPE_ISSUE,
|
|
8
|
+
CONTEXT_ITEM_TYPE_MERGE_REQUEST,
|
|
9
|
+
CONTEXT_ITEM_TYPE_PROJECT_FILE,
|
|
10
|
+
} from '../constants';
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
name: 'GlDuoChatContextItemSelections',
|
|
14
|
+
components: {
|
|
15
|
+
GlIcon,
|
|
16
|
+
GlDuoChatContextItemPopover,
|
|
17
|
+
GlToken,
|
|
18
|
+
},
|
|
19
|
+
props: {
|
|
20
|
+
selections: {
|
|
21
|
+
type: Array,
|
|
22
|
+
required: true,
|
|
23
|
+
},
|
|
24
|
+
title: {
|
|
25
|
+
type: String,
|
|
26
|
+
required: true,
|
|
27
|
+
},
|
|
28
|
+
defaultCollapsed: {
|
|
29
|
+
type: Boolean,
|
|
30
|
+
required: true,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
data() {
|
|
34
|
+
return {
|
|
35
|
+
isCollapsed: this.defaultCollapsed,
|
|
36
|
+
selectionsId: uniqueId(),
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
computed: {
|
|
40
|
+
collapseIconName() {
|
|
41
|
+
return this.isCollapsed ? 'chevron-right' : 'chevron-down';
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
methods: {
|
|
45
|
+
getIconName(type) {
|
|
46
|
+
const iconMap = {
|
|
47
|
+
[CONTEXT_ITEM_TYPE_PROJECT_FILE]: 'document',
|
|
48
|
+
[CONTEXT_ITEM_TYPE_ISSUE]: 'issues',
|
|
49
|
+
[CONTEXT_ITEM_TYPE_MERGE_REQUEST]: 'merge-request',
|
|
50
|
+
};
|
|
51
|
+
return iconMap[type] || 'document';
|
|
52
|
+
},
|
|
53
|
+
toggleCollapse() {
|
|
54
|
+
this.isCollapsed = !this.isCollapsed;
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<template>
|
|
61
|
+
<div class="gl-mb-3 gl-flex gl-flex-col">
|
|
62
|
+
<button
|
|
63
|
+
class="gl-flex gl-w-full gl-items-center gl-border-0 gl-bg-transparent gl-p-0 gl-text-left gl-text-xs gl-lowercase gl-text-gray-500"
|
|
64
|
+
data-testid="chat-context-selections-title"
|
|
65
|
+
@click="toggleCollapse"
|
|
66
|
+
>
|
|
67
|
+
<gl-icon :name="collapseIconName" data-testid="chat-context-collapse-icon" /> {{ title }}
|
|
68
|
+
</button>
|
|
69
|
+
|
|
70
|
+
<div
|
|
71
|
+
v-show="!isCollapsed"
|
|
72
|
+
class="gl-mt-1 gl-flex gl-grow gl-flex-wrap"
|
|
73
|
+
data-testid="chat-context-tokens-wrapper"
|
|
74
|
+
>
|
|
75
|
+
<gl-token
|
|
76
|
+
v-for="item in selections"
|
|
77
|
+
:key="item.id"
|
|
78
|
+
:view-only="true"
|
|
79
|
+
variant="default"
|
|
80
|
+
class="gl-mb-2 gl-mr-2"
|
|
81
|
+
>
|
|
82
|
+
<div :id="`context-item-${item.id}-${selectionsId}`" class="gl-flex gl-items-center">
|
|
83
|
+
<gl-icon :name="getIconName(item.type)" :size="12" class="gl-mr-1" />
|
|
84
|
+
{{ item.metadata.name }}
|
|
85
|
+
</div>
|
|
86
|
+
<gl-duo-chat-context-item-popover
|
|
87
|
+
:item="item"
|
|
88
|
+
:target="`context-item-${item.id}-${selectionsId}`"
|
|
89
|
+
placement="bottom"
|
|
90
|
+
/>
|
|
91
|
+
</gl-token>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</template>
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
export const MOCK_CONTEXT_ITEM_FILE = {
|
|
2
|
+
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
3
|
+
isEnabled: true,
|
|
4
|
+
metadata: {
|
|
5
|
+
name: 'strawberry.ts',
|
|
6
|
+
info: {
|
|
7
|
+
project: 'example/garden',
|
|
8
|
+
relFilePath: 'src/plants/strawberry.ts',
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
type: 'project_file',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const MOCK_CONTEXT_ITEM_FILE_DISABLED = {
|
|
15
|
+
id: '323e4567-e89b-12d3-a456-426614174002',
|
|
16
|
+
isEnabled: false,
|
|
17
|
+
metadata: {
|
|
18
|
+
name: 'motorbike.cs',
|
|
19
|
+
info: {
|
|
20
|
+
project: 'example/vehicles',
|
|
21
|
+
relFilePath: '/src/VehicleFoo/motorbike.cs',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
type: 'project_file',
|
|
25
|
+
};
|
|
26
|
+
const mockFiles = [
|
|
27
|
+
MOCK_CONTEXT_ITEM_FILE,
|
|
28
|
+
{
|
|
29
|
+
id: '223e4567-e89b-12d3-a456-426614174001',
|
|
30
|
+
isEnabled: true,
|
|
31
|
+
metadata: {
|
|
32
|
+
name: 'potato.ts',
|
|
33
|
+
info: {
|
|
34
|
+
project: 'example/garden',
|
|
35
|
+
relFilePath: '/src/plants/potato.ts',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
type: 'project_file',
|
|
39
|
+
},
|
|
40
|
+
MOCK_CONTEXT_ITEM_FILE_DISABLED,
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
export const MOCK_CONTEXT_ITEM_ISSUE = {
|
|
44
|
+
id: '423e4567-e89b-12d3-a456-426614174003',
|
|
45
|
+
isEnabled: true,
|
|
46
|
+
metadata: {
|
|
47
|
+
name: 'Implement watering schedule',
|
|
48
|
+
info: {
|
|
49
|
+
project: 'example/garden',
|
|
50
|
+
iid: 1234,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
type: 'issue',
|
|
54
|
+
};
|
|
55
|
+
export const MOCK_CONTEXT_ITEM_ISSUE_DISABLED = {
|
|
56
|
+
id: 'c463fb31-2a4c-4f8e-a609-97230ac48ae5',
|
|
57
|
+
isEnabled: false,
|
|
58
|
+
metadata: {
|
|
59
|
+
name: 'Fix vehicle colours',
|
|
60
|
+
info: {
|
|
61
|
+
project: 'example/vehicle',
|
|
62
|
+
iid: 91011,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
disabledReasons: ['This foo is not available to bar', 'Lorem something something wow?'],
|
|
66
|
+
type: 'issue',
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const mockIssues = [
|
|
70
|
+
MOCK_CONTEXT_ITEM_ISSUE,
|
|
71
|
+
{
|
|
72
|
+
id: '523e4567-e89b-12d3-a456-426614174004',
|
|
73
|
+
isEnabled: true,
|
|
74
|
+
metadata: {
|
|
75
|
+
name: 'Refactor plant growth rates',
|
|
76
|
+
info: {
|
|
77
|
+
project: 'example/garden',
|
|
78
|
+
iid: 5678,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
type: 'issue',
|
|
82
|
+
},
|
|
83
|
+
MOCK_CONTEXT_ITEM_ISSUE_DISABLED,
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
export const MOCK_CONTEXT_ITEM_MERGE_REQUEST = {
|
|
87
|
+
id: '623e4567-e89b-12d3-a456-426614174005',
|
|
88
|
+
isEnabled: true,
|
|
89
|
+
metadata: {
|
|
90
|
+
name: 'Improve database performance',
|
|
91
|
+
info: {
|
|
92
|
+
project: 'example/garden',
|
|
93
|
+
iid: 1122,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
type: 'merge_request',
|
|
97
|
+
};
|
|
98
|
+
export const MOCK_CONTEXT_ITEM_MERGE_REQUEST_DISABLED = {
|
|
99
|
+
id: '4eb665fc-e5e1-49b0-9789-2a16964e461a',
|
|
100
|
+
isEnabled: false,
|
|
101
|
+
metadata: {
|
|
102
|
+
name: 'Fix broken layout at small viewports',
|
|
103
|
+
info: {
|
|
104
|
+
project: 'example/vehicle',
|
|
105
|
+
iid: 5566,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
disabledReasons: ['This foo is not available to bar', 'Lorem something something wow?'],
|
|
109
|
+
type: 'merge_request',
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const mockMergeRequests = [
|
|
113
|
+
MOCK_CONTEXT_ITEM_MERGE_REQUEST,
|
|
114
|
+
{
|
|
115
|
+
id: '723e4567-e89b-12d3-a456-426614174006',
|
|
116
|
+
isEnabled: false,
|
|
117
|
+
metadata: {
|
|
118
|
+
name: 'Add vehicle registration details',
|
|
119
|
+
info: {
|
|
120
|
+
project: 'example/vehicle',
|
|
121
|
+
iid: 3344,
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
disabledReasons: ['This foo is not available to bar', 'Lorem something something wow?'],
|
|
125
|
+
type: 'merge_request',
|
|
126
|
+
},
|
|
127
|
+
MOCK_CONTEXT_ITEM_MERGE_REQUEST_DISABLED,
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
export const getMockContextItems = () => {
|
|
131
|
+
const allItems = [...mockFiles, ...mockIssues, ...mockMergeRequests];
|
|
132
|
+
|
|
133
|
+
// put disabled items in the back
|
|
134
|
+
const disabledItems = allItems.filter((item) => !item.isEnabled);
|
|
135
|
+
const enabledItems = allItems.filter((item) => item.isEnabled);
|
|
136
|
+
return [...enabledItems, ...disabledItems];
|
|
137
|
+
};
|
package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.md
CHANGED
|
@@ -62,3 +62,8 @@ The component emits the `track-feedback` event, a proxy of the `feedback` event
|
|
|
62
62
|
the `GlDuoUserFeedback` component. Please refer to
|
|
63
63
|
[the documentation on that component](/story/experimental-duo-user-feedback--docs#listening-to-the-feedback-form-submission)
|
|
64
64
|
when processing feedback from users.
|
|
65
|
+
|
|
66
|
+
## Included context references
|
|
67
|
+
|
|
68
|
+
Messages will display any included context references (files, issues merge requests etc.) when
|
|
69
|
+
the message `meta.contextItems` array contains valid items.
|