@gitlab/ui 86.6.0 → 86.7.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.
Files changed (19) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/components/experimental/duo/chat/components/duo_chat_conversation/duo_chat_conversation.js +13 -1
  3. package/dist/components/experimental/duo/chat/components/duo_chat_message/buttons_utils.js +25 -0
  4. package/dist/components/experimental/duo/chat/components/duo_chat_message/copy_code_element.js +2 -21
  5. package/dist/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.js +9 -2
  6. package/dist/components/experimental/duo/chat/components/duo_chat_message/insert_code_snippet_element.js +20 -0
  7. package/dist/components/experimental/duo/chat/duo_chat.js +12 -1
  8. package/dist/components/experimental/duo/chat/mock_data.js +3 -1
  9. package/dist/index.css +1 -1
  10. package/dist/index.css.map +1 -1
  11. package/package.json +1 -1
  12. package/src/components/experimental/duo/chat/components/duo_chat_conversation/duo_chat_conversation.vue +17 -1
  13. package/src/components/experimental/duo/chat/components/duo_chat_message/buttons_utils.js +30 -0
  14. package/src/components/experimental/duo/chat/components/duo_chat_message/copy_code_element.js +2 -31
  15. package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.scss +19 -2
  16. package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.vue +9 -1
  17. package/src/components/experimental/duo/chat/components/duo_chat_message/insert_code_snippet_element.js +17 -0
  18. package/src/components/experimental/duo/chat/duo_chat.vue +13 -0
  19. package/src/components/experimental/duo/chat/mock_data.js +3 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "86.6.0",
3
+ "version": "86.7.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -29,6 +29,13 @@ export default {
29
29
  type: Array,
30
30
  required: true,
31
31
  },
32
+ /**
33
+ * Whether the insertCode feature should be available.
34
+ */
35
+ enableCodeInsertion: {
36
+ type: Boolean,
37
+ required: true,
38
+ },
32
39
  /**
33
40
  * Whether to show the delimiter before this conversation
34
41
  */
@@ -46,12 +53,20 @@ export default {
46
53
  */
47
54
  this.$emit('track-feedback', event);
48
55
  },
56
+ onInsertCodeSnippet(e) {
57
+ this.$emit('insert-code-snippet', e);
58
+ },
49
59
  },
50
60
  i18n,
51
61
  };
52
62
  </script>
53
63
  <template>
54
- <div class="gl-display-flex gl-flex-direction-column gl-justify-content-end">
64
+ <div
65
+ :class="[
66
+ 'gl-display-flex gl-flex-direction-column gl-justify-content-end',
67
+ { 'insert-code-hidden': !enableCodeInsertion },
68
+ ]"
69
+ >
55
70
  <div
56
71
  v-if="showDelimiter"
57
72
  class="gl-my-5 gl-display-flex gl-align-items-center gl-gap-4 gl-text-gray-500"
@@ -67,6 +82,7 @@ export default {
67
82
  :message="msg"
68
83
  :is-cancelled="canceledRequestIds.includes(msg.requestId)"
69
84
  @track-feedback="onTrackFeedback"
85
+ @insert-code-snippet="onInsertCodeSnippet"
70
86
  />
71
87
  </div>
72
88
  </template>
@@ -0,0 +1,30 @@
1
+ import iconsPath from '@gitlab/svgs/dist/icons.svg';
2
+
3
+ export const createButton = (title = 'Insert the code snippet', iconId = 'insert') => {
4
+ const button = document.createElement('button');
5
+ button.type = 'button';
6
+ button.classList.add(
7
+ 'btn',
8
+ 'btn-default',
9
+ 'btn-md',
10
+ 'gl-button',
11
+ 'btn-default-secondary',
12
+ 'btn-icon'
13
+ );
14
+ button.dataset.title = title;
15
+
16
+ // Create an SVG element with the correct namespace
17
+ const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
18
+ svg.setAttribute('role', 'img');
19
+ svg.setAttribute('aria-hidden', 'true');
20
+ svg.classList.add('gl-button-icon', 'gl-icon', 's16');
21
+
22
+ // Create a 'use' element with the correct namespace
23
+ const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
24
+ use.setAttribute('href', `${iconsPath}#${iconId}`);
25
+
26
+ svg.appendChild(use);
27
+ button.appendChild(svg);
28
+
29
+ return button;
30
+ };
@@ -1,38 +1,9 @@
1
- import iconsPath from '@gitlab/svgs/dist/icons.svg';
2
-
3
- const createButton = () => {
4
- const button = document.createElement('button');
5
- button.type = 'button';
6
- button.classList.add(
7
- 'btn',
8
- 'btn-default',
9
- 'btn-md',
10
- 'gl-button',
11
- 'btn-default-secondary',
12
- 'btn-icon'
13
- );
14
- button.dataset.title = 'Copy to clipboard';
15
-
16
- // Create an SVG element with the correct namespace
17
- const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
18
- svg.setAttribute('role', 'img');
19
- svg.setAttribute('aria-hidden', 'true');
20
- svg.classList.add('gl-button-icon', 'gl-icon', 's16');
21
-
22
- // Create a 'use' element with the correct namespace
23
- const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
24
- use.setAttribute('href', `${iconsPath}#copy-to-clipboard`);
25
-
26
- svg.appendChild(use);
27
- button.appendChild(svg);
28
-
29
- return button;
30
- };
1
+ import { createButton } from './buttons_utils';
31
2
 
32
3
  export class CopyCodeElement extends HTMLElement {
33
4
  constructor() {
34
5
  super();
35
- const btn = createButton();
6
+ const btn = createButton('Copy to clipboard', 'copy-to-clipboard');
36
7
  const wrapper = this.parentNode;
37
8
 
38
9
  this.appendChild(btn);
@@ -21,7 +21,8 @@
21
21
  @include gl-mb-0;
22
22
  }
23
23
 
24
- copy-code {
24
+ copy-code,
25
+ insert-code-snippet {
25
26
  position: absolute;
26
27
  @include gl-transition-medium;
27
28
  @include gl-opacity-0;
@@ -29,9 +30,15 @@
29
30
  top: $gl-spacing-scale-3;
30
31
  }
31
32
 
33
+ copy-code {
34
+ margin-right: $gl-spacing-scale-8;
35
+ }
36
+
32
37
  .js-markdown-code.markdown-code-block:hover {
33
38
  copy-code,
34
- copy-code:focus-within {
39
+ copy-code:focus-within,
40
+ insert-code-snippet,
41
+ insert-code-snippet:focus-within {
35
42
  @include gl-opacity-10;
36
43
  }
37
44
  }
@@ -45,3 +52,13 @@
45
52
  position: absolute;
46
53
  }
47
54
  }
55
+
56
+ .insert-code-hidden {
57
+ insert-code-snippet {
58
+ display: none;
59
+ }
60
+
61
+ copy-code {
62
+ margin-right: 0;
63
+ }
64
+ }
@@ -11,6 +11,7 @@ import DocumentationSources from '../duo_chat_message_sources/duo_chat_message_s
11
11
  // eslint-disable-next-line no-restricted-imports
12
12
  import { renderDuoChatMarkdownPreview } from '../../markdown_renderer';
13
13
  import { CopyCodeElement } from './copy_code_element';
14
+ import { InsertCodeSnippetElement } from './insert_code_snippet_element';
14
15
  import { concatUntilEmpty } from './utils';
15
16
 
16
17
  export const i18n = {
@@ -30,7 +31,7 @@ export default {
30
31
  name: 'GlDuoChatMessage',
31
32
  i18n,
32
33
  safeHtmlConfigExtension: {
33
- ADD_TAGS: ['copy-code'],
34
+ ADD_TAGS: ['copy-code', 'insert-code-snippet'],
34
35
  },
35
36
  components: {
36
37
  DocumentationSources,
@@ -132,6 +133,9 @@ export default {
132
133
  if (!customElements.get('copy-code')) {
133
134
  customElements.define('copy-code', CopyCodeElement);
134
135
  }
136
+ if (!customElements.get('insert-code-snippet')) {
137
+ customElements.define('insert-code-snippet', InsertCodeSnippetElement);
138
+ }
135
139
  },
136
140
  mounted() {
137
141
  if (this.isAssistantMessage) {
@@ -180,6 +184,9 @@ export default {
180
184
  this.stopWatchingMessage();
181
185
  }
182
186
  },
187
+ onInsertCodeSnippet(e) {
188
+ this.$emit('insert-code-snippet', e);
189
+ },
183
190
  },
184
191
  };
185
192
  </script>
@@ -193,6 +200,7 @@ export default {
193
200
  'gl-bg-white': isAssistantMessage && !error,
194
201
  'gl-bg-red-50 gl-border-none!': error,
195
202
  }"
203
+ @insert-code-snippet="onInsertCodeSnippet"
196
204
  >
197
205
  <gl-icon
198
206
  v-if="error"
@@ -0,0 +1,17 @@
1
+ import { createButton } from './buttons_utils';
2
+
3
+ export class InsertCodeSnippetElement extends HTMLElement {
4
+ constructor(codeBlock) {
5
+ super();
6
+ const btn = createButton();
7
+ const wrapper = codeBlock;
8
+ this.appendChild(btn);
9
+ btn.addEventListener('click', () => {
10
+ if (wrapper) {
11
+ wrapper.dispatchEvent(
12
+ new CustomEvent('insert-code-snippet', { bubbles: true, cancelable: true })
13
+ );
14
+ }
15
+ });
16
+ }
17
+ }
@@ -116,6 +116,14 @@ export default {
116
116
  required: false,
117
117
  default: true,
118
118
  },
119
+ /**
120
+ * Whether the insertCode feature should be available.
121
+ */
122
+ enableCodeInsertion: {
123
+ type: Boolean,
124
+ required: false,
125
+ default: false,
126
+ },
119
127
  /**
120
128
  * Array of predefined prompts to display in the chat to start a conversation.
121
129
  */
@@ -403,6 +411,9 @@ export default {
403
411
  this.setPromptAndFocus(`${command.name} `);
404
412
  }
405
413
  },
414
+ onInsertCodeSnippet(e) {
415
+ this.$emit('insert-code-snippet', e);
416
+ },
406
417
  },
407
418
  i18n,
408
419
  emptySvg,
@@ -487,10 +498,12 @@ export default {
487
498
  <gl-duo-chat-conversation
488
499
  v-for="(conversation, index) in conversations"
489
500
  :key="`conversation-${index}`"
501
+ :enable-code-insertion="enableCodeInsertion"
490
502
  :messages="conversation"
491
503
  :canceled-request-ids="canceledRequestIds"
492
504
  :show-delimiter="index > 0"
493
505
  @track-feedback="onTrackFeedback"
506
+ @insert-code-snippet="onInsertCodeSnippet"
494
507
  />
495
508
  <template v-if="!hasMessages && !isLoading">
496
509
  <gl-empty-state
@@ -1,4 +1,5 @@
1
1
  import { setStoryTimeout } from '../../../../utils/test_utils';
2
+ import { InsertCodeSnippetElement } from './components/duo_chat_message/insert_code_snippet_element';
2
3
  import {
3
4
  DOCUMENTATION_SOURCE_TYPES,
4
5
  MESSAGE_MODEL_ROLES,
@@ -31,7 +32,7 @@ export const MOCK_RESPONSE_MESSAGE = {
31
32
  content:
32
33
  'Here is a simple JavaScript function to sum two numbers:\n\n ```js\n function sum(a, b) {\n return a + b;\n }\n ```\n \n To use it:\n \n ```js\n const result = sum(5, 3); // result = 8\n ```\n \n This function takes two number parameters, a and b. It returns the sum of adding them together.\n',
33
34
  contentHtml:
34
- '<p data-sourcepos="1:1-1:56" dir="auto">Here is a simple JavaScript function to sum two numbers:</p>\n<div class="gl-relative markdown-code-block js-markdown-code">\n<pre data-sourcepos="3:1-7:3" data-canonical-lang="js" class="code highlight js-syntax-highlight language-javascript" lang="javascript" v-pre="true"><code><span id="LC1" class="line" lang="javascript"><span class="kd">function</span> <span class="nf">sum</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">{</span></span>\n<span id="LC2" class="line" lang="javascript"> <span class="k">return</span> <span class="nx">a</span> <span class="o">+</span> <span class="nx">b</span><span class="p">;</span></span>\n<span id="LC3" class="line" lang="javascript"><span class="p">}</span></span></code></pre>\n<copy-code></copy-code>\n</div>\n<p data-sourcepos="9:1-9:10" dir="auto">To use it:</p>\n<div class="gl-relative markdown-code-block js-markdown-code">\n<pre data-sourcepos="11:1-13:3" data-canonical-lang="js" class="code highlight js-syntax-highlight language-javascript" lang="javascript" v-pre="true"><code><span id="LC1" class="line" lang="javascript"><span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span> <span class="c1">// result = 8</span></span></code></pre>\n<copy-code></copy-code>\n</div>\n<p data-sourcepos="15:1-15:95" dir="auto">This function takes two number parameters, a and b. It returns the sum of adding them together.</p>',
35
+ '<p data-sourcepos="1:1-1:56" dir="auto">Here is a simple JavaScript function to sum two numbers:</p>\n<div class="gl-relative markdown-code-block js-markdown-code">\n<pre data-sourcepos="3:1-7:3" data-canonical-lang="js" class="code highlight js-syntax-highlight language-javascript" lang="javascript" v-pre="true"><code><span id="LC1" class="line" lang="javascript"><span class="kd">function</span> <span class="nf">sum</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">{</span></span>\n<span id="LC2" class="line" lang="javascript"> <span class="k">return</span> <span class="nx">a</span> <span class="o">+</span> <span class="nx">b</span><span class="p">;</span></span>\n<span id="LC3" class="line" lang="javascript"><span class="p">}</span></span></code></pre>\n<copy-code></copy-code>\n<insert-code-snippet></insert-code-snippet>\n</div>\n<p data-sourcepos="9:1-9:10" dir="auto">To use it:</p>\n<div class="gl-relative markdown-code-block js-markdown-code">\n<pre data-sourcepos="11:1-13:3" data-canonical-lang="js" class="code highlight js-syntax-highlight language-javascript" lang="javascript" v-pre="true"><code><span id="LC1" class="line" lang="javascript"><span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span> <span class="c1">// result = 8</span></span></code></pre>\n<copy-code></copy-code>\n</div>\n<p data-sourcepos="15:1-15:95" dir="auto">This function takes two number parameters, a and b. It returns the sum of adding them together.</p>',
35
36
  role: MESSAGE_MODEL_ROLES.assistant,
36
37
  extras: {
37
38
  sources: MOCK_SOURCES,
@@ -137,6 +138,7 @@ export const renderGFM = (el) => {
137
138
  const codeBlock = el.querySelectorAll('.markdown-code-block');
138
139
  codeBlock.forEach((block) => {
139
140
  block?.classList.add('gl-markdown', 'gl-compact-markdown');
141
+ block?.appendChild(new InsertCodeSnippetElement(block));
140
142
  });
141
143
  };
142
144