@gitlab/ui 78.1.0 → 78.1.2

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.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Tue, 05 Mar 2024 12:25:08 GMT
3
+ * Generated on Wed, 13 Mar 2024 13:53:39 GMT
4
4
  */
5
5
 
6
6
  :root {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Tue, 05 Mar 2024 12:25:08 GMT
3
+ * Generated on Wed, 13 Mar 2024 13:53:39 GMT
4
4
  */
5
5
 
6
6
  :root.gl-dark {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Tue, 05 Mar 2024 12:25:08 GMT
3
+ * Generated on Wed, 13 Mar 2024 13:53:39 GMT
4
4
  */
5
5
 
6
6
  export const DATA_VIZ_GREEN_50 = "#133a03";
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Tue, 05 Mar 2024 12:25:08 GMT
3
+ * Generated on Wed, 13 Mar 2024 13:53:39 GMT
4
4
  */
5
5
 
6
6
  export const DATA_VIZ_GREEN_50 = "#ddfab7";
@@ -1,6 +1,6 @@
1
1
 
2
2
  // Do not edit directly
3
- // Generated on Tue, 05 Mar 2024 12:25:08 GMT
3
+ // Generated on Wed, 13 Mar 2024 13:53:39 GMT
4
4
 
5
5
  $gl-text-tertiary: #737278 !default;
6
6
  $gl-text-secondary: #89888d !default;
@@ -1,6 +1,6 @@
1
1
 
2
2
  // Do not edit directly
3
- // Generated on Tue, 05 Mar 2024 12:25:08 GMT
3
+ // Generated on Wed, 13 Mar 2024 13:53:39 GMT
4
4
 
5
5
  $gl-text-tertiary: #89888d !default;
6
6
  $gl-text-secondary: #737278 !default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "78.1.0",
3
+ "version": "78.1.2",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -102,7 +102,7 @@
102
102
  "@gitlab/eslint-plugin": "19.4.0",
103
103
  "@gitlab/fonts": "^1.3.0",
104
104
  "@gitlab/stylelint-config": "6.1.0",
105
- "@gitlab/svgs": "3.88.0",
105
+ "@gitlab/svgs": "3.89.0",
106
106
  "@rollup/plugin-commonjs": "^11.1.0",
107
107
  "@rollup/plugin-node-resolve": "^7.1.3",
108
108
  "@rollup/plugin-replace": "^2.3.2",
@@ -7,9 +7,7 @@ const defaultValue = (prop) => GlPopover.props[prop].default;
7
7
  const components = { GlPopover, GlButton };
8
8
 
9
9
  const contentString = `
10
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent volutpat a nisi non
11
- pellentesque. Pellentesque efficitur vulputate rutrum. Fusce nisl magna, porttitor in
12
- massa ac, porta condimentum libero. Ut id lacus tristique, egestas arcu non, molestie nisi.
10
+ A popover is used to provide supplemental, useful, unique information about an element.
13
11
  `;
14
12
 
15
13
  const getTemplate = (id, slots = '') => `
@@ -58,6 +56,23 @@ WithCloseButton.args = generateProps({
58
56
  showCloseButton: true,
59
57
  });
60
58
 
59
+ export const TextLinks = (_args, { viewMode, argTypes }) => ({
60
+ viewMode,
61
+ components,
62
+ props: Object.keys(argTypes),
63
+ template: getTemplate(
64
+ 'popover-with-text-links',
65
+ `
66
+ <template>
67
+ A popover is used to provide supplemental, useful, unique information about an element. This one has a link to <a class="gl-link" href="https://design.gitlab.com/components/popover">learn more about popovers.</a>
68
+ </template>
69
+ `
70
+ ),
71
+ });
72
+ TextLinks.args = generateProps({
73
+ showCloseButton: true,
74
+ });
75
+
61
76
  export const OnClick = (_args, { viewMode, argTypes }) => ({
62
77
  viewMode,
63
78
  components,
@@ -17,6 +17,25 @@ table.gl-table {
17
17
  th {
18
18
  @include gl-font-weight-bold;
19
19
  @include gl-text-gray-900;
20
+
21
+ &.gl-text-right > span {
22
+ @include gl-display-flex;
23
+ @include gl-justify-content-end;
24
+
25
+ span:first-of-type {
26
+ order: 1;
27
+ }
28
+
29
+ span:nth-of-type(2) {
30
+ order: 0;
31
+ @include gl-ml-0;
32
+ @include gl-mr-3;
33
+ }
34
+ }
35
+
36
+ [name='sort-icon'] {
37
+ user-select: none;
38
+ }
20
39
  }
21
40
 
22
41
  td {
@@ -121,3 +140,8 @@ table.gl-table {
121
140
  .table.b-table > tfoot > tr > th {
122
141
  background-image: none !important;
123
142
  }
143
+
144
+ .table.b-table > thead > tr > [aria-sort]:not(.b-table-sort-icon-left),
145
+ .table.b-table > tfoot > tr > [aria-sort]:not(.b-table-sort-icon-left) {
146
+ padding-right: 1rem;
147
+ }
@@ -3,7 +3,6 @@ import { shallowMount, mount } from '@vue/test-utils';
3
3
  import { BTable } from 'bootstrap-vue';
4
4
  import { logWarning } from '../../../utils/utils';
5
5
  import { waitForAnimationFrame } from '../../../utils/test_utils';
6
- import Icon from '../icon/icon.vue';
7
6
  import { glTableLiteWarning } from './constants';
8
7
  import Table from './table.vue';
9
8
 
@@ -100,20 +99,18 @@ describe('GlTable', () => {
100
99
  findFirstColHeader().trigger('click');
101
100
  await nextTick();
102
101
 
103
- const icon = findFirstColHeader().findComponent(Icon);
102
+ const headerText = findFirstColHeader().text();
104
103
 
105
- expect(icon.exists()).toBe(true);
106
- expect(icon.props('name')).toBe('arrow-up');
104
+ expect(headerText).toContain('↑');
107
105
  });
108
106
 
109
107
  it('renders the descending sort icon', async () => {
110
108
  findFirstColHeader().trigger('click');
111
109
  findFirstColHeader().trigger('click');
112
110
  await nextTick();
113
- const icon = findFirstColHeader().findComponent(Icon);
111
+ const headerText = findFirstColHeader().text();
114
112
 
115
- expect(icon.exists()).toBe(true);
116
- expect(icon.props('name')).toBe('arrow-down');
113
+ expect(headerText).toContain('↓');
117
114
  });
118
115
  });
119
116
 
@@ -136,11 +133,10 @@ describe('GlTable', () => {
136
133
  findFirstColHeader().trigger('click');
137
134
  await nextTick();
138
135
 
139
- const icon = findFirstColHeader().findComponent(Icon);
136
+ const headerText = findFirstColHeader().text();
140
137
 
141
- expect(icon.exists()).toBe(true);
142
- expect(icon.props('name')).toBe('arrow-up');
143
- expect(findFirstColHeader().text()).toContain(customSlotContent);
138
+ expect(headerText).toContain('↑');
139
+ expect(headerText).toContain(customSlotContent);
144
140
  });
145
141
  });
146
142
  });
@@ -7,15 +7,18 @@ const components = { GlTable };
7
7
  const tableItems = [
8
8
  {
9
9
  column_one: 'test',
10
- col_2: 1234,
10
+ col_2: 'ABC',
11
+ col_three: 1234,
11
12
  },
12
13
  {
13
14
  column_one: 'test2',
14
- col_2: 5678,
15
+ col_2: 'DEF',
16
+ col_three: 5678,
15
17
  },
16
18
  {
17
19
  column_one: 'test3',
18
- col_2: 9101,
20
+ col_2: 'GHI',
21
+ col_three: 9101,
19
22
  },
20
23
  ];
21
24
 
@@ -44,8 +47,9 @@ export const Default = (args, { argTypes }) => ({
44
47
  :fixed="fixed"
45
48
  :stacked="stacked"
46
49
  :foot-clone="footClone"
47
- sort-by="col_2"
50
+ sort-by="col_three"
48
51
  sort-desc
52
+ no-sort-reset
49
53
  hover
50
54
  selectable
51
55
  selected-variant="primary"
@@ -65,9 +69,16 @@ export const Default = (args, { argTypes }) => ({
65
69
  },
66
70
  {
67
71
  key: 'col_2',
72
+ label: 'Column 2',
73
+ formatter: (value) => value,
74
+ },
75
+ {
76
+ key: 'col_three',
68
77
  sortable: true,
69
78
  label: 'Column 2',
70
79
  formatter: (value) => value,
80
+ thClass: 'gl-text-right',
81
+ tdClass: 'gl-text-right',
71
82
  },
72
83
  ],
73
84
  items: tableItems,
@@ -1,7 +1,6 @@
1
1
  <!-- eslint-disable vue/multi-word-component-names -->
2
2
  <script>
3
3
  import { BTable } from 'bootstrap-vue';
4
- import GlIcon from '../icon/icon.vue';
5
4
  import { logWarning, isDev } from '../../../utils/utils';
6
5
  import { tableFullSlots, tableFullProps, glTableLiteWarning } from './constants';
7
6
 
@@ -18,7 +17,6 @@ export default {
18
17
  name: 'GlTable',
19
18
  components: {
20
19
  BTable,
21
- GlIcon,
22
20
  },
23
21
  inheritAttrs: false,
24
22
  props: {
@@ -98,17 +96,27 @@ export default {
98
96
  <slot :name="slotName" v-bind="scope"></slot>
99
97
  </template>
100
98
  <template v-for="headSlotName in headSlots" #[headSlotName]="scope">
101
- <div :key="headSlotName" class="gl-display-flex gl-align-items-center">
102
- <slot :name="headSlotName" v-bind="scope">{{ scope.label }}</slot
99
+ <span :key="headSlotName">
100
+ <slot :name="headSlotName" v-bind="scope"
101
+ ><span>{{ scope.label }}</span></slot
103
102
  ><template v-if="isSortable(scope)">
104
- <gl-icon
105
- v-if="getSortingIcon(scope)"
106
- :name="getSortingIcon(scope)"
107
- class="gl-ml-3 gl-min-w-5 gl-text-gray-900"
108
- />
109
- <div v-else class="gl-display-inline-block gl-w-5 gl-h-5 gl-ml-3"></div>
103
+ <span
104
+ v-if="getSortingIcon(scope) && getSortingIcon(scope) === 'arrow-up'"
105
+ class="gl-ml-3 gl-min-w-5 gl-text-gray-900 gl-text-center"
106
+ name="sort-icon"
107
+ >
108
+
109
+ </span>
110
+ <span
111
+ v-else-if="getSortingIcon(scope) && getSortingIcon(scope) === 'arrow-down'"
112
+ class="gl-ml-3 gl-min-w-5 gl-text-gray-900 gl-text-center"
113
+ name="sort-icon"
114
+ >
115
+
116
+ </span>
117
+ <span v-else class="gl-display-inline-block gl-w-5 gl-h-3 gl-ml-3"></span>
110
118
  </template>
111
- </div>
119
+ </span>
112
120
  </template>
113
121
  </b-table>
114
122
  </template>
@@ -8,6 +8,7 @@ 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 { MOCK_RESPONSE_MESSAGE, MOCK_USER_PROMPT_MESSAGE } from './mock_data';
11
12
 
12
13
  import { MESSAGE_MODEL_ROLES, CHAT_RESET_MESSAGE } from './constants';
13
14
 
@@ -339,11 +340,38 @@ describe('GlDuoChat', () => {
339
340
  data: { prompt: promptStr },
340
341
  });
341
342
  trigger();
342
- if (expectEmitted) {
343
- expect(wrapper.emitted('send-chat-prompt')).toEqual(expectEmitted);
344
- } else {
345
- expect(wrapper.emitted('send-chat-prompt')).toBe(undefined);
346
- }
343
+ expect(wrapper.emitted('send-chat-prompt')).toEqual(expectEmitted);
344
+ });
345
+
346
+ it.each`
347
+ desc | msgs
348
+ ${''} | ${[]}
349
+ ${'with just a user message'} | ${[MOCK_USER_PROMPT_MESSAGE]}
350
+ ${'with a user message, and a complete response'} | ${[MOCK_USER_PROMPT_MESSAGE, MOCK_RESPONSE_MESSAGE]}
351
+ `('prevents submission when loading $desc', ({ msgs } = {}) => {
352
+ createComponent({
353
+ propsData: { isChatAvailable: true, isLoading: true, messages: msgs },
354
+ data: { prompt: promptStr },
355
+ });
356
+ clickSubmit();
357
+ expect(wrapper.emitted('send-chat-prompt')).toBe(undefined);
358
+ });
359
+
360
+ it.each([
361
+ [[{ ...MOCK_RESPONSE_MESSAGE, content: undefined, chunks: [''] }]],
362
+ [
363
+ [
364
+ MOCK_USER_PROMPT_MESSAGE,
365
+ { ...MOCK_RESPONSE_MESSAGE, content: undefined, chunks: [''] },
366
+ ],
367
+ ],
368
+ ])('prevents submission when streaming (messages = "%o")', (msgs = []) => {
369
+ createComponent({
370
+ propsData: { isChatAvailable: true, messages: msgs },
371
+ data: { prompt: promptStr },
372
+ });
373
+ clickSubmit();
374
+ expect(wrapper.emitted('send-chat-prompt')).toBe(undefined);
347
375
  });
348
376
  });
349
377
 
@@ -428,7 +456,7 @@ describe('GlDuoChat', () => {
428
456
  expect(findChatComponent().exists()).toBe(true);
429
457
  });
430
458
 
431
- it('resets the prompt when new messages are added', async () => {
459
+ it('resets the prompt when a message is loaded', async () => {
432
460
  const prompt = 'foo';
433
461
  createComponent({ data: { prompt } });
434
462
  expect(findChatInput().props('value')).toBe(prompt);
@@ -436,7 +464,7 @@ describe('GlDuoChat', () => {
436
464
  // reactive behavior which consistutes an exception
437
465
  // See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
438
466
  wrapper.setProps({
439
- messages,
467
+ isLoading: true,
440
468
  });
441
469
  await nextTick();
442
470
  expect(findChatInput().props('value')).toBe('');
@@ -1,6 +1,5 @@
1
1
  import GlButton from '../../../base/button/button.vue';
2
2
  import GlAlert from '../../../base/alert/alert.vue';
3
- import { setStoryTimeout } from '../../../../utils/test_utils';
4
3
  import { makeContainer } from '../../../../utils/story_decorators/container';
5
4
  import GlDuoChat from './duo_chat.vue';
6
5
  import readme from './duo_chat.md';
@@ -132,32 +131,52 @@ export const Interactive = (args, { argTypes }) => ({
132
131
  this.isHidden = false;
133
132
  this.loggerInfo += `Chat opened\n\n`;
134
133
  },
135
- onResponseRequested() {
134
+ async onResponseRequested() {
136
135
  this.timeout = null;
137
- this.chunks = generateMockResponseChunks(this.requestId);
138
- this.mockResponseFromAi();
136
+ await this.mockResponseFromAi();
139
137
  this.requestId += 1;
140
138
  },
141
- mockResponseFromAi() {
142
- this.promptInFlight = false;
143
- if (this.chunks.length) {
144
- const newResponse = this.chunks.shift();
139
+ async mockResponseFromAi() {
140
+ const generator = generateMockResponseChunks(this.requestId);
141
+
142
+ for await (const result of generator) {
143
+ const { chunkId, content, ...messageAttributes } = result;
145
144
  const existingMessageIndex = this.msgs.findIndex(
146
- (msg) => msg.requestId === newResponse.requestId && msg.role === newResponse.role
145
+ (msg) => msg.requestId === result.requestId && msg.role === result.role
147
146
  );
148
- const existingMessage = this.msgs[existingMessageIndex];
149
- if (existingMessage) {
150
- this.msgs.splice(existingMessageIndex, 1, {
151
- ...existingMessage,
152
- content: existingMessage.content + newResponse.content,
153
- });
147
+
148
+ if (existingMessageIndex === -1) {
149
+ this.addNewMessage(messageAttributes, content);
150
+ } else {
151
+ this.updateExistingMessage(existingMessageIndex, content, chunkId);
152
+ }
153
+ }
154
+ },
155
+ addNewMessage(messageAttributes, content) {
156
+ this.promptInFlight = false;
157
+ this.$set(this.msgs, this.msgs.length, {
158
+ ...messageAttributes,
159
+ chunks: [content],
160
+ });
161
+ },
162
+ updateExistingMessage(index, content, chunkId) {
163
+ const message = this.msgs[index];
164
+
165
+ if (chunkId != null) {
166
+ // Ensure the chunks array exists
167
+ if (!message.chunks) {
168
+ this.$set(message, 'chunks', []);
154
169
  } else {
155
- this.msgs.push(newResponse);
170
+ this.$set(message.chunks, chunkId, content);
171
+ }
172
+ } else {
173
+ // Update for final message
174
+ this.$set(message, 'content', content);
175
+
176
+ // Remove chunks if they are not needed anymore
177
+ if (message.chunks) {
178
+ this.$delete(message, 'chunks');
156
179
  }
157
- this.logerInfo += `New response: ${JSON.stringify(newResponse)}\n\n`;
158
- this.timeout = setStoryTimeout(() => {
159
- this.mockResponseFromAi();
160
- }, Math.floor(Math.random() * 251) + 16);
161
180
  }
162
181
  },
163
182
  },
@@ -212,13 +212,20 @@ export default {
212
212
  [[]]
213
213
  );
214
214
  },
215
+ lastMessage() {
216
+ return this.messages[this.messages.length - 1];
217
+ },
215
218
  resetDisabled() {
216
219
  if (this.isLoading || !this.hasMessages) {
217
220
  return true;
218
221
  }
219
-
220
- const lastMessage = this.messages[this.messages.length - 1];
221
- return lastMessage.content === CHAT_RESET_MESSAGE;
222
+ return this.lastMessage?.content === CHAT_RESET_MESSAGE;
223
+ },
224
+ submitDisabled() {
225
+ return this.isLoading || this.isStreaming;
226
+ },
227
+ isStreaming() {
228
+ return Boolean(this.lastMessage?.chunks?.length > 0 && !this.lastMessage?.content);
222
229
  },
223
230
  filteredSlashCommands() {
224
231
  const caseInsensitivePrompt = this.prompt.toLowerCase();
@@ -246,12 +253,13 @@ export default {
246
253
  },
247
254
  },
248
255
  watch: {
249
- isLoading() {
256
+ isLoading(newVal) {
250
257
  this.isHidden = false;
251
258
  this.scrollToBottom();
252
- },
253
- messages() {
254
- this.prompt = '';
259
+ if (newVal) {
260
+ // We reset the prompt when we start getting the response and focus in the prompt field
261
+ this.setPromptAndFocus();
262
+ }
255
263
  },
256
264
  },
257
265
  created() {
@@ -269,6 +277,9 @@ export default {
269
277
  this.$emit('chat-hidden');
270
278
  },
271
279
  sendChatPrompt() {
280
+ if (this.submitDisabled) {
281
+ return;
282
+ }
272
283
  if (this.prompt) {
273
284
  if (this.prompt === CHAT_RESET_MESSAGE && this.resetDisabled) {
274
285
  return;
@@ -336,14 +347,18 @@ export default {
336
347
  this.activeCommandIndex = 0;
337
348
  }
338
349
  },
350
+ async setPromptAndFocus(prompt = '') {
351
+ this.prompt = prompt;
352
+ await this.$nextTick();
353
+ this.$refs.prompt.$el.focus();
354
+ },
339
355
  selectSlashCommand(index) {
340
356
  const command = this.filteredSlashCommands[index];
341
357
  if (command.shouldSubmit) {
342
358
  this.prompt = command.name;
343
359
  this.sendChatPrompt();
344
360
  } else {
345
- this.prompt = `${command.name} `;
346
- this.$refs.prompt.$el.focus();
361
+ this.setPromptAndFocus(`${command.name} `);
347
362
  }
348
363
  },
349
364
  },
@@ -494,7 +509,6 @@ export default {
494
509
  class="gl-absolute gl-h-full! gl-py-4! gl-bg-transparent! gl-rounded-top-right-none gl-rounded-bottom-right-none gl-shadow-none!"
495
510
  :class="{ 'gl-text-truncate': !prompt }"
496
511
  :placeholder="inputPlaceholder"
497
- :disabled="isLoading"
498
512
  autofocus
499
513
  @keydown.enter.exact.native.prevent
500
514
  @keyup.native="onInputKeyup"
@@ -507,8 +521,9 @@ export default {
507
521
  variant="confirm"
508
522
  class="!gl-absolute gl-bottom-2 gl-right-2 gl-rounded-base!"
509
523
  type="submit"
524
+ data-testid="chat-prompt-submit-button"
510
525
  :aria-label="$options.i18n.CHAT_SUBMIT_LABEL"
511
- :disabled="isLoading"
526
+ :disabled="submitDisabled"
512
527
  />
513
528
  </template>
514
529
  </gl-form-input-group>
@@ -1,3 +1,4 @@
1
+ import { setStoryTimeout } from '../../../../utils/test_utils';
1
2
  import { DOCUMENTATION_SOURCE_TYPES, MESSAGE_MODEL_ROLES } from './constants';
2
3
 
3
4
  const MOCK_SOURCES = [
@@ -66,24 +67,39 @@ export const MOCK_RESPONSE_MESSAGE_FOR_STREAMING = {
66
67
  timestamp: '2021-04-21T12:00:00.000Z',
67
68
  };
68
69
 
69
- export const generateMockResponseChunks = (requestId) => {
70
- const chunks = [];
70
+ // Utility function for delay
71
+ async function delayRandom(min = 16, max = 267) {
72
+ const delay = Math.floor(Math.random() * (max - min + 1)) + min;
73
+ // eslint-disable-next-line no-promise-executor-return
74
+ return new Promise((resolve) => setStoryTimeout(resolve, delay));
75
+ }
76
+
77
+ export async function* generateMockResponseChunks(requestId = 1) {
71
78
  const chunkSize = 5;
72
- const chunkCount = Math.ceil(MOCK_RESPONSE_MESSAGE_FOR_STREAMING.content.length / chunkSize);
73
- for (let i = 0; i < chunkCount; i += 1) {
79
+ const contentLength = MOCK_RESPONSE_MESSAGE_FOR_STREAMING.content.length;
80
+ const chunkCount = Math.ceil(contentLength / chunkSize);
81
+
82
+ for (let chunkId = 0; chunkId < chunkCount; chunkId += 1) {
83
+ const start = chunkId * chunkSize;
84
+ const end = Math.min((chunkId + 1) * chunkSize, contentLength);
74
85
  const chunk = {
75
86
  ...MOCK_RESPONSE_MESSAGE_FOR_STREAMING,
76
87
  requestId,
77
- content: MOCK_RESPONSE_MESSAGE_FOR_STREAMING.content.substring(
78
- i * chunkSize,
79
- (i + 1) * chunkSize
80
- ),
81
- chunkId: i,
88
+ content: MOCK_RESPONSE_MESSAGE_FOR_STREAMING.content.substring(start, end),
89
+ chunkId,
82
90
  };
83
- chunks.push(chunk);
91
+
92
+ // eslint-disable-next-line no-await-in-loop
93
+ await delayRandom();
94
+ yield chunk;
84
95
  }
85
- return chunks;
86
- };
96
+ yield {
97
+ ...MOCK_RESPONSE_MESSAGE_FOR_STREAMING,
98
+ requestId,
99
+ content: MOCK_RESPONSE_MESSAGE_FOR_STREAMING.content,
100
+ chunkId: null,
101
+ };
102
+ }
87
103
 
88
104
  export const MOCK_USER_PROMPT_MESSAGE = {
89
105
  id: '456',