@centreon/ui 25.10.29 → 25.10.30

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 (69) hide show
  1. package/package.json +3 -3
  2. package/public/mockServiceWorker.js +8 -31
  3. package/src/Dashboard/Item.tsx +142 -149
  4. package/src/Form/Inputs/ConnectedAutocomplete.tsx +2 -0
  5. package/src/Form/Inputs/Grid.tsx +2 -3
  6. package/src/Form/Inputs/models.ts +2 -0
  7. package/src/Form/Section/navigateToSection.ts +6 -6
  8. package/src/Graph/BarChart/BarChart.cypress.spec.tsx +55 -102
  9. package/src/Graph/BarChart/BarChart.stories.tsx +1 -51
  10. package/src/Graph/BarChart/BarChart.tsx +1 -1
  11. package/src/Graph/BarChart/BarGroup.tsx +32 -22
  12. package/src/Graph/BarChart/BarStack.tsx +26 -15
  13. package/src/Graph/BarChart/MemoizedGroup.tsx +18 -14
  14. package/src/Graph/BarChart/ResponsiveBarChart.tsx +6 -7
  15. package/src/Graph/BarChart/Tooltip/BarChartTooltip.tsx +2 -2
  16. package/src/Graph/Chart/BasicComponents/Lines/StackedLines/index.tsx +5 -4
  17. package/src/Graph/Chart/BasicComponents/Lines/StackedLines/useStackedLines.ts +45 -18
  18. package/src/Graph/Chart/BasicComponents/Lines/index.tsx +118 -124
  19. package/src/Graph/Chart/Chart.cypress.spec.tsx +6 -25
  20. package/src/Graph/Chart/Chart.stories.tsx +1 -43
  21. package/src/Graph/Chart/Chart.tsx +13 -9
  22. package/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltip.ts +4 -2
  23. package/src/Graph/Chart/Legend/index.tsx +2 -26
  24. package/src/Graph/Chart/index.tsx +45 -31
  25. package/src/Graph/Chart/models.ts +1 -6
  26. package/src/Graph/Chart/translatedLabels.ts +1 -0
  27. package/src/Graph/Chart/useChartData.ts +24 -3
  28. package/src/Graph/common/Axes/index.tsx +1 -1
  29. package/src/Graph/common/BaseChart/BaseChart.tsx +1 -6
  30. package/src/Graph/common/BaseChart/ChartSvgWrapper.tsx +23 -16
  31. package/src/Graph/common/Error/NoData.tsx +18 -0
  32. package/src/Graph/common/Grids/index.tsx +4 -4
  33. package/src/Graph/common/timeSeries/index.test.ts +4 -24
  34. package/src/Graph/common/timeSeries/index.ts +120 -184
  35. package/src/Graph/common/timeSeries/models.ts +1 -1
  36. package/src/Graph/common/utils.ts +4 -10
  37. package/src/Graph/index.ts +20 -20
  38. package/src/InputField/Select/Autocomplete/Connected/index.tsx +3 -3
  39. package/src/InputField/Select/Autocomplete/Multi/Listbox.tsx +11 -3
  40. package/src/InputField/Select/Autocomplete/Multi/Multi.tsx +3 -2
  41. package/src/InputField/Select/index.tsx +2 -1
  42. package/src/Listing/ActionBar/Pagination.tsx +2 -1
  43. package/src/Listing/ActionBar/index.tsx +113 -8
  44. package/src/Listing/index.tsx +19 -2
  45. package/src/Listing/translatedLabels.ts +4 -0
  46. package/src/Module/index.tsx +2 -8
  47. package/src/ThemeProvider/index.tsx +21 -30
  48. package/src/ThemeProvider/tailwindcss.css +12 -10
  49. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +8 -5
  50. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/models.ts +0 -1
  51. package/src/api/useGraphQuery/index.ts +7 -4
  52. package/src/components/Layout/PageLayout/PageLayout.tsx +3 -9
  53. package/src/components/Layout/PageLayout/PageLayoutActions.tsx +3 -5
  54. package/src/components/Layout/PageLayout/PageLayoutBody.tsx +3 -5
  55. package/src/components/Layout/PageLayout/PageLayoutHeader.tsx +3 -5
  56. package/src/components/Layout/PageLayout/PageQuickAccess.tsx +44 -25
  57. package/src/components/Layout/PageLayout/translatedLabels.ts +1 -0
  58. package/src/components/Menu/Button/MenuButton.styles.ts +27 -0
  59. package/src/components/Menu/Button/MenuButton.tsx +5 -6
  60. package/src/components/Menu/Menu.styles.ts +68 -0
  61. package/src/components/Menu/MenuDivider.tsx +5 -1
  62. package/src/components/Menu/MenuItem.tsx +5 -1
  63. package/src/components/Menu/MenuItems.tsx +4 -5
  64. package/src/components/Modal/Modal.styles.ts +2 -1
  65. package/src/components/Modal/ModalHeader.tsx +1 -5
  66. package/src/utils/useInfiniteScrollListing.ts +11 -7
  67. package/src/utils/useViewportIntersection.ts +3 -4
  68. package/src/Graph/mockedData/dataWithMissingPoint.json +0 -74
  69. package/src/Graph/mockedData/pingServiceWithStackedKeys.json +0 -205
@@ -5,10 +5,7 @@ import { LineChartData } from '../common/models';
5
5
  import dataPingService from '../mockedData/pingService.json';
6
6
  import dataPingServiceMixedStacked from '../mockedData/pingServiceMixedStacked.json';
7
7
  import dataPingServiceStacked from '../mockedData/pingServiceStacked.json';
8
- import dataPingServiceStackeKey from '../mockedData/pingServiceWithStackedKeys.json';
9
8
 
10
- import { ClickAwayListener } from '@mui/material';
11
- import { useState } from 'react';
12
9
  import BarChart from './BarChart';
13
10
 
14
11
  const meta: Meta<typeof BarChart> = {
@@ -262,51 +259,4 @@ export const mixedStackedMinMax: Story = {
262
259
  max: 20
263
260
  },
264
261
  render: Template
265
- };
266
-
267
- const LegendSecondaryClick = (args) => {
268
- const [position, setPosition] = useState<Array<[number, number]> | null>(
269
- null
270
- );
271
-
272
- return (
273
- <>
274
- <Template
275
- {...args}
276
- legend={{
277
- secondaryClick: ({ position }) => setPosition(position)
278
- }}
279
- />
280
- {position && (
281
- <ClickAwayListener onClickAway={() => setPosition(null)}>
282
- <div
283
- className="absolute py-1 px-2 rounded-sm bg-background-widget shadow-md"
284
- style={{ left: position?.[0], top: position?.[1] }}
285
- open={Boolean(position)}
286
- onClose={() => setPosition(null)}
287
- >
288
- menu
289
- </div>
290
- </ClickAwayListener>
291
- )}
292
- </>
293
- );
294
- };
295
-
296
- export const withLegendSecondaryClick: Story = {
297
- args: defaultArgs,
298
- render: (args) => (
299
- <LegendSecondaryClick
300
- {...args}
301
- data={dataPingService as unknown as LineChartData}
302
- />
303
- )
304
- };
305
-
306
- export const stackKey: Story = {
307
- args: {
308
- ...defaultArgs,
309
- data: dataPingServiceStackeKey
310
- },
311
- render: Template
312
- };
262
+ };
@@ -116,4 +116,4 @@ const BarChart = ({
116
116
  );
117
117
  };
118
118
 
119
- export default BarChart;
119
+ export default BarChart;
@@ -1,13 +1,12 @@
1
1
  import { scaleBand, scaleOrdinal } from '@visx/scale';
2
2
  import { BarGroupHorizontal, BarGroup as VisxBarGroup } from '@visx/shape';
3
3
  import { ScaleLinear } from 'd3-scale';
4
- import { difference, equals, keys, omit, pick } from 'ramda';
4
+ import { difference, equals, keys, omit, pick, pluck, uniq } from 'ramda';
5
5
  import { memo, useMemo } from 'react';
6
6
 
7
7
  import { useDeepMemo } from '../../utils';
8
8
  import {
9
9
  getSortedStackedLines,
10
- getStackedLinesTimeSeriesPerStackAndUnit,
11
10
  getTime,
12
11
  getTimeSeriesForLines,
13
12
  getUnits
@@ -55,18 +54,41 @@ const BarGroup = ({
55
54
  );
56
55
 
57
56
  const stackedLines = getSortedStackedLines(lines);
57
+ const stackedUnits = uniq(pluck('unit', stackedLines));
58
58
  const notStackedLines = difference(lines, stackedLines);
59
+
60
+ const stackedKeys = stackedUnits.reduce(
61
+ (acc, unit) => ({
62
+ ...acc,
63
+ [`stacked-${unit}`]: null
64
+ }),
65
+ {}
66
+ );
67
+ const stackedLinesTimeSeriesPerUnit = stackedUnits.reduce(
68
+ (acc, stackedUnit) => {
69
+ const relatedLines = stackedLines.filter(({ unit }) =>
70
+ equals(unit, stackedUnit)
71
+ );
72
+
73
+ return {
74
+ ...acc,
75
+ [stackedUnit]: {
76
+ lines: relatedLines,
77
+ timeSeries: getTimeSeriesForLines({
78
+ lines: relatedLines,
79
+ timeSeries
80
+ })
81
+ }
82
+ };
83
+ },
84
+ {}
85
+ );
86
+
59
87
  const notStackedTimeSeries = getTimeSeriesForLines({
60
88
  lines: notStackedLines,
61
89
  timeSeries
62
90
  });
63
91
 
64
- const { stackedLinesTimeSeriesPerStackKeyAndUnit, stackedKeys } = useMemo(
65
- () =>
66
- getStackedLinesTimeSeriesPerStackAndUnit({ stackedLines, timeSeries }),
67
- [stackedLines, timeSeries]
68
- );
69
-
70
92
  const normalizedTimeSeries = notStackedTimeSeries.map((timeSerie) => ({
71
93
  ...timeSerie,
72
94
  ...stackedKeys
@@ -76,16 +98,6 @@ const BarGroup = ({
76
98
  deps: [normalizedTimeSeries],
77
99
  variable: keys(omit(['timeTick'], normalizedTimeSeries[0]))
78
100
  });
79
- const sortedLineKeys = lineKeys.sort((lineKeyA: string, lineKeyB: string) => {
80
- if (lineKeyA.startsWith('stacked-') && !lineKeyB.startsWith('stacked-')) {
81
- return true;
82
- }
83
-
84
- const lineKeysA = lineKeyA.split('-');
85
- const lineKeysB = lineKeyB.split('-');
86
-
87
- return lineKeysA[2] === '' && lineKeysB[2] !== '';
88
- });
89
101
  const colors = useDeepMemo({
90
102
  deps: [lineKeys, lines],
91
103
  variable: lineKeys.map((key) => {
@@ -142,7 +154,7 @@ const BarGroup = ({
142
154
  color={colorScale}
143
155
  data={normalizedTimeSeries}
144
156
  height={size}
145
- keys={sortedLineKeys}
157
+ keys={lineKeys}
146
158
  {...barComponentBaseProps}
147
159
  >
148
160
  {(barGroups) =>
@@ -152,9 +164,7 @@ const BarGroup = ({
152
164
  key={`bar-group-${barGroup.index}-${barGroup.x0}`}
153
165
  barGroup={barGroup}
154
166
  barStyle={barStyle}
155
- stackedLinesTimeSeriesPerStackKeyAndUnit={
156
- stackedLinesTimeSeriesPerStackKeyAndUnit
157
- }
167
+ stackedLinesTimeSeriesPerUnit={stackedLinesTimeSeriesPerUnit}
158
168
  notStackedTimeSeries={notStackedTimeSeries}
159
169
  notStackedLines={notStackedLines}
160
170
  isTooltipHidden={isTooltipHidden}
@@ -1,4 +1,4 @@
1
- import { memo } from 'react';
1
+ import { memo, ReactElement } from 'react';
2
2
 
3
3
  import { ScaleType, scaleBand } from '@visx/scale';
4
4
  import { BarRounded } from '@visx/shape';
@@ -22,6 +22,7 @@ interface Props extends Omit<UseBarStackProps, 'xScale'> {
22
22
  barWidth: number;
23
23
  isTooltipHidden: boolean;
24
24
  neutralValue: number;
25
+ isStacked?: boolean;
25
26
  }
26
27
 
27
28
  const getPadding = ({ padding, size, isNegativeValue }): number => {
@@ -83,8 +84,9 @@ const BarStack = ({
83
84
  barIndex,
84
85
  isTooltipHidden,
85
86
  barStyle = { opacity: 1, radius: 0.2 },
86
- neutralValue
87
- }: Props): JSX.Element => {
87
+ neutralValue,
88
+ isStacked
89
+ }: Props): ReactElement => {
88
90
  const {
89
91
  BarStackComponent,
90
92
  commonBarStackProps,
@@ -118,6 +120,15 @@ const BarStack = ({
118
120
  metricId: Number(bar.key)
119
121
  }) as BarStyle;
120
122
 
123
+ const barY =
124
+ isNegativeValue && isStacked && !shouldApplyRadiusOnBottom
125
+ ? getPadding({
126
+ isNegativeValue,
127
+ padding: bar.y,
128
+ size: bar.height
129
+ })
130
+ : bar.y;
131
+
121
132
  return (
122
133
  <BarRounded
123
134
  {...barRoundedProps}
@@ -128,10 +139,10 @@ const BarStack = ({
128
139
  barWidth,
129
140
  y: isHorizontal
130
141
  ? getPadding({
131
- isNegativeValue,
132
- padding: bar.y,
133
- size: bar.height
134
- })
142
+ isNegativeValue,
143
+ padding: bar.y,
144
+ size: bar.height
145
+ })
135
146
  : barPadding,
136
147
  isFirstBar: shouldApplyRadiusOnBottom,
137
148
  isHorizontal,
@@ -146,19 +157,19 @@ const BarStack = ({
146
157
  isHorizontal
147
158
  ? barPadding
148
159
  : getPadding({
149
- isNegativeValue,
150
- padding: bar.x,
151
- size: bar.width
152
- })
160
+ isNegativeValue,
161
+ padding: bar.x,
162
+ size: bar.width
163
+ })
153
164
  }
154
- y={isHorizontal ? bar.y : barPadding}
165
+ y={isHorizontal ? barY : barPadding}
155
166
  onMouseEnter={
156
167
  isTooltipHidden
157
168
  ? undefined
158
169
  : hoverBar({
159
- barIndex,
160
- highlightedMetric: Number(bar.key)
161
- })
170
+ barIndex,
171
+ highlightedMetric: Number(bar.key)
172
+ })
162
173
  }
163
174
  onMouseLeave={isTooltipHidden ? undefined : exitBar}
164
175
  />
@@ -12,7 +12,7 @@ interface Props {
12
12
  isTooltipHidden: boolean;
13
13
  barStyle: BarStyle;
14
14
  yScalesPerUnit: Record<string, ScaleLinear<number, number>>;
15
- stackedLinesTimeSeriesPerStackKeyAndUnit: Record<
15
+ stackedLinesTimeSeriesPerUnit: Record<
16
16
  string,
17
17
  { lines: Array<Line>; timeSeries: Array<TimeValue> }
18
18
  >;
@@ -25,7 +25,7 @@ interface Props {
25
25
 
26
26
  const MemoizedGroup = ({
27
27
  barGroup,
28
- stackedLinesTimeSeriesPerStackKeyAndUnit,
28
+ stackedLinesTimeSeriesPerUnit,
29
29
  notStackedLines,
30
30
  notStackedTimeSeries,
31
31
  isHorizontal,
@@ -38,7 +38,9 @@ const MemoizedGroup = ({
38
38
  const hasEmptyValues = barGroup.bars.every(({ key, value }) => {
39
39
  if (key.startsWith('stacked-')) {
40
40
  const timeValueBar =
41
- stackedLinesTimeSeriesPerStackKeyAndUnit[key].timeSeries[barIndex];
41
+ stackedLinesTimeSeriesPerUnit[key.replace('stacked-', '')].timeSeries[
42
+ barIndex
43
+ ];
42
44
 
43
45
  return Object.values(omit(['timeTick'], timeValueBar)).every(
44
46
  (value) => !value
@@ -57,19 +59,21 @@ const MemoizedGroup = ({
57
59
  {barGroup.bars.map((bar) => {
58
60
  const isStackedBar = bar.key.startsWith('stacked-');
59
61
  const linesBar = isStackedBar
60
- ? stackedLinesTimeSeriesPerStackKeyAndUnit[bar.key].lines
62
+ ? stackedLinesTimeSeriesPerUnit[bar.key.replace('stacked-', '')].lines
61
63
  : (notStackedLines.find(({ metric_id }) =>
62
- equals(metric_id, Number(bar.key))
63
- ) as Line);
64
+ equals(metric_id, Number(bar.key))
65
+ ) as Line);
64
66
  const timeSeriesBar = isStackedBar
65
- ? stackedLinesTimeSeriesPerStackKeyAndUnit[bar.key].timeSeries
67
+ ? stackedLinesTimeSeriesPerUnit[bar.key.replace('stacked-', '')]
68
+ .timeSeries
66
69
  : notStackedTimeSeries.map((timeSerie) => ({
67
- timeTick: timeSerie.timeTick,
68
- [bar.key]: timeSerie[Number(bar.key)]
69
- }));
70
+ timeTick: timeSerie.timeTick,
71
+ [bar.key]: timeSerie[Number(bar.key)]
72
+ }));
70
73
 
71
74
  return isStackedBar ? (
72
75
  <BarStack
76
+ isStacked
73
77
  key={`bar-${barGroup.index}-${bar.width}-${bar.y}-${bar.height}-${bar.x}`}
74
78
  barIndex={barGroup.index}
75
79
  barPadding={isHorizontal ? bar.x : bar.y}
@@ -79,7 +83,7 @@ const MemoizedGroup = ({
79
83
  isTooltipHidden={isTooltipHidden}
80
84
  lines={linesBar as Array<Line>}
81
85
  timeSeries={timeSeriesBar}
82
- yScale={yScalesPerUnit[bar.key.split('-')[1] || undefined]}
86
+ yScale={yScalesPerUnit[bar.key.replace('stacked-', '')] ?? undefined}
83
87
  neutralValue={neutralValue}
84
88
  />
85
89
  ) : (
@@ -93,7 +97,7 @@ const MemoizedGroup = ({
93
97
  isTooltipHidden={isTooltipHidden}
94
98
  lines={[linesBar as Line]}
95
99
  timeSeries={timeSeriesBar}
96
- yScale={yScalesPerUnit[(linesBar as Line).unit]}
100
+ yScale={yScalesPerUnit[(linesBar as Line).unit ?? undefined]}
97
101
  neutralValue={neutralValue}
98
102
  />
99
103
  );
@@ -107,8 +111,8 @@ export default memo(
107
111
  (prevProps, nextProps) =>
108
112
  equals(prevProps.barGroup, nextProps.barGroup) &&
109
113
  equals(
110
- prevProps.stackedLinesTimeSeriesPerStackKeyAndUnit,
111
- nextProps.stackedLinesTimeSeriesPerStackKeyAndUnit
114
+ prevProps.stackedLinesTimeSeriesPerUnit,
115
+ nextProps.stackedLinesTimeSeriesPerUnit
112
116
  ) &&
113
117
  equals(prevProps.notStackedLines, nextProps.notStackedLines) &&
114
118
  equals(prevProps.notStackedTimeSeries, nextProps.notStackedTimeSeries) &&
@@ -68,7 +68,7 @@ const ResponsiveBarChart = ({
68
68
 
69
69
  const { classes, cx } = useTooltipStyles();
70
70
 
71
- const [linesGraph, setLinesGraph] = useState<Array<Line>>(lines);
71
+ const [linesGraph, setLinesGraph] = useState<Array<Line>>(lines || []);
72
72
  const graphSvgRef = useRef<SVGSVGElement | null>(null);
73
73
 
74
74
  const [tooltipData, setTooltipData] = useAtom(tooltipDataAtom);
@@ -81,7 +81,7 @@ const ResponsiveBarChart = ({
81
81
  );
82
82
 
83
83
  const [firstUnit, secondUnit] = getUnits(displayedLines);
84
- const allUnits = getUnits(lines);
84
+ const allUnits = getUnits(lines || []);
85
85
 
86
86
  const { maxLeftAxisCharacters, maxRightAxisCharacters } =
87
87
  useComputeYAxisMaxCharacters({
@@ -156,12 +156,12 @@ const ResponsiveBarChart = ({
156
156
  ]
157
157
  );
158
158
 
159
- const leftScale = yScalesPerUnit[firstUnit];
160
- const rightScale = yScalesPerUnit[secondUnit];
159
+ const leftScale = yScalesPerUnit[firstUnit ?? allUnits?.[0]];
160
+ const rightScale = yScalesPerUnit[secondUnit ?? allUnits?.[1]];
161
161
 
162
162
  useEffect(
163
163
  () => {
164
- setLinesGraph(lines);
164
+ setLinesGraph(lines || []);
165
165
  },
166
166
  useDeepCompare([lines])
167
167
  );
@@ -196,8 +196,7 @@ const ResponsiveBarChart = ({
196
196
  displayLegend,
197
197
  mode: legend?.mode,
198
198
  placement: legend?.placement,
199
- renderExtraComponent: legend?.renderExtraComponent,
200
- secondaryClick: legend?.secondaryClick
199
+ renderExtraComponent: legend?.renderExtraComponent
201
200
  }}
202
201
  legendRef={legendRef}
203
202
  limitLegend={limitLegend}
@@ -36,7 +36,7 @@ const BarChartTooltip = ({
36
36
  sortOrder
37
37
  }: Props): JSX.Element | null => {
38
38
  const { classes } = useBarChartTooltipStyles();
39
- const { format } = useLocaleDateTimeFormat();
39
+ const { toDate, toTime } = useLocaleDateTimeFormat();
40
40
  const tooltipData = useAtomValue(tooltipDataAtom);
41
41
 
42
42
  if (isNil(tooltipData)) {
@@ -48,7 +48,7 @@ const BarChartTooltip = ({
48
48
  }
49
49
 
50
50
  const date = timeSeries[tooltipData.index].timeTick;
51
- const formattedDateTime = format({ date, formatString: 'L LTS' });
51
+ const formattedDateTime = `${toDate(date)} / ${toTime(date)}`;
52
52
 
53
53
  const isSingleMode = equals(mode, 'single');
54
54
 
@@ -27,6 +27,7 @@ import { StackValue } from '../../../InteractiveComponents/AnchorPoint/models';
27
27
  import { getCurveFactory, getFillColor } from '../../../common';
28
28
  import { LineStyle } from '../../../models';
29
29
  import Point from '../Point';
30
+ import { ReactElement } from 'react';
30
31
 
31
32
  interface Props {
32
33
  areaTransparency?: number;
@@ -56,7 +57,7 @@ const StackLines = ({
56
57
  lineStyle,
57
58
  hasSecondUnit,
58
59
  maxLeftAxisCharacters
59
- }: Props): JSX.Element => {
60
+ }: Props): ReactElement => {
60
61
  const curveType = getCurveFactory(
61
62
  (equals(type(lineStyle), 'Array')
62
63
  ? lineStyle?.[0].curve
@@ -134,9 +135,9 @@ const StackLines = ({
134
135
  equals(style?.showArea, false)
135
136
  ? 'transparent'
136
137
  : getFillColor({
137
- areaColor: areaColor || lineColor,
138
- transparency: formattedTransparency
139
- })
138
+ areaColor: areaColor || lineColor,
139
+ transparency: formattedTransparency
140
+ })
140
141
  }
141
142
  opacity={highlight === false ? 0.3 : 1}
142
143
  stroke={lineColor}
@@ -1,7 +1,9 @@
1
+ import { equals, pluck, uniq } from 'ramda';
2
+
1
3
  import {
2
4
  getInvertedStackedLines,
3
5
  getNotInvertedStackedLines,
4
- getStackedLinesTimeSeriesPerStackAndUnit
6
+ getTimeSeriesForLines
5
7
  } from '../../../../common/timeSeries';
6
8
  import { LinesData } from '../models';
7
9
 
@@ -12,28 +14,53 @@ interface StackedLinesState {
12
14
 
13
15
  const useStackedLines = ({ lines, timeSeries }): StackedLinesState => {
14
16
  const regularStackedLines = getNotInvertedStackedLines(lines);
15
- const {
16
- stackedLinesTimeSeriesPerStackKeyAndUnit:
17
- regularStackedLinesTimeSeriesPerStackKeyAndUnit
18
- } = getStackedLinesTimeSeriesPerStackAndUnit({
19
- stackedLines: regularStackedLines,
20
- timeSeries
21
- });
17
+ const regularStackedUnits = uniq(pluck('unit', regularStackedLines));
18
+ const regularStackedLinesTimeSeriesPerUnit = regularStackedUnits.reduce(
19
+ (acc, stackedUnit) => {
20
+ const relatedLines = regularStackedLines.filter(({ unit }) =>
21
+ equals(unit, stackedUnit)
22
+ );
23
+
24
+ return {
25
+ ...acc,
26
+ [stackedUnit]: {
27
+ lines: relatedLines,
28
+ timeSeries: getTimeSeriesForLines({
29
+ lines: relatedLines,
30
+ timeSeries
31
+ })
32
+ }
33
+ };
34
+ },
35
+ {}
36
+ );
22
37
 
23
38
  const invertedStackedLines = getInvertedStackedLines(lines);
39
+ const invertedStackedUnits = uniq(pluck('unit', invertedStackedLines));
40
+ const invertedStackedLinesTimeSeriesPerUnit = invertedStackedUnits.reduce(
41
+ (acc, stackedUnit) => {
42
+ const relatedLines = invertedStackedLines.filter(({ unit }) =>
43
+ equals(unit, stackedUnit)
44
+ );
24
45
 
25
- const {
26
- stackedLinesTimeSeriesPerStackKeyAndUnit:
27
- invertedStackedLinesTimeSeriesPerStackKeyAndUnit
28
- } = getStackedLinesTimeSeriesPerStackAndUnit({
29
- stackedLines: invertedStackedLines,
30
- timeSeries,
31
- invert: true
32
- });
46
+ return {
47
+ ...acc,
48
+ [stackedUnit]: {
49
+ lines: relatedLines,
50
+ timeSeries: getTimeSeriesForLines({
51
+ invert: true,
52
+ lines: relatedLines,
53
+ timeSeries
54
+ })
55
+ }
56
+ };
57
+ },
58
+ {}
59
+ );
33
60
 
34
61
  return {
35
- invertedStackedLinesData: invertedStackedLinesTimeSeriesPerStackKeyAndUnit,
36
- stackedLinesData: regularStackedLinesTimeSeriesPerStackKeyAndUnit
62
+ invertedStackedLinesData: invertedStackedLinesTimeSeriesPerUnit,
63
+ stackedLinesData: regularStackedLinesTimeSeriesPerUnit
37
64
  };
38
65
  };
39
66