@gitlab/ui 67.2.0 → 67.3.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 CHANGED
@@ -1,3 +1,10 @@
1
+ # [67.3.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v67.2.0...v67.3.0) (2023-10-31)
2
+
3
+
4
+ ### Features
5
+
6
+ * **GlLineChart:** Defines a #tooltip-value slot ([4624919](https://gitlab.com/gitlab-org/gitlab-ui/commit/462491952e19832c9abd257b54130ed93244fd88))
7
+
1
8
  # [67.2.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v67.1.0...v67.2.0) (2023-10-30)
2
9
 
3
10
 
@@ -306,7 +306,7 @@ const __vue_script__ = script;
306
306
  /* template */
307
307
  var __vue_render__ = function () {
308
308
  var _obj;
309
- var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"position-relative",class:( _obj = {}, _obj[_vm.$options.HEIGHT_AUTO_CLASSES] = _vm.autoHeight, _obj )},[_c('chart',_vm._g(_vm._b({class:{ 'gl-flex-grow-1': _vm.autoHeight },attrs:{"height":_vm.height,"options":_vm.options},on:{"created":_vm.onCreated}},'chart',_vm.$attrs,false),_vm.$listeners)),_vm._v(" "),(_vm.shouldShowAnnotationsTooltip)?_c('chart-tooltip',{ref:"annotationsTooltip",attrs:{"id":"annotationsTooltip","show":_vm.showAnnotationsTooltip,"chart":_vm.chart,"top":_vm.annotationsTooltipPosition.top,"left":_vm.annotationsTooltipPosition.left,"placement":"bottom"},scopedSlots:_vm._u([{key:"title",fn:function(){return [_c('div',[_vm._v(_vm._s(_vm.annotationsTooltipTitle))])]},proxy:true}],null,false,1889294429)},[_vm._v(" "),_c('div',[_vm._v(_vm._s(_vm.annotationsTooltipContent))])]):_vm._e(),_vm._v(" "),(_vm.chart)?_c('chart-tooltip',{ref:"dataTooltip",staticClass:"gl-pointer-events-none",attrs:{"id":"dataTooltip","show":_vm.showDataTooltip,"chart":_vm.chart,"top":_vm.dataTooltipPosition.top,"left":_vm.dataTooltipPosition.left},scopedSlots:_vm._u([{key:"title",fn:function(){return [(_vm.formatTooltipText)?_vm._t("tooltip-title"):_c('div',[_vm._v("\n "+_vm._s(_vm.dataTooltipTitle)+"\n "),(_vm.options.xAxis.name)?[_vm._v("("+_vm._s(_vm.options.xAxis.name)+")")]:_vm._e()],2)]},proxy:true}],null,true)},[_vm._v(" "),(_vm.formatTooltipText)?_vm._t("tooltip-content"):_c('tooltip-default-format',{attrs:{"tooltip-content":_vm.dataTooltipContent}})],2):_vm._e(),_vm._v(" "),(_vm.hasLegend)?_c('chart-legend',{style:(_vm.legendStyle),attrs:{"chart":_vm.chart,"series-info":_vm.seriesInfo,"text-style":_vm.compiledOptions.textStyle,"min-text":_vm.legendMinText,"max-text":_vm.legendMaxText,"average-text":_vm.legendAverageText,"current-text":_vm.legendCurrentText,"layout":_vm.legendLayout}}):_vm._e()],1)};
309
+ var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"position-relative",class:( _obj = {}, _obj[_vm.$options.HEIGHT_AUTO_CLASSES] = _vm.autoHeight, _obj )},[_c('chart',_vm._g(_vm._b({class:{ 'gl-flex-grow-1': _vm.autoHeight },attrs:{"height":_vm.height,"options":_vm.options},on:{"created":_vm.onCreated}},'chart',_vm.$attrs,false),_vm.$listeners)),_vm._v(" "),(_vm.shouldShowAnnotationsTooltip)?_c('chart-tooltip',{ref:"annotationsTooltip",attrs:{"id":"annotationsTooltip","show":_vm.showAnnotationsTooltip,"chart":_vm.chart,"top":_vm.annotationsTooltipPosition.top,"left":_vm.annotationsTooltipPosition.left,"placement":"bottom"},scopedSlots:_vm._u([{key:"title",fn:function(){return [_c('div',[_vm._v(_vm._s(_vm.annotationsTooltipTitle))])]},proxy:true}],null,false,1889294429)},[_vm._v(" "),_c('div',[_vm._v(_vm._s(_vm.annotationsTooltipContent))])]):_vm._e(),_vm._v(" "),(_vm.chart)?_c('chart-tooltip',{ref:"dataTooltip",staticClass:"gl-pointer-events-none",attrs:{"id":"dataTooltip","show":_vm.showDataTooltip,"chart":_vm.chart,"top":_vm.dataTooltipPosition.top,"left":_vm.dataTooltipPosition.left},scopedSlots:_vm._u([{key:"title",fn:function(){return [(_vm.formatTooltipText)?_vm._t("tooltip-title"):_c('div',[_vm._v("\n "+_vm._s(_vm.dataTooltipTitle)+"\n "),(_vm.options.xAxis.name)?[_vm._v("("+_vm._s(_vm.options.xAxis.name)+")")]:_vm._e()],2)]},proxy:true}],null,true)},[_vm._v(" "),(_vm.formatTooltipText)?_vm._t("tooltip-content"):_c('tooltip-default-format',{attrs:{"tooltip-content":_vm.dataTooltipContent},scopedSlots:_vm._u([(_vm.$scopedSlots['tooltip-value'])?{key:"tooltip-value",fn:function(scope){return [_vm._t("tooltip-value",null,null,scope)]}}:null],null,true)})],2):_vm._e(),_vm._v(" "),(_vm.hasLegend)?_c('chart-legend',{style:(_vm.legendStyle),attrs:{"chart":_vm.chart,"series-info":_vm.seriesInfo,"text-style":_vm.compiledOptions.textStyle,"min-text":_vm.legendMinText,"max-text":_vm.legendMaxText,"average-text":_vm.legendAverageText,"current-text":_vm.legendCurrentText,"layout":_vm.legendLayout}}):_vm._e()],1)};
310
310
  var __vue_staticRenderFns__ = [];
311
311
 
312
312
  /* style */
@@ -18,7 +18,7 @@ var script = {
18
18
  const __vue_script__ = script;
19
19
 
20
20
  /* template */
21
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',_vm._l((_vm.tooltipContent),function(value,label){return _c('div',{key:("" + label + (value.value)),staticClass:"gl-charts-tooltip-default-format-series"},[_c('series-label',{staticClass:"gl-charts-tooltip-default-format-series-label",attrs:{"color":value.color}},[_vm._v("\n "+_vm._s(label)+"\n ")]),_vm._v(" "),_c('div',{staticClass:"gl-charts-tooltip-default-format-series-value"},[_vm._v("\n "+_vm._s(value.value)+"\n ")])],1)}),0)};
21
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',_vm._l((_vm.tooltipContent),function(value,label){return _c('div',{key:("" + label + (value.value)),staticClass:"gl-charts-tooltip-default-format-series"},[_c('series-label',{staticClass:"gl-charts-tooltip-default-format-series-label",attrs:{"color":value.color}},[_vm._v("\n "+_vm._s(label)+"\n ")]),_vm._v(" "),_c('div',{staticClass:"gl-charts-tooltip-default-format-series-value"},[_vm._t("tooltip-value",function(){return [_vm._v(_vm._s(value.value))]},{"value":value.value})],2)],1)}),0)};
22
22
  var __vue_staticRenderFns__ = [];
23
23
 
24
24
  /* style */
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Mon, 30 Oct 2023 10:30:21 GMT
3
+ * Generated on Tue, 31 Oct 2023 09:40:12 GMT
4
4
  */
5
5
 
6
6
  :root {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly
3
- * Generated on Mon, 30 Oct 2023 10:30:21 GMT
3
+ * Generated on Tue, 31 Oct 2023 09:40:12 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 Mon, 30 Oct 2023 10:30:21 GMT
3
+ * Generated on Tue, 31 Oct 2023 09:40:12 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, 30 Oct 2023 10:30:21 GMT
3
+ * Generated on Tue, 31 Oct 2023 09:40:12 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, 30 Oct 2023 10:30:21 GMT
3
+ // Generated on Tue, 31 Oct 2023 09:40:12 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, 30 Oct 2023 10:30:21 GMT
3
+ // Generated on Tue, 31 Oct 2023 09:40:12 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": "67.2.0",
3
+ "version": "67.3.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -1,10 +1,14 @@
1
+ import { nextTick } from 'vue';
1
2
  import { shallowMount } from '@vue/test-utils';
2
3
 
3
4
  import { LEGEND_LAYOUT_INLINE, LEGEND_LAYOUT_TABLE } from '~/utils/charts/constants';
4
5
  import { createMockChartInstance, ChartTooltipStub } from '~helpers/chart_stubs';
5
6
  import { expectHeightAutoClasses } from '~helpers/chart_height';
7
+
6
8
  import Chart from '../chart/chart.vue';
7
9
  import ChartLegend from '../legend/legend.vue';
10
+ import TooltipDefaultFormat from '../../shared_components/charts/tooltip_default_format.vue';
11
+
8
12
  import LineChart from './line.vue';
9
13
 
10
14
  let mockChartInstance;
@@ -39,7 +43,7 @@ describe('line component', () => {
39
43
  it('emits `created`, with the chart instance', async () => {
40
44
  createShallowWrapper();
41
45
 
42
- await wrapper.vm.$nextTick();
46
+ await nextTick();
43
47
 
44
48
  expect(wrapper.emitted('created').length).toBe(1);
45
49
  expect(wrapper.emitted('created')[0][0]).toBe(mockChartInstance);
@@ -49,7 +53,7 @@ describe('line component', () => {
49
53
  it('are hidden by default', async () => {
50
54
  createShallowWrapper();
51
55
 
52
- await wrapper.vm.$nextTick();
56
+ await nextTick();
53
57
 
54
58
  expect(findAnnotationsTooltip().exists()).toBe(false);
55
59
  });
@@ -64,7 +68,7 @@ describe('line component', () => {
64
68
  ],
65
69
  });
66
70
 
67
- await wrapper.vm.$nextTick();
71
+ await nextTick();
68
72
 
69
73
  expect(findAnnotationsTooltip().exists()).toBe(true);
70
74
  });
@@ -88,7 +92,7 @@ describe('line component', () => {
88
92
  },
89
93
  });
90
94
 
91
- await wrapper.vm.$nextTick();
95
+ await nextTick();
92
96
 
93
97
  expect(findAnnotationsTooltip().exists()).toBe(true);
94
98
  });
@@ -127,13 +131,65 @@ describe('line component', () => {
127
131
 
128
132
  wrapper.vm.onChartDataPointMouseOver(params);
129
133
 
130
- await wrapper.vm.$nextTick();
134
+ await nextTick();
131
135
 
132
136
  expect(findAnnotationsTooltip().html()).toContain(params.data.xAxis);
133
137
  expect(findAnnotationsTooltip().html()).toContain(params.data.tooltipData.content);
134
138
  });
135
139
  });
136
140
 
141
+ describe('tooltip', () => {
142
+ const tooltipParams = {
143
+ seriesData: [
144
+ {
145
+ seriesName: 'Series 1',
146
+ value: ['x', 1000],
147
+ color: '#fff',
148
+ },
149
+ {
150
+ seriesName: 'Series 2',
151
+ value: ['x', 1001],
152
+ color: '#fff',
153
+ },
154
+ ],
155
+ };
156
+
157
+ it('renders tooltip', async () => {
158
+ createShallowWrapper(
159
+ {},
160
+ {
161
+ stubs: { TooltipDefaultFormat },
162
+ }
163
+ );
164
+
165
+ wrapper.vm.defaultFormatTooltipText(tooltipParams); // force render of a tooltip
166
+ await nextTick();
167
+
168
+ const tooltipText = findDataTooltip().text();
169
+ expect(tooltipText).toContain('1000');
170
+ expect(tooltipText).toContain('1001');
171
+ });
172
+
173
+ it('renders formatted tooltip values', async () => {
174
+ createShallowWrapper(
175
+ {},
176
+ {
177
+ stubs: { TooltipDefaultFormat },
178
+ scopedSlots: {
179
+ 'tooltip-value': ({ value }) => `$ ${value.toLocaleString()}`,
180
+ },
181
+ }
182
+ );
183
+
184
+ wrapper.vm.defaultFormatTooltipText(tooltipParams); // force render of a tooltip
185
+ await nextTick();
186
+
187
+ const tooltipText = findDataTooltip().text();
188
+ expect(tooltipText).toContain('$ 1,000');
189
+ expect(tooltipText).toContain('$ 1,001');
190
+ });
191
+ });
192
+
137
193
  describe('tooltip position', () => {
138
194
  const dataTooltipTitle = 'FooBar';
139
195
 
@@ -160,7 +216,7 @@ describe('line component', () => {
160
216
 
161
217
  wrapper.setData({ dataTooltipPosition: { left, top }, dataTooltipTitle });
162
218
 
163
- await wrapper.vm.$nextTick();
219
+ await nextTick();
164
220
 
165
221
  expect(findDataTooltip().props('left')).toBe(`${left}`);
166
222
  expect(findDataTooltip().props('top')).toBe(`${top}`);
@@ -172,7 +228,7 @@ describe('line component', () => {
172
228
  it('is inline by default', async () => {
173
229
  createShallowWrapper();
174
230
 
175
- await wrapper.vm.$nextTick();
231
+ await nextTick();
176
232
 
177
233
  expect(findLegend().props('layout')).toBe(LEGEND_LAYOUT_INLINE);
178
234
  });
@@ -182,7 +238,7 @@ describe('line component', () => {
182
238
  legendLayout: LEGEND_LAYOUT_INLINE,
183
239
  });
184
240
 
185
- await wrapper.vm.$nextTick();
241
+ await nextTick();
186
242
 
187
243
  expect(findLegend().props('layout')).toBe(LEGEND_LAYOUT_INLINE);
188
244
  });
@@ -192,7 +248,7 @@ describe('line component', () => {
192
248
  legendLayout: LEGEND_LAYOUT_TABLE,
193
249
  });
194
250
 
195
- await wrapper.vm.$nextTick();
251
+ await nextTick();
196
252
 
197
253
  expect(findLegend().props('layout')).toBe(LEGEND_LAYOUT_TABLE);
198
254
  });
@@ -201,7 +257,7 @@ describe('line component', () => {
201
257
  showLegend: false,
202
258
  });
203
259
 
204
- await wrapper.vm.$nextTick();
260
+ await nextTick();
205
261
 
206
262
  expect(findLegend().exists()).toBe(false);
207
263
  });
@@ -390,7 +390,12 @@ export default {
390
390
  </div>
391
391
  </template>
392
392
  <slot v-if="formatTooltipText" name="tooltip-content"></slot>
393
- <tooltip-default-format v-else :tooltip-content="dataTooltipContent" />
393
+ <tooltip-default-format v-else :tooltip-content="dataTooltipContent">
394
+ <template v-if="$scopedSlots['tooltip-value']" #tooltip-value="scope">
395
+ <!-- @slot Tooltip value formatter -->
396
+ <slot name="tooltip-value" v-bind="scope"></slot>
397
+ </template>
398
+ </tooltip-default-format>
394
399
  </chart-tooltip>
395
400
  <chart-legend
396
401
  v-if="hasLegend"
@@ -0,0 +1,69 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+
3
+ import SeriesLabel from '../../charts/series_label/series_label.vue';
4
+ import TooltipDefaultFormat from './tooltip_default_format.vue';
5
+
6
+ const mockTooltipContent = {
7
+ 'Series A': {
8
+ color: '#000000',
9
+ value: 1000,
10
+ },
11
+ 'Series B': {
12
+ color: '#ffffff',
13
+ value: 5555.5,
14
+ },
15
+ };
16
+
17
+ describe('tooltip default format', () => {
18
+ let wrapper;
19
+
20
+ const createComponent = ({ props, ...options } = {}) => {
21
+ wrapper = shallowMount(TooltipDefaultFormat, {
22
+ propsData: {
23
+ tooltipContent: mockTooltipContent,
24
+ ...props,
25
+ },
26
+ ...options,
27
+ });
28
+ };
29
+
30
+ const findSeriesLabelAt = (i) => wrapper.findAllComponents(SeriesLabel).at(i);
31
+
32
+ it('renders default tooltip', () => {
33
+ createComponent();
34
+
35
+ const text = wrapper.text();
36
+
37
+ expect(text).toContain('Series A');
38
+ expect(text).toContain('1000');
39
+
40
+ expect(text).toContain('Series B');
41
+ expect(text).toContain('5555.5');
42
+ });
43
+
44
+ it('renders label colors', () => {
45
+ createComponent();
46
+
47
+ expect(findSeriesLabelAt(0).props('color')).toBe('#000000');
48
+ expect(findSeriesLabelAt(1).props('color')).toBe('#ffffff');
49
+ });
50
+
51
+ it('renders formatted values', () => {
52
+ createComponent({
53
+ scopedSlots: {
54
+ 'tooltip-value': ({ value }) =>
55
+ value.toLocaleString(undefined, {
56
+ minimumFractionDigits: 2,
57
+ }),
58
+ },
59
+ });
60
+
61
+ const text = wrapper.text();
62
+
63
+ expect(text).toContain('Series A');
64
+ expect(text).toContain('1,000.00');
65
+
66
+ expect(text).toContain('Series B');
67
+ expect(text).toContain('5,555.50');
68
+ });
69
+ });
@@ -25,7 +25,7 @@ export default {
25
25
  {{ label }}
26
26
  </series-label>
27
27
  <div class="gl-charts-tooltip-default-format-series-value">
28
- {{ value.value }}
28
+ <slot name="tooltip-value" :value="value.value">{{ value.value }}</slot>
29
29
  </div>
30
30
  </div>
31
31
  </div>