@eturnity/eturnity_reusable_components 8.16.9-EPDM-15095.0 → 8.16.9-EPDM-14690.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_reusable_components",
3
- "version": "8.16.9-EPDM-15095.0",
3
+ "version": "8.16.9-EPDM-14690.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "src"
@@ -0,0 +1,229 @@
1
+ <template>
2
+ <div
3
+ style="
4
+ margin-top: 100px;
5
+ margin-left: 80px;
6
+ padding-bottom: 100px;
7
+ display: flex;
8
+ flex-direction: column;
9
+ "
10
+ >
11
+ <!-- Simple bar chart -->
12
+ <BarChart
13
+ :bar-width="60"
14
+ chart-controls-position="bottom"
15
+ :data="monthlyData"
16
+ height="400px"
17
+ :is-bottom-fields-shown="true"
18
+ :is-scrollable="false"
19
+ :is-selection-enabled="true"
20
+ :selection-size="3"
21
+ :value-formatter="valueFormatter"
22
+ width="700px"
23
+ @selection-change="handleSelectionChange"
24
+ />
25
+ <br />
26
+ <br />
27
+
28
+ <!-- Stacked bar chart -->
29
+ <BarChart
30
+ :bar-width="60"
31
+ :data="monthLabels"
32
+ height="400px"
33
+ :is-bottom-fields-shown="true"
34
+ :is-legend-shown="true"
35
+ :legends-item-per-row="4"
36
+ :selected-split-button="selectedTimeFrame"
37
+ :series="tariffZones"
38
+ :show-percentage-on-tooltip="true"
39
+ :split-button-options="options"
40
+ :value-formatter="valueFormatter"
41
+ width="700px"
42
+ y-axis-title="Energy (kWh)"
43
+ @input-blur="handleInputBlur"
44
+ @select-split-button="handleSelectSplitButton"
45
+ />
46
+
47
+ <!-- Stacked bar chart -->
48
+ <BarChart
49
+ :bar-width="60"
50
+ :data="monthLabels"
51
+ field-mode="percentage"
52
+ height="400px"
53
+ :is-bottom-fields-shown="true"
54
+ :is-legend-shown="false"
55
+ :legends-item-per-row="4"
56
+ :series="tariffZones"
57
+ :value-formatter="valueFormatter"
58
+ width="700px"
59
+ @input-blur="handleInputBlur"
60
+ @select-split-button="handleSelectSplitButton"
61
+ >
62
+ <!-- <template #tooltip="{ item, segment }">
63
+ <div style="display: flex; flex-direction: column">
64
+ {{ $c.log(item, segment) }}
65
+ <div>{{ item.label }}</div>
66
+ <div>{{ item.segments[0].value }} kWh</div>
67
+ </div>
68
+ </template> -->
69
+ </BarChart>
70
+ </div>
71
+ </template>
72
+
73
+ <script setup>
74
+ import { ref } from 'vue'
75
+ import BarChart from '@/components/barchart/index.vue'
76
+
77
+ const options = [
78
+ { label: 'Day', value: 'day' },
79
+ { label: 'Month', value: 'month' },
80
+ { label: 'Year', value: 'year' },
81
+ ]
82
+
83
+ const selectedTimeFrame = ref('day')
84
+
85
+ const handleSelectSplitButton = (value) => {
86
+ selectedTimeFrame.value = value
87
+ }
88
+
89
+ const monthlyData = [
90
+ { label: 'Jan', value: 300 },
91
+ { label: 'Feb', value: 600 },
92
+ { label: 'Mar', value: 1000 },
93
+ { label: 'Apr', value: 1200 },
94
+ { label: 'May', value: 1400 },
95
+ { label: 'Jun', value: 1810 },
96
+ { label: 'Jul', value: 1400 },
97
+ { label: 'Aug', value: 1200 },
98
+ { label: 'Sep', value: 1000 },
99
+ // { label: 'Oct', value: 800 },
100
+ // { label: 'Nov', value: 600 },
101
+ // { label: 'Dec', value: 400 },
102
+ // { label: 'Jan', value: 300 },
103
+ // { label: 'Feb', value: 600 },
104
+ // { label: 'Mar', value: 1000 },
105
+ // { label: 'Apr', value: 1200 },
106
+ // { label: 'May', value: 1400 },
107
+ // { label: 'Jun', value: 1810 },
108
+ // { label: 'Jul', value: 1400 },
109
+ // { label: 'Aug', value: 1200 },
110
+ // { label: 'Sep', value: 1000 },
111
+ // { label: 'Oct', value: 800 },
112
+ // { label: 'Nov', value: 600 },
113
+ // { label: 'Dec', value: 400 },
114
+
115
+ // ... more months
116
+ ]
117
+
118
+ const monthLabels = [
119
+ { label: 'Jan' },
120
+ { label: 'Feb' },
121
+ { label: 'Mar' },
122
+ { label: 'Apr' },
123
+ { label: 'May' },
124
+ { label: 'Jun' },
125
+ // ... more months
126
+ ]
127
+
128
+ const tariffZones = ref([
129
+ {
130
+ name: 'Tariff Zone 1',
131
+ data: [
132
+ { label: 'Jan', value: 200 },
133
+ { label: 'Feb', value: 130 },
134
+ { label: 'Mar', value: 220 },
135
+ { label: 'Apr', value: 230 },
136
+ { label: 'May', value: 200 },
137
+ { label: 'Jun', value: 210 },
138
+ // ... more months
139
+ ],
140
+ },
141
+ {
142
+ name: 'Tariff Zone 2',
143
+ data: [
144
+ { label: 'Jan', value: 200 },
145
+ { label: 'Feb', value: 100 },
146
+ { label: 'Mar', value: 270 },
147
+ { label: 'Apr', value: 180 },
148
+ { label: 'May', value: 300 },
149
+ { label: 'Jun', value: 250 },
150
+ // ... more months
151
+ ],
152
+ },
153
+ {
154
+ name: 'Tariff Zone 3',
155
+ data: [
156
+ { label: 'Jan', value: 200 },
157
+ { label: 'Feb', value: 100 },
158
+ { label: 'Mar', value: 210 },
159
+ { label: 'Apr', value: 220 },
160
+ { label: 'May', value: 300 },
161
+ { label: 'Jun', value: 190 },
162
+ // ... more months
163
+ ],
164
+ },
165
+ {
166
+ name: 'Tariff Zone 4',
167
+ data: [
168
+ { label: 'Jan', value: 200 },
169
+ { label: 'Feb', value: 100 },
170
+ { label: 'Mar', value: 210 },
171
+ { label: 'Apr', value: 220 },
172
+ { label: 'May', value: 300 },
173
+ { label: 'Jun', value: 190 },
174
+ // ... more months
175
+ ],
176
+ },
177
+ {
178
+ name: 'Tariff Zone 5',
179
+ data: [
180
+ { label: 'Jan', value: 200 },
181
+ { label: 'Feb', value: 100 },
182
+ { label: 'Mar', value: 210 },
183
+ { label: 'Apr', value: 220 },
184
+ { label: 'May', value: 300 },
185
+ { label: 'Jun', value: 190 },
186
+ // ... more months
187
+ ],
188
+ },
189
+ {
190
+ name: 'Tariff Zone 6',
191
+ data: [
192
+ { label: 'Jan', value: 200 },
193
+ { label: 'Feb', value: 100 },
194
+ { label: 'Mar', value: 210 },
195
+ { label: 'Apr', value: 220 },
196
+ { label: 'May', value: 300 },
197
+ { label: 'Jun', value: 190 },
198
+ // ... more months
199
+ ],
200
+ },
201
+ // ... more tariff zones
202
+ ])
203
+
204
+ const valueFormatter = (value) => {
205
+ return `${value} kWh`
206
+ }
207
+
208
+ const handleSelectionChange = (selectedBars) => {
209
+ console.log('selectedBars', selectedBars)
210
+ }
211
+
212
+ const handleInputBlur = (payload) => {
213
+ const newVal = [...tariffZones.value].map((zone) => {
214
+ if (zone.name === payload.seriesName) {
215
+ zone.data = zone.data.map((item) => {
216
+ if (item.label === payload.label) {
217
+ item.value = payload.value
218
+ }
219
+ return item
220
+ })
221
+ }
222
+ return zone
223
+ })
224
+
225
+ tariffZones.value = newVal
226
+ }
227
+ </script>
228
+
229
+ <style lang="scss" scoped></style>
@@ -1,14 +1,14 @@
1
1
  <template>
2
2
  <Container :is-chart-controls-shown-in-bottom="isChartControlsShownInBottom">
3
3
  <LabelsColumn :width="yAxisWidth">
4
- <LabelRow v-for="series in props.series" :key="series.name">
4
+ <LabelRow v-for="series in seriesData" :key="series.name">
5
5
  {{ series.name }}
6
6
  </LabelRow>
7
- <TotalRow v-if="props.series.length && fieldMode === 'percentage'">
8
- {{ $gettext ? $gettext('Total (%)') : 'Total (%)' }}
7
+ <TotalRow v-if="seriesData.length && fieldMode === 'percentage'">
8
+ {{ $gettext ? `${$gettext('Total')} (%)` : 'Total (%)' }}
9
9
  </TotalRow>
10
- <TotalRow v-if="props.series.length">
11
- {{ $gettext ? $gettext('Total (kWh)') : 'Total (kWh)' }}
10
+ <TotalRow v-if="seriesData.length">
11
+ {{ $gettext ? `${$gettext('Total')} (kWh)` : 'Total (kWh)' }}
12
12
  </TotalRow>
13
13
  </LabelsColumn>
14
14
 
@@ -18,27 +18,37 @@
18
18
  >
19
19
  <FieldsWrapper>
20
20
  <!-- For stacked bar chart -->
21
- <template v-if="props.series.length">
21
+ <template v-if="seriesData.length">
22
22
  <InputRow
23
- v-for="series in props.series"
23
+ v-for="series in seriesData"
24
24
  :key="series.name"
25
25
  :data-series-name="series.name"
26
26
  >
27
27
  <InputGroup
28
28
  v-for="(item, index) in props.data"
29
+ :key="index"
29
30
  :bar-width="barWidth"
30
31
  :is-scrollable="isScrollable"
31
- :key="index"
32
32
  >
33
33
  <InputNumber
34
34
  :allow-negative="false"
35
+ :disabled="isInputsDisabled"
36
+ :error-message="null"
35
37
  input-height="36px"
36
- :number-precision="0"
38
+ :is-border-error-only="true"
39
+ :is-error="
40
+ fieldMode === 'percentage'
41
+ ? calculatePercentageTotal(item.label) !== 100
42
+ : false
43
+ "
37
44
  :min-decimals="0"
45
+ :number-precision="fieldMode === 'percentage' ? 2 : 0"
38
46
  text-align="center"
39
47
  :unit-name="fieldMode === 'percentage' ? '%' : ''"
40
48
  :value="getDisplayValue(series.data, item.label)"
41
- @input-blur="handleInputBlur($event, series.name, item.label)"
49
+ @input-blur="
50
+ handleInputBlur($event, series.name, item.label, series.data)
51
+ "
42
52
  @input-focus="handleInputFocus(series.name, item.label)"
43
53
  />
44
54
  </InputGroup>
@@ -47,16 +57,17 @@
47
57
  <TotalInputRow v-if="fieldMode === 'percentage'">
48
58
  <InputGroup
49
59
  v-for="(item, index) in props.data"
60
+ :key="index"
50
61
  :bar-width="barWidth"
51
62
  :is-scrollable="isScrollable"
52
- :key="index"
53
63
  >
54
64
  <InputNumber
55
65
  :allow-negative="false"
66
+ :disabled="isInputsDisabled"
56
67
  input-height="36px"
57
68
  :is-read-only="true"
58
- :number-precision="0"
59
69
  :min-decimals="0"
70
+ :number-precision="fieldMode === 'percentage' ? 2 : 0"
60
71
  text-align="center"
61
72
  :unit-name="fieldMode === 'percentage' ? '%' : ''"
62
73
  :value="calculatePercentageTotal(item.label)"
@@ -67,17 +78,24 @@
67
78
  <TotalInputRow>
68
79
  <InputGroup
69
80
  v-for="(item, index) in props.data"
81
+ :key="index"
70
82
  :bar-width="barWidth"
71
83
  :is-scrollable="isScrollable"
72
- :key="index"
73
84
  >
74
85
  <InputNumber
86
+ :error-message="$gettext('load_profile_not_add_up_to_100')"
75
87
  input-height="36px"
88
+ :is-border-error-only="true"
89
+ :is-error="
90
+ fieldMode === 'percentage'
91
+ ? calculatePercentageTotal(item.label) !== 100
92
+ : false
93
+ "
76
94
  :is-read-only="true"
77
- :number-precision="2"
78
95
  :min-decimals="0"
96
+ :number-precision="2"
79
97
  text-align="center"
80
- :value="calculateTotal(item.label)"
98
+ :value="calculateTotalValue(item.label)"
81
99
  />
82
100
  </InputGroup>
83
101
  </TotalInputRow>
@@ -88,17 +106,19 @@
88
106
  <InputRow>
89
107
  <InputGroup
90
108
  v-for="(item, index) in props.data"
109
+ :key="index"
91
110
  :bar-width="barWidth"
92
111
  :is-scrollable="isScrollable"
93
- :key="index"
94
112
  >
95
113
  <InputNumber
114
+ :allow-negative="false"
115
+ :disabled="isInputsDisabled"
96
116
  input-height="36px"
97
117
  :min-decimals="0"
98
118
  :number-precision="2"
99
119
  text-align="center"
100
120
  :value="item.value"
101
- @input-blur="handleInputBlur($event, null, item.label)"
121
+ @input-blur="handleInputBlur($event, null, item.label, null)"
102
122
  @input-focus="handleInputFocus(null, item.label)"
103
123
  />
104
124
  </InputGroup>
@@ -110,7 +130,8 @@
110
130
  </template>
111
131
 
112
132
  <script setup>
113
- import { ref } from 'vue'
133
+ import { ref, watch, watchEffect, onMounted } from 'vue'
134
+ import styled from 'vue3-styled-components'
114
135
  import InputNumber from '../inputs/inputNumber'
115
136
 
116
137
  import {
@@ -159,6 +180,61 @@
159
180
  default: 'absolute',
160
181
  validator: (value) => ['absolute', 'percentage'].includes(value),
161
182
  },
183
+ isInputsDisabled: {
184
+ type: Boolean,
185
+ default: false,
186
+ },
187
+ })
188
+
189
+ const seriesData = ref([])
190
+
191
+ // onMounted(() => {
192
+ // seriesData.value = props.series.map((item) => {
193
+ // const data = item.data.map((d) => ({
194
+ // label: d.label,
195
+ // value: d.value,
196
+ // originalValue: d.value,
197
+ // }))
198
+
199
+ // return {
200
+ // name: item.name,
201
+ // data,
202
+ // }
203
+ // })
204
+ // })
205
+
206
+ watchEffect(() => {
207
+ let isNewSetOfSeries = false
208
+ const seriesDataCopy = [...seriesData.value]
209
+ if (
210
+ !seriesDataCopy.length ||
211
+ !props.series.length ||
212
+ seriesDataCopy.length !== props.series.length ||
213
+ !seriesDataCopy.some((item) => {
214
+ return props.series.map((s) => s.name).includes(item.name)
215
+ })
216
+ ) {
217
+ isNewSetOfSeries = true
218
+ }
219
+ const currentSeriesData = !isNewSetOfSeries ? seriesDataCopy : []
220
+ const newSeriesData = []
221
+
222
+ props.series.forEach((item, itemIndex) => {
223
+ const data = item.data.map((d, dIndex) => ({
224
+ label: d.label,
225
+ value: d.value,
226
+ originalValue: currentSeriesData.length
227
+ ? currentSeriesData[itemIndex].data[dIndex].originalValue
228
+ : d.value,
229
+ }))
230
+
231
+ newSeriesData.push({
232
+ name: item.name,
233
+ data,
234
+ })
235
+ })
236
+
237
+ seriesData.value = [...newSeriesData]
162
238
  })
163
239
 
164
240
  const emit = defineEmits([
@@ -175,11 +251,13 @@
175
251
  emit('input-focus', { seriesName, label })
176
252
  }
177
253
 
178
- const calculateTotal = (label) => {
179
- return props.series.reduce((sum, series) => {
254
+ const calculateTotalValue = (label) => {
255
+ const total = seriesData.value.reduce((sum, series) => {
180
256
  const value = series.data.find((d) => d.label === label)?.value || 0
181
257
  return sum + value
182
258
  }, 0)
259
+
260
+ return Math.round(total)
183
261
  }
184
262
 
185
263
  const syncScroll = (scrollLeft) => {
@@ -190,34 +268,74 @@
190
268
  container.scrollLeft = scrollLeft
191
269
  }
192
270
  }
193
- const getDisplayValue = (seriesData, label) => {
271
+
272
+ const calculateTotalOriginalValue = (label) => {
273
+ return seriesData.value.reduce((sum, series) => {
274
+ const value =
275
+ series.data.find((d) => d.label === label)?.originalValue || 0
276
+ return sum + value
277
+ }, 0)
278
+ }
279
+
280
+ const getDisplayValue = (data, label, shouldRound = true) => {
194
281
  if (props.fieldMode === 'absolute') {
195
- return seriesData.find((d) => d.label === label)?.value || ''
282
+ return data.find((d) => d.label === label)?.value || ''
196
283
  }
197
284
 
198
- const value = seriesData.find((d) => d.label === label)?.value || 0
199
- const total = calculateTotal(label)
200
- return total ? Number(((value / total) * 100).toFixed(0)) : 0
285
+ const value = data.find((d) => d.label === label)?.value || 0
286
+
287
+ const total = seriesData.value.reduce((sum, series) => {
288
+ const value =
289
+ series.data.find((d) => d.label === label)?.originalValue || 0
290
+ return sum + value
291
+ }, 0)
292
+
293
+ return shouldRound ? (value / total) * 100 : (value / total) * 100
201
294
  }
202
295
 
203
296
  const calculatePercentageTotal = (label) => {
204
- return props.series.reduce((sum, series) => {
297
+ const originalTotal = seriesData.value.reduce((sum, series) => {
298
+ const originalValue =
299
+ series.data.find((d) => d.label === label)?.originalValue || 0
300
+ return sum + originalValue
301
+ }, 0)
302
+
303
+ const totalPercentage = seriesData.value.reduce((sum, series) => {
205
304
  const value = series.data.find((d) => d.label === label)?.value || 0
206
- const total = calculateTotal(label)
207
- const percentage = total ? Number(((value / total) * 100).toFixed(0)) : 0
305
+ const percentage = originalTotal
306
+ ? Number((value / originalTotal) * 100)
307
+ : 0
208
308
  return sum + percentage
209
309
  }, 0)
310
+
311
+ return Math.round(totalPercentage)
210
312
  }
211
313
 
212
- const handleInputBlur = (_value, seriesName, label) => {
314
+ const handleInputBlur = (_value, seriesName, label, currentSeriesData) => {
213
315
  let value = Number(_value)
214
316
 
215
317
  if (props.fieldMode === 'percentage') {
216
- const total = calculateTotal(label)
318
+ const total = seriesData.value.reduce((sum, series) => {
319
+ const value =
320
+ series.data.find((d) => d.label === label)?.originalValue || 0
321
+ return sum + value
322
+ }, 0)
323
+
217
324
  value = (value / 100) * total
218
325
  }
219
326
 
220
- const payload = seriesName ? { seriesName, label, value } : { label, value }
327
+ const payload = seriesName
328
+ ? {
329
+ seriesName,
330
+ label,
331
+ value,
332
+ inputValue: _value,
333
+ percentage: Number(
334
+ getDisplayValue(currentSeriesData, label, false).toFixed(2)
335
+ ),
336
+ totalSeriesValue: calculateTotalOriginalValue(label),
337
+ }
338
+ : { label, value }
221
339
  emit('input-blur', payload)
222
340
  focusedInput.value = null
223
341
 
@@ -247,6 +365,11 @@
247
365
  emit('sync-scroll', event.target.scrollLeft)
248
366
  }
249
367
 
368
+ const toFixedNoRounding = (number, decimals) => {
369
+ const factor = Math.pow(10, decimals)
370
+ return Math.floor(number * factor) / factor
371
+ }
372
+
250
373
  defineExpose({
251
374
  syncScroll,
252
375
  })
@@ -84,7 +84,7 @@ export function useAxisCalculations(props, maxValue) {
84
84
  })
85
85
 
86
86
  const yAxisWidth = computed(() => {
87
- return !!props.yAxisTitle || props.isBottomFieldsShown ? '70px' : '60px'
87
+ return !!props.yAxisTitle || props.isBottomFieldsShown ? '80px' : '60px'
88
88
  })
89
89
 
90
90
  const isChartControlsShown = (position) => {
@@ -66,7 +66,7 @@ export function useChartData(props, paddedMaxValue) {
66
66
  let accumulated = 0
67
67
  return {
68
68
  label: item.label,
69
- segments: [...props.series].reverse().map((series, index) => {
69
+ segments: [...props.series].map((series, index) => {
70
70
  const value =
71
71
  series.data.find((d) => d.label === item.label)?.value || 0
72
72
  accumulated += value
@@ -16,7 +16,21 @@ export function useTooltip(chartId, normalizedData) {
16
16
  if (!showTooltipContent.value) {
17
17
  showTooltipContent.value = true
18
18
  }
19
- if (isObjectEqual(item, tooltipData.value)) return
19
+ if (isObjectEqual(item, tooltipData.value)) {
20
+ return
21
+ }
22
+
23
+ const totalValue = item.segments.reduce((acc, segment) => {
24
+ return acc + segment.value
25
+ }, 0)
26
+
27
+ const segments = item.segments.map((segment) => {
28
+ let valuePercentage = (segment.value / totalValue) * 100
29
+ segment.valuePercentage = Math.round(valuePercentage)
30
+
31
+ return segment
32
+ })
33
+ item.segments = segments
20
34
 
21
35
  tooltipData.value = { ...item }
22
36
 
@@ -41,16 +55,27 @@ export function useTooltip(chartId, normalizedData) {
41
55
 
42
56
  isInputFocused.value = true
43
57
  const barData = normalizedData.value.find((item) => item.label === label)
44
-
45
58
  if (!barData) return
59
+
60
+ const totalValue = barData.segments.reduce((acc, segment) => {
61
+ return acc + segment.value
62
+ }, 0)
63
+ const segments = barData.segments.map((segment) => {
64
+ let valuePercentage = (segment.value / totalValue) * 100
65
+ segment.valuePercentage = Math.round(valuePercentage)
66
+
67
+ return segment
68
+ })
69
+ barData.segments = segments
46
70
  focusedBarData.value = barData
71
+
47
72
  const barElement = document.querySelector(
48
73
  `.barchart-${chartId} .bar-group:nth-child(${
49
74
  normalizedData.value.indexOf(barData) + 1
50
75
  })`
51
76
  )
52
-
53
77
  if (!barElement) return
78
+
54
79
  // Get the last bar segment, samee as hover behavior
55
80
  const targetElement = barElement.querySelector('.bar-segment:last-child')
56
81
  const rect = targetElement.getBoundingClientRect()
@@ -17,7 +17,7 @@
17
17
  />
18
18
  </ChartControlsWrapper>
19
19
  <GraphSection :height="height" :width="width">
20
- <YAxis :width="yAxisWidth" :height="height">
20
+ <YAxis :height="height" :width="yAxisWidth">
21
21
  <YAxisTitleWrapper v-if="yAxisTitle" :height="yAxisHeight">
22
22
  {{ yAxisTitle }}
23
23
  </YAxisTitleWrapper>
@@ -30,15 +30,15 @@
30
30
  )
31
31
  "
32
32
  >
33
- <YAxisLabel>{{ label }}</YAxisLabel>
33
+ <YAxisLabel>{{ getYAxisLabel(label) }}</YAxisLabel>
34
34
  <YAxisLine :y-axis-width="yAxisWidth" />
35
35
  </YAxisRow>
36
36
  </YAxis>
37
37
 
38
38
  <ScrollContainer
39
39
  :class="`chart-scroll-container-${chartId}`"
40
- :is-scrollable="isScrollable"
41
40
  :height="height"
41
+ :is-scrollable="isScrollable"
42
42
  @scroll="handleChartScroll"
43
43
  >
44
44
  <ChartContent
@@ -64,19 +64,19 @@
64
64
  <BarsContainer>
65
65
  <BarGroup
66
66
  v-for="(item, index) in normalizedData"
67
+ :key="index"
67
68
  :bar-width="barWidth"
68
69
  class="bar-group"
69
70
  :is-scrollable="isScrollable"
70
- :key="index"
71
71
  >
72
72
  <BarWrapper>
73
73
  <BarSegment
74
74
  v-for="(segment, segIndex) in item.segments"
75
+ :key="segIndex"
75
76
  class="bar-segment"
76
77
  :gradient-from="getSegmentGradient(index, segment).from"
77
78
  :gradient-to="getSegmentGradient(index, segment).to"
78
79
  :height="`${segment.percentage}%`"
79
- :key="segIndex"
80
80
  :z-index="item.segments.length - segIndex"
81
81
  @mouseenter="showTooltip(item, $event, series)"
82
82
  @mouseleave="hideTooltip"
@@ -96,7 +96,7 @@
96
96
  :left="tooltipStyle.left"
97
97
  :top="tooltipStyle.top"
98
98
  >
99
- <slot :item="tooltipData" name="tooltip" />
99
+ <slot :item="tooltipData" name="tooltip"></slot>
100
100
  <TooltipTextWrapper v-if="!slots.tooltip && tooltipData">
101
101
  <template v-if="!series.length">
102
102
  <TooltipText font-weight="500">{{ tooltipData.label }}</TooltipText>
@@ -128,7 +128,11 @@
128
128
  :gradient-to="segment.gradientTo"
129
129
  />
130
130
  <TooltipText>
131
- {{ handleValueFormatter(segment.value) }}
131
+ {{
132
+ fieldMode === 'absolute' && showPercentageOnTooltip
133
+ ? `${segment.valuePercentage}%`
134
+ : handleValueFormatter(segment.value)
135
+ }}
132
136
  </TooltipText>
133
137
  </TooltipRow>
134
138
  </template>
@@ -159,6 +163,7 @@
159
163
  :data="data"
160
164
  :field-mode="fieldMode"
161
165
  :is-chart-controls-shown-in-bottom="isChartControlsShown('bottom')"
166
+ :is-inputs-disabled="isLoading"
162
167
  :is-scrollable="isScrollable"
163
168
  :series="series"
164
169
  :y-axis-width="yAxisWidth"
@@ -171,12 +176,13 @@
171
176
  </template>
172
177
 
173
178
  <script setup>
174
- import { useSlots, computed } from 'vue'
179
+ import { useSlots, computed, ref } from 'vue'
175
180
 
176
181
  import ChartControls from './ChartControls'
177
182
  import BottomFields from './BottomFields'
178
183
  import SelectionBox from './SelectionBox'
179
184
  import Spinner from '../spinner'
185
+ import { numberToString } from '../../helpers/numberConverter'
180
186
 
181
187
  import {
182
188
  useTooltip,
@@ -296,6 +302,10 @@
296
302
  type: Boolean,
297
303
  default: false,
298
304
  },
305
+ showPercentageOnTooltip: {
306
+ type: Boolean,
307
+ default: false,
308
+ },
299
309
  })
300
310
 
301
311
  const generateChartId = () =>
@@ -378,8 +388,14 @@
378
388
  }
379
389
 
380
390
  const handleValueFormatter = (value) => {
381
- return props.valueFormatter
382
- ? props.valueFormatter(Math.round(value))
383
- : value
391
+ return props.valueFormatter ? props.valueFormatter(value) : value
392
+ }
393
+
394
+ const getYAxisLabel = (label) => {
395
+ return numberToString({
396
+ value: label,
397
+ numberPrecision: 0,
398
+ minDecimals: 0,
399
+ })
384
400
  }
385
401
  </script>
@@ -17,18 +17,18 @@ export const LabelsColumn = styled('div', { width: String })`
17
17
 
18
18
  export const LabelRow = styled.div`
19
19
  height: 32px;
20
+ padding-top: 5px;
20
21
  font-size: 12px;
21
22
  font-weight: 500;
22
23
  color: ${(props) => props.theme.semanticColors.teal[600]};
23
24
  display: flex;
24
- align-items: flex-start;
25
+ align-items: center;
25
26
  `
26
27
 
27
28
  export const TotalRow = styled(LabelRow)``
28
29
 
29
30
  export const FieldsContainer = styled.div`
30
31
  flex: 1;
31
- overflow-x: auto;
32
32
  scrollbar-width: none;
33
33
 
34
34
  &::-webkit-scrollbar {
@@ -63,4 +63,9 @@ export const InputGroup = styled('div', {
63
63
  props.barWidth}px;
64
64
  display: flex;
65
65
  justify-content: center;
66
+ position: relative;
67
+
68
+ input[readonly] {
69
+ border: 1px solid ${(props) => props.theme.colors.grey4} !important;
70
+ }
66
71
  `
@@ -127,6 +127,7 @@ export const BarWrapper = styled.div`
127
127
  height: 100%;
128
128
  width: 100%;
129
129
  position: relative;
130
+ overflow: hidden;
130
131
  `
131
132
 
132
133
  export const BarSegment = styled('div', {
@@ -19,7 +19,7 @@
19
19
  background: ${(props) => props.theme.colors.red};
20
20
  padding: 10px;
21
21
  width: max-content;
22
- max-width: 100%;
22
+ /* max-width: 100%; */
23
23
  min-width: min-content;
24
24
  font-size: 11px;
25
25
  font-weight: 400;
@@ -123,11 +123,7 @@
123
123
  return this.type === 'error_minor'
124
124
  },
125
125
  iconName() {
126
- return this.type === 'warning'
127
- ? 'warning_triangle'
128
- : this.isErrorMinor
129
- ? 'erase'
130
- : 'info'
126
+ return this.type === 'warning' ? 'warning_triangle' : 'info'
131
127
  },
132
128
  presetStyles() {
133
129
  // the types that doesn't have explicit border anyway have it transparent
@@ -146,8 +142,8 @@
146
142
  stylesCollection.iconColor = theme.semanticColors.teal[800]
147
143
  } else if (this.isErrorMinor) {
148
144
  stylesCollection.borderStyle = 'dashed'
149
- stylesCollection.borderColor = theme.colors.grey4
150
- stylesCollection.iconColor = theme.colors.red
145
+ stylesCollection.borderColor = theme.colors.pureRed
146
+ stylesCollection.iconColor = theme.colors.pureRed
151
147
  } else {
152
148
  stylesCollection.borderStyle = 'dashed'
153
149
  stylesCollection.borderColor = theme.colors.grey4
@@ -50,6 +50,7 @@
50
50
  :has-slot="hasSlot"
51
51
  :has-unit="unitName && !!unitName.length"
52
52
  :input-height="inputHeight"
53
+ :is-border-error-only="isBorderErrorOnly"
53
54
  :is-disabled="disabled"
54
55
  :is-error="isError"
55
56
  :is-interactive="isInteractive"
@@ -57,6 +58,7 @@
57
58
  :no-border="noBorder"
58
59
  :placeholder="displayedPlaceholder"
59
60
  :read-only="isReadOnly"
61
+ :readonly="isReadOnly"
60
62
  :show-arrow-controls="showArrowControls"
61
63
  :show-linear-unit-name="showLinearUnitName"
62
64
  :slot-size="slotSize"
@@ -80,7 +82,7 @@
80
82
  >{{ unitName }}</UnitContainer
81
83
  >
82
84
  <IconWrapper
83
- v-if="isError && !showLinearUnitName"
85
+ v-if="isError && !showLinearUnitName && !isBorderErrorOnly"
84
86
  :margin-right="showSelect ? selectWidth : 0"
85
87
  size="16px"
86
88
  >
@@ -134,7 +136,9 @@
134
136
  </ArrowButton>
135
137
  </ArrowControls>
136
138
  </InputWrapper>
137
- <ErrorMessage v-if="isError">{{ errorMessage }}</ErrorMessage>
139
+ <ErrorMessage v-if="isError && errorMessage">{{
140
+ errorMessage
141
+ }}</ErrorMessage>
138
142
  </Container>
139
143
  </template>
140
144
 
@@ -205,6 +209,7 @@
205
209
  colorMode: String,
206
210
  showArrowControls: Boolean,
207
211
  readOnly: Boolean,
212
+ isBorderErrorOnly: Boolean,
208
213
  }
209
214
 
210
215
  const Container = styled('div', inputProps)`
@@ -236,16 +241,17 @@
236
241
  showLinearUnitName,
237
242
  colorMode,
238
243
  showArrowControls,
244
+ isBorderErrorOnly,
239
245
  }) =>
240
246
  showArrowControls
241
247
  ? '40px'
242
248
  : colorMode === 'transparent'
243
249
  ? '0'
244
250
  : slotSize
245
- ? isError && !showLinearUnitName
251
+ ? isError && !showLinearUnitName && !isBorderErrorOnly
246
252
  ? 'calc(' + slotSize + ' + 24px)'
247
253
  : 'calc(' + slotSize + ' + 10px)'
248
- : isError && !showLinearUnitName
254
+ : isError && !showLinearUnitName && !isBorderErrorOnly
249
255
  ? '24px'
250
256
  : '5px'};
251
257
  border-radius: ${(props) =>
@@ -698,6 +704,10 @@
698
704
  type: Boolean,
699
705
  default: false,
700
706
  },
707
+ isBorderErrorOnly: {
708
+ type: Boolean,
709
+ default: false,
710
+ },
701
711
  },
702
712
  data() {
703
713
  return {
@@ -1,8 +1,8 @@
1
1
  <template>
2
2
  <TitleWrap data-test-id="page_wrapper" :has-info-text="!!infoText">
3
3
  <TitleText
4
- data-test-id="page_title_text"
5
4
  :color="color"
5
+ data-test-id="page_title_text"
6
6
  :font-size="fontSize"
7
7
  :uppercase="uppercase"
8
8
  >
@@ -10,8 +10,8 @@
10
10
  </TitleText>
11
11
  <InfoText
12
12
  v-if="!!infoText"
13
- data-test-id="page_title_tooltip"
14
13
  :align-arrow="infoAlign"
14
+ data-test-id="page_title_tooltip"
15
15
  :text="infoText"
16
16
  />
17
17
  </TitleWrap>
@@ -44,9 +44,8 @@
44
44
  const titleAttrs = { color: String, fontSize: String, uppercase: Boolean }
45
45
  const TitleText = styled('span', titleAttrs)`
46
46
  color: ${(props) => (props.color ? props.color : props.theme.colors.black)};
47
- font-weight: bold;
47
+ font-weight: 500;
48
48
  font-size: ${(props) => (props.fontSize ? props.fontSize : '20px')};
49
- text-transform: ${(props) => (props.uppercase ? 'uppercase' : 'none')};
50
49
  `
51
50
 
52
51
  export default {