@gitlab/ui 66.32.0 → 66.33.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/dist/index.js CHANGED
@@ -88,6 +88,7 @@ export { default as GlCarousel } from './components/base/carousel/carousel';
88
88
  export { default as GlCarouselSlide } from './components/base/carousel/carousel_slide';
89
89
  export { default as GlExperimentBadge } from './components/experimental/experiment_badge/experiment_badge';
90
90
  export { default as GlDuoUserFeedback } from './components/experimental/duo/user_feedback/user_feedback';
91
+ export { default as GlDuoChat } from './components/experimental/duo/chat/duo_chat';
91
92
  export { default as GlAnimatedNumber } from './components/utilities/animated_number/animated_number';
92
93
  export { default as GlFriendlyWrap } from './components/utilities/friendly_wrap/friendly_wrap';
93
94
  export { default as GlIntersperse } from './components/utilities/intersperse/intersperse';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Mon, 16 Oct 2023 11:22:12 GMT
3
+ * Generated on Tue, 17 Oct 2023 12:41:31 GMT
4
4
  */
5
5
 
6
6
  :root {
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Mon, 16 Oct 2023 11:22:12 GMT
3
+ * Generated on Tue, 17 Oct 2023 12:41:31 GMT
4
4
  */
5
5
 
6
- :root {
6
+ :root.gl-dark {
7
7
  --red-950: #fff4f3;
8
8
  --red-900: #fcf1ef;
9
9
  --red-800: #fdd4cd;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Mon, 16 Oct 2023 11:22:12 GMT
3
+ * Generated on Tue, 17 Oct 2023 12:41:31 GMT
4
4
  */
5
5
 
6
6
  export const BLACK = "#fff";
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Mon, 16 Oct 2023 11:22:12 GMT
3
+ * Generated on Tue, 17 Oct 2023 12:41:31 GMT
4
4
  */
5
5
 
6
6
  export const BLACK = "#000";
@@ -1,6 +1,6 @@
1
1
 
2
2
  // Do not edit directly
3
- // Generated on Mon, 16 Oct 2023 11:22:12 GMT
3
+ // Generated on Tue, 17 Oct 2023 12:41:31 GMT
4
4
 
5
5
  $red-950: #fff4f3;
6
6
  $red-900: #fcf1ef;
@@ -1,6 +1,6 @@
1
1
 
2
2
  // Do not edit directly
3
- // Generated on Mon, 16 Oct 2023 11:22:12 GMT
3
+ // Generated on Tue, 17 Oct 2023 12:41:31 GMT
4
4
 
5
5
  $gl-line-height-52: 3.25rem;
6
6
  $gl-line-height-44: 2.75rem;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "66.32.0",
3
+ "version": "66.33.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -91,9 +91,9 @@
91
91
  "@babel/core": "^7.23.2",
92
92
  "@babel/preset-env": "^7.23.2",
93
93
  "@babel/preset-react": "^7.22.15",
94
- "@gitlab/eslint-plugin": "19.0.0",
95
- "@gitlab/fonts": "^1.2.0",
96
- "@gitlab/stylelint-config": "5.0.0",
94
+ "@gitlab/eslint-plugin": "19.2.0",
95
+ "@gitlab/fonts": "^1.3.0",
96
+ "@gitlab/stylelint-config": "5.0.1",
97
97
  "@gitlab/svgs": "3.66.0",
98
98
  "@rollup/plugin-commonjs": "^11.1.0",
99
99
  "@rollup/plugin-node-resolve": "^7.1.3",
@@ -122,7 +122,7 @@
122
122
  "babel-loader": "^8.0.5",
123
123
  "babel-plugin-require-context-hook": "^1.0.0",
124
124
  "bootstrap": "4.6.2",
125
- "cypress": "13.3.0",
125
+ "cypress": "13.3.1",
126
126
  "cypress-axe": "^1.4.0",
127
127
  "dompurify": "^3.0.0",
128
128
  "emoji-regex": "^10.0.0",
@@ -28,6 +28,16 @@ $clear-button-size: 24px;
28
28
  }
29
29
  }
30
30
 
31
+ // top container radius minus its border size to avoid the small gap between the focus ring and container
32
+ $input-focus-ring-border-radius: calc($gl-border-radius-large - $gl-border-size-1);
33
+
34
+ &.gl-listbox-topmost {
35
+ .gl-listbox-search-input {
36
+ border-top-left-radius: $input-focus-ring-border-radius;
37
+ border-top-right-radius: $input-focus-ring-border-radius;
38
+ }
39
+ }
40
+
31
41
  .gl-listbox-search-icon {
32
42
  @include gl-absolute;
33
43
  top: calc(50% - #{$search-icon-size} / 2);
@@ -809,6 +809,7 @@ export default {
809
809
  :aria-owns="listboxId"
810
810
  data-testid="listbox-search-input"
811
811
  :placeholder="searchPlaceholder"
812
+ :class="{ 'gl-listbox-topmost': !headerText }"
812
813
  @input="search"
813
814
  @keydown.enter.prevent
814
815
  @keydown="onKeydown"
@@ -1,3 +1,5 @@
1
+ export const CHAT_RESET_MESSAGE = '/reset';
2
+
1
3
  export const LOADING_TRANSITION_DURATION = 7500;
2
4
 
3
5
  export const DOCUMENTATION_SOURCE_TYPES = {
@@ -0,0 +1,143 @@
1
+ The component represents the complete Duo Chat feature.
2
+
3
+ The component provides a configurable chat UI interface. The primary use is communication with
4
+ GitLab Duo, however, the component is BE-agnostic and can accept information from any source.
5
+
6
+ ## Usage
7
+
8
+ To use the component in its simplest form, import it and add it to the `template` part of your
9
+ consumer component.
10
+
11
+ ```html
12
+ <gl-duo-chat
13
+ :title="title"
14
+ :messages="messages"
15
+ :error="error"
16
+ :is-loading="isLoading"
17
+ :is-chat-available="isChatAvailable"
18
+ :predefined-prompts="predefinedPrompts"
19
+ :experiment-help-page-url="experimentHelpPageUrl"
20
+ :tool-name="toolName"
21
+ @chat-hidden="onChatHidden"
22
+ @send-chat-prompt="onSendChatPrompt"
23
+ @track-feedback="onTrackFeedback"
24
+ />
25
+ ```
26
+
27
+ ## Integration
28
+
29
+ To demonstrate how to connect this component to a backend implementation, let's consider its use
30
+ for GitLab Duo. First, some general notes on the best practices and expectations when using this
31
+ component.
32
+
33
+ ### Expected dependency injection
34
+
35
+ To be universal, the component delegates some of its responsibilities to the consumer component.
36
+
37
+ The component expects two function props:
38
+
39
+ - `renderMarkdown`
40
+ - `renderGFM`
41
+
42
+ #### `renderMarkdown`
43
+
44
+ This function prop converts plain Markdown text into HTML markup. To have a better understanding
45
+ of what is expected from this function, take a look at
46
+ [the existing GitLab example](https://gitlab.com/gitlab-org/gitlab/-/blob/774ecc1f2b15a581e8eab6441de33585c9691c82/app/assets/javascripts/notes/utils.js#L22-24).
47
+
48
+ #### `renderGFM`
49
+
50
+ This function prop extends the standard Markdown rendering with support for the
51
+ [GitLab Flavored Markdown (GLFM)](https://docs.gitlab.com/ee/user/markdown.html). To
52
+ have a better understanding of what is expected from this function, take a look at
53
+ [the existing GitLab example](https://gitlab.com/gitlab-org/gitlab/-/blob/774ecc1f2b15a581e8eab6441de33585c9691c82/app/assets/javascripts/behaviors/markdown/render_gfm.js#L18-40).
54
+
55
+ The reason to have two different functions for rendering Markdown is performance. `renderGFM`
56
+ operates on a DOM node and might come with many additional mutations for the node's content.
57
+ Such behavior suits a one-time update. However, Duo Chat also supports streaming of the AI
58
+ responses (check the [Interactive story for this component](?path=/story/experimental-duo-chat-duo-chat--interactive))
59
+ and, in this case, when the message is constantly updating, we rely on a more lightweight
60
+ `renderMarkdown` to render the updated message faster.
61
+
62
+ ### Don't use reactivity where unnecessary
63
+
64
+ The `GlDuoChat` component exposes many properties, as seen below. But not all of those should
65
+ be necessarily reactive in the consumer component. The properties that might be static:
66
+
67
+ - `title`. The title is shown in the head of the component.
68
+ - `isChatAvailable`. The flag indicates whether the communication interface should allow follow-up
69
+ questions. Usually, this decision stays the same during the component's lifecycle.
70
+ - `predefinedPrompts`. The `Array` of strings that represents the possible questions to ask when
71
+ there are no messages in the chat.
72
+ - `experimentHelpPageUrl`. The link to an external page explaining the meaning of an "experiment".
73
+ The prop is passed down to the [`GlExperimentBadge` component](?path=/docs/experimental-experiment-badge--docs).
74
+
75
+ ### Set up communication with consumer
76
+
77
+ ```javascript
78
+ import { GlDuoChat } from '@gitlab/ui';
79
+
80
+ export default {
81
+ ...
82
+ data() {
83
+ return {
84
+ messages: [],
85
+ error: null,
86
+ isLoading: false,
87
+ toolName: '',
88
+ }
89
+ },
90
+ provide: {
91
+ renderMarkdown: (content) => {
92
+ // implementation of the `renderMarkdown` functionality
93
+ },
94
+ renderGFM: (el) => {
95
+ // implementation of the `renderGFM` functionality
96
+ },
97
+ },
98
+ beforeCreate() {
99
+ // Here, we set up our non-reactive properties if we must change the default values
100
+ this.title = 'Foo Bar';
101
+ this.isChatAvailable = true; // this is just an example. `true` is the default value
102
+ this.predefinedPrompts = ['How to …?', 'Where do I …?'];
103
+ this.experimentHelpPageUrl = 'https://dev.null';
104
+ }
105
+ methods: {
106
+ onChatHidden() {
107
+ ...
108
+ },
109
+ onSendChatPrompt(prompt = '') {
110
+ this.isLoading = true;
111
+ this.messages.push(constructUserMessage(prompt));
112
+ ...
113
+ },
114
+ onTrackFeedback(feedbackObj = {}) {
115
+ ...
116
+ },
117
+ onAiResponse(data) {
118
+ this.messages = data
119
+
120
+ this.isLoading = false;
121
+ },
122
+ onAiResponseError(error) {
123
+ this.error = error;
124
+ this.isLoading = false;
125
+ },
126
+ onToolNameChange(toolMessage) {
127
+ this.toolName = toolMessage.content;
128
+ }
129
+ }
130
+ }
131
+ ```
132
+
133
+ With this template in place, consumer is left with the following things to implement:
134
+
135
+ - Fetch `messages`. For Duo Chat, we rely on GraphQL query to get the cached
136
+ messages and subscription to monitor new messages when:
137
+
138
+ - streaming response
139
+ - listening to chat messages in other tabs/environments
140
+ - listen to updates from different tools to update `toolName`
141
+
142
+ - Send the new user's prompt. For Duo Chat, we rely on GraphQL mutation for this purpose.
143
+ - Send user feedback to the telemetry of your choice when `track-feedback` event arrives.
@@ -0,0 +1,50 @@
1
+ .duo-chat {
2
+ z-index: 999;
3
+
4
+ .message-enter-active,
5
+ .message-leave-active {
6
+ transition: all 0.5s ease;
7
+ }
8
+
9
+ .message-enter,
10
+ .message-leave-to {
11
+ @include gl-opacity-0;
12
+ transform: translateY(10px);
13
+ }
14
+
15
+ .loader-enter-active,
16
+ .loader-leave-active {
17
+ transition: opacity 0.5s ease;
18
+ }
19
+
20
+ .loader-enter,
21
+ .loader-leave-to {
22
+ @include gl-opacity-0;
23
+ }
24
+
25
+ .loader-leave-active {
26
+ @include gl-absolute;
27
+ }
28
+
29
+ .gl-drawer-body-scrim-on-footer {
30
+ &::before {
31
+ background: linear-gradient(to bottom, rgba($gray-10, 0), $gray-10);
32
+ }
33
+ }
34
+ }
35
+
36
+ .duo-chat-input {
37
+ @include gl-display-flex;
38
+ @include gl-flex-direction-column;
39
+
40
+ &:focus-within {
41
+ @include gl-focus($color: $gray-900);
42
+ }
43
+
44
+ .gl-form-textarea.form-control {
45
+ flex: 1;
46
+ resize: none;
47
+ max-height: 240px;
48
+ width: calc(100% - 40px);
49
+ }
50
+ }