Skip to content

Commit be720d3

Browse files
authored
Merge pull request #4048 from dlabrecq/skeleton
Show chart skeleton for Cost explorer
2 parents cdc0d3f + 093a4ce commit be720d3

File tree

9 files changed

+108
-22
lines changed

9 files changed

+108
-22
lines changed

src/components/featureToggle/featureToggle.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { FeatureToggleActions } from 'store/featureToggle';
77
export const enum FeatureToggle {
88
accountInfoEmptyState = 'cost-management.ui.account-info-empty-state', // https://issues.redhat.com/browse/COST-5335
99
awsEc2Instances = 'cost-management.ui.aws-ec2-instances', // https://issues.redhat.com/browse/COST-4855
10+
chartSkeleton = 'cost-management.ui.chart-skeleton', // https://issues.redhat.com/browse/COST-5573
1011
debug = 'cost-management.ui.debug',
1112
detailsDateRange = 'cost-management.ui.details-date-range', // https://issues.redhat.com/browse/COST-5563
1213
exports = 'cost-management.ui.exports', // Async exports https://issues.redhat.com/browse/COST-2223
@@ -28,6 +29,10 @@ export const useIsAwsEc2InstancesToggleEnabled = () => {
2829
return useIsToggleEnabled(FeatureToggle.awsEc2Instances);
2930
};
3031

32+
export const useIsChartSkeletonToggleEnabled = () => {
33+
return useIsToggleEnabled(FeatureToggle.chartSkeleton);
34+
};
35+
3136
export const useIsDebugToggleEnabled = () => {
3237
return useIsToggleEnabled(FeatureToggle.debug);
3338
};
@@ -59,6 +64,7 @@ export const useFeatureToggle = () => {
5964

6065
const isAccountInfoEmptyStateToggleEnabled = useIsAccountInfoEmptyStateToggleEnabled();
6166
const isAwsEc2InstancesToggleEnabled = useIsAwsEc2InstancesToggleEnabled();
67+
const isChartSkeletonToggleEnabled = useIsChartSkeletonToggleEnabled();
6268
const isDebugToggleEnabled = useIsDebugToggleEnabled();
6369
const isDetailsDateRangeToggleEnabled = useIsDetailsDateRangeToggleEnabled();
6470
const isExportsToggleEnabled = useIsExportsToggleEnabled();
@@ -78,6 +84,7 @@ export const useFeatureToggle = () => {
7884
FeatureToggleActions.setFeatureToggle({
7985
isAccountInfoEmptyStateToggleEnabled,
8086
isAwsEc2InstancesToggleEnabled,
87+
isChartSkeletonToggleEnabled,
8188
isDebugToggleEnabled,
8289
isDetailsDateRangeToggleEnabled,
8390
isExportsToggleEnabled,
@@ -93,6 +100,7 @@ export const useFeatureToggle = () => {
93100
}, [
94101
isAccountInfoEmptyStateToggleEnabled,
95102
isAwsEc2InstancesToggleEnabled,
103+
isChartSkeletonToggleEnabled,
96104
isDebugToggleEnabled,
97105
isDetailsDateRangeToggleEnabled,
98106
isExportsToggleEnabled,

src/routes/components/charts/costExplorerChart/costExplorerChart.tsx

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import messages from 'locales/messages';
1515
import React from 'react';
1616
import type { WrappedComponentProps } from 'react-intl';
1717
import { injectIntl } from 'react-intl';
18-
import { default as ChartTheme } from 'routes/components/charts/chartTheme';
1918
import { getMaxValue } from 'routes/components/charts/common/chartDatum';
2019
import type { ChartSeries } from 'routes/components/charts/common/chartUtils';
2120
import {
@@ -38,6 +37,7 @@ interface CostExplorerChartOwnProps {
3837
baseHeight?: number;
3938
formatOptions?: FormatOptions;
4039
formatter?: Formatter;
40+
isSkeleton?: boolean;
4141
legendItemsPerRow?: number;
4242
name?: string;
4343
padding?: any;
@@ -97,7 +97,7 @@ class CostExplorerChartBase extends React.Component<CostExplorerChartProps, Stat
9797
}
9898

9999
private initDatum = () => {
100-
const { top1stData, top2ndData, top3rdData, top4thData, top5thData, top6thData } = this.props;
100+
const { isSkeleton, top1stData, top2ndData, top3rdData, top4thData, top5thData, top6thData } = this.props;
101101

102102
const series: ChartSeries[] = [];
103103
if (top1stData && top1stData.length) {
@@ -108,13 +108,13 @@ class CostExplorerChartBase extends React.Component<CostExplorerChartProps, Stat
108108
legendItem: {
109109
name,
110110
symbol: {
111-
fill: chartStyles.colorScale[0],
111+
fill: isSkeleton ? undefined : chartStyles.colorScale[0],
112112
},
113113
tooltip: name,
114114
},
115115
style: {
116116
data: {
117-
fill: chartStyles.colorScale[0],
117+
fill: isSkeleton ? undefined : chartStyles.colorScale[0],
118118
},
119119
},
120120
});
@@ -127,13 +127,13 @@ class CostExplorerChartBase extends React.Component<CostExplorerChartProps, Stat
127127
legendItem: {
128128
name,
129129
symbol: {
130-
fill: chartStyles.colorScale[1],
130+
fill: isSkeleton ? undefined : chartStyles.colorScale[1],
131131
},
132132
tooltip: name,
133133
},
134134
style: {
135135
data: {
136-
fill: chartStyles.colorScale[1],
136+
fill: isSkeleton ? undefined : chartStyles.colorScale[1],
137137
},
138138
},
139139
});
@@ -146,13 +146,13 @@ class CostExplorerChartBase extends React.Component<CostExplorerChartProps, Stat
146146
legendItem: {
147147
name,
148148
symbol: {
149-
fill: chartStyles.colorScale[2],
149+
fill: isSkeleton ? undefined : chartStyles.colorScale[2],
150150
},
151151
tooltip: name,
152152
},
153153
style: {
154154
data: {
155-
fill: chartStyles.colorScale[2],
155+
fill: isSkeleton ? undefined : chartStyles.colorScale[2],
156156
},
157157
},
158158
});
@@ -165,13 +165,13 @@ class CostExplorerChartBase extends React.Component<CostExplorerChartProps, Stat
165165
legendItem: {
166166
name,
167167
symbol: {
168-
fill: chartStyles.colorScale[3],
168+
fill: isSkeleton ? undefined : chartStyles.colorScale[3],
169169
},
170170
tooltip: name,
171171
},
172172
style: {
173173
data: {
174-
fill: chartStyles.colorScale[3],
174+
fill: isSkeleton ? undefined : chartStyles.colorScale[3],
175175
},
176176
},
177177
});
@@ -184,13 +184,13 @@ class CostExplorerChartBase extends React.Component<CostExplorerChartProps, Stat
184184
legendItem: {
185185
name,
186186
symbol: {
187-
fill: chartStyles.colorScale[4],
187+
fill: isSkeleton ? undefined : chartStyles.colorScale[4],
188188
},
189189
tooltip: name,
190190
},
191191
style: {
192192
data: {
193-
fill: chartStyles.colorScale[4],
193+
fill: isSkeleton ? undefined : chartStyles.colorScale[4],
194194
},
195195
},
196196
});
@@ -203,13 +203,13 @@ class CostExplorerChartBase extends React.Component<CostExplorerChartProps, Stat
203203
legendItem: {
204204
name,
205205
symbol: {
206-
fill: chartStyles.colorScale[5],
206+
fill: isSkeleton ? undefined : chartStyles.colorScale[5],
207207
},
208208
tooltip: name,
209209
},
210210
style: {
211211
data: {
212-
fill: chartStyles.colorScale[5],
212+
fill: isSkeleton ? undefined : chartStyles.colorScale[5],
213213
},
214214
},
215215
});
@@ -384,7 +384,7 @@ class CostExplorerChartBase extends React.Component<CostExplorerChartProps, Stat
384384

385385
private getTruncatedString = (str: string) => {
386386
const maxChars = 20;
387-
return str.length > maxChars ? str.substring(0, maxChars - 1) + '...' : str;
387+
return str?.length > maxChars ? str.substring(0, maxChars - 1) + '...' : str;
388388
};
389389

390390
private getTickValue = (t: number) => {
@@ -430,7 +430,7 @@ class CostExplorerChartBase extends React.Component<CostExplorerChartProps, Stat
430430
};
431431

432432
public render() {
433-
const { baseHeight, intl, name, padding = this.getPadding() } = this.props;
433+
const { baseHeight, intl, isSkeleton, name, padding = this.getPadding() } = this.props;
434434
const { cursorVoronoiContainer, hiddenSeries, series, tickValues, width } = this.state;
435435

436436
const barWidth = this.getBarWidth();
@@ -455,7 +455,7 @@ class CostExplorerChartBase extends React.Component<CostExplorerChartProps, Stat
455455
<div style={{ height: chartHeight }}>
456456
<Chart
457457
ariaTitle={intl.formatMessage(messages.explorerChartAriaTitle)}
458-
containerComponent={container}
458+
containerComponent={isSkeleton ? undefined : container}
459459
domain={this.getDomain(series, hiddenSeries)}
460460
domainPadding={{ x: this.getBarWidth(true) }}
461461
events={this.getEvents()}
@@ -466,8 +466,7 @@ class CostExplorerChartBase extends React.Component<CostExplorerChartProps, Stat
466466
legendPosition="bottom-left"
467467
name={name}
468468
padding={padding}
469-
theme={ChartTheme}
470-
themeColor={ChartThemeColor.multiOrdered}
469+
themeColor={isSkeleton ? ChartThemeColor.skeleton : ChartThemeColor.multiOrdered}
471470
width={width}
472471
>
473472
{series && series.length > 0 && (

src/routes/explorer/explorer.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ interface ExplorerStateProps {
8686
gcpProviders: Providers;
8787
ibmProviders: Providers;
8888
isAccountInfoEmptyStateToggleEnabled?: boolean;
89+
isChartSkeletonToggleEnabled?: boolean;
8990
isCurrentMonthData?: boolean;
9091
isDataAvailable?: boolean;
9192
isDetailsDateRangeToggleEnabled?: boolean;
@@ -496,6 +497,7 @@ class Explorer extends React.Component<ExplorerProps, ExplorerState> {
496497
gcpProviders,
497498
ibmProviders,
498499
intl,
500+
isChartSkeletonToggleEnabled,
499501
isCurrentMonthData,
500502
isDataAvailable,
501503
isDetailsDateRangeToggleEnabled,
@@ -620,7 +622,7 @@ class Explorer extends React.Component<ExplorerProps, ExplorerState> {
620622
</div>
621623
</div>
622624
) : (
623-
itemsTotal > 0 && (
625+
(itemsTotal > 0 || isChartSkeletonToggleEnabled) && (
624626
<div style={styles.chartContent}>
625627
<div style={styles.chartContainer}>
626628
<ExplorerChart
@@ -778,6 +780,7 @@ const mapStateToProps = createMapStateToProps<ExplorerOwnProps, ExplorerStatePro
778780
gcpProviders,
779781
ibmProviders,
780782
isAccountInfoEmptyStateToggleEnabled: FeatureToggleSelectors.selectIsAccountInfoEmptyStateToggleEnabled(state),
783+
isChartSkeletonToggleEnabled: FeatureToggleSelectors.selectIsChartSkeletonToggleEnabled(state),
781784
isCurrentMonthData,
782785
isDataAvailable,
783786
isDetailsDateRangeToggleEnabled,

src/routes/explorer/explorerChart.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { withRouter } from 'utils/router';
3131
import { getCostDistribution } from 'utils/sessionStorage';
3232

3333
import { chartStyles, styles } from './explorerChart.styles';
34+
import { getExplorerSkeletonData } from './explorerSkeletonData';
3435
import { PerspectiveType } from './explorerUtils';
3536
import { getGroupByDefault, getReportPathsType, getReportType } from './explorerUtils';
3637

@@ -233,9 +234,15 @@ class ExplorerChartBase extends React.Component<ExplorerChartProps, ExplorerChar
233234
};
234235

235236
public render() {
236-
const { perspective, reportFetchStatus, intl } = this.props;
237+
const { perspective, report, reportFetchStatus, intl } = this.props;
237238

238-
const datums = this.getChartDatums(this.getComputedItems());
239+
let datums = this.getChartDatums(this.getComputedItems());
240+
let isSkeleton = false;
241+
242+
if (report && datums.length === 0) {
243+
isSkeleton = true;
244+
datums = getExplorerSkeletonData(report?.meta?.count) as any;
245+
}
239246

240247
// Todo: get title from perspective menu
241248
return (
@@ -254,6 +261,7 @@ class ExplorerChartBase extends React.Component<ExplorerChartProps, ExplorerChar
254261
baseHeight={chartStyles.chartHeight}
255262
formatOptions={{}}
256263
formatter={formatUnits}
264+
isSkeleton={isSkeleton}
257265
top1stData={datums.length > 0 ? datums[0] : []}
258266
top2ndData={datums.length > 1 ? datums[1] : []}
259267
top3rdData={datums.length > 2 ? datums[2] : []}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
const top1stData = [
2+
1108.53, 1108.12, 1109.35, 1109.71, 1109.73, 1109.81, 1109.69, 1108.75, 1109.03, 1108.87, 1108.62, 1108.57, 1108.95,
3+
1109.85, 1109.83, 1109.78, 1109.57, 1108.47, 1108.53, 1108.9, 1109.8, 1109.91, 1111.42, 1109.74, 1109.61, 1109.6,
4+
1109.73, 1112.55, 1109.65, 1109.78, 231.21,
5+
];
6+
const top2ndData = [
7+
1343.03, 903.56, 953.58, 609.13, 1185.89, 1501.3, 887.25, 598.46, 913.52, 1957.66, 1645.23, 544.67, 1203.28, 1251.59,
8+
552.12, 673.74, 753.94, 1392.65, 435.82, 1269.72, 1288.04, 936.65, 823.59, 824.14, 823.54, 824.06, 480.64, 417.32,
9+
1003.14, 1001.25, 583.4,
10+
];
11+
const top3rdData = [
12+
374.82, 383.76, 319.87, 104.59, 118.03, 337.04, 823.11, 579.26, 295.51, 531.44, 105.67, 104.6, 971.38, 286.35, 568.39,
13+
238.03, 192.37, 60.09, 78.2, 237.03, 209.01, 224.73, 326.58, 200.96, 68.54, 99.04, 300.24, 232.8, 107.08, 267.67,
14+
55.62,
15+
];
16+
const top4thData = [
17+
120.66, 60.11, 8.44, 8.45, 20.26, 75.93, 32.08, 11.92, 22.96, 67.38, 25.19, 17.91, 67.42, 47.74, 67.47, 67.31, 71.37,
18+
52.86, 11.64, 26.41, 31.85, 67.31, 19.95, 59.17, 7.32, 7.32, 7.33, 328.35, 8.08, 8.69, 1.19,
19+
];
20+
const top5thData = [
21+
123.35, 123.04, 123.13, 123.06, 124.51, 123.46, 123.21, 123.22, 123.28, 123.14, 123.19, 129.31, 123.18, 123.42,
22+
123.56, 123.46, 123.16, 123.19, 126.51, 123.28, 123.44, 123.38, 123.43, 123.38, 123.25, 129.4, 123.7, 123.12, 123.15,
23+
119.73, 21.57,
24+
];
25+
const top6thData = [
26+
1535.93, 1403.04, 1356.65, 1282.12, 1264.35, 1286.7, 1511.64, 1388.88, 1370.51, 1319.67, 1155.13, 975.7, 1030.38,
27+
1129.76, 1218.14, 1117.55, 1196.87, 997.1, 830.46, 1031.18, 1215.34, 1373, 1405.28, 1431.94, 1164.6, 1031.98, 1360.85,
28+
1548.71, 1206.01, 1179.92,
29+
];
30+
31+
const getData = (name: string, values: number[], count: number) => {
32+
const datum = [];
33+
34+
let index = 0;
35+
while (count > index) {
36+
datum.push({
37+
date: `${index}`,
38+
key: name,
39+
name,
40+
units: 'USD',
41+
x: `${index}`,
42+
y: values[index % values.length],
43+
});
44+
index++;
45+
}
46+
return datum;
47+
};
48+
49+
export const getExplorerSkeletonData = (count = 0) => {
50+
// There will always be at least one day
51+
const days = count ? count : 1;
52+
53+
return [
54+
getData('top1stData', top1stData, days),
55+
getData('top2ndData', top2ndData, days),
56+
getData('top3rdData', top3rdData, days),
57+
getData('top4thData', top4thData, days),
58+
getData('top5thData', top5thData, days),
59+
getData('top6thData', top6thData, days), // Others
60+
];
61+
};

src/store/featureToggle/__snapshots__/featureToggle.test.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ exports[`default state 1`] = `
55
"hasFeatureToggle": false,
66
"isAccountInfoEmptyStateToggleEnabled": false,
77
"isAwsEc2InstancesToggleEnabled": false,
8+
"isChartSkeletonToggleEnabled": false,
89
"isDebugToggleEnabled": false,
910
"isDetailsDateRangeToggleEnabled": false,
1011
"isExportsToggleEnabled": false,

src/store/featureToggle/featureToggleActions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createAction } from 'typesafe-actions';
33
export interface FeatureToggleActionMeta {
44
isAccountInfoEmptyStateToggleEnabled?: boolean;
55
isAwsEc2InstancesToggleEnabled?: boolean;
6+
isChartSkeletonToggleEnabled?: boolean;
67
isDebugToggleEnabled?: boolean;
78
isDetailsDateRangeToggleEnabled?: boolean;
89
isExportsToggleEnabled?: boolean;

src/store/featureToggle/featureToggleReducer.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export type FeatureToggleState = Readonly<{
1010
hasFeatureToggle: boolean;
1111
isAccountInfoEmptyStateToggleEnabled: boolean;
1212
isAwsEc2InstancesToggleEnabled: boolean;
13+
isChartSkeletonToggleEnabled: boolean;
1314
isDebugToggleEnabled: boolean;
1415
isDetailsDateRangeToggleEnabled: boolean;
1516
isExportsToggleEnabled: boolean;
@@ -22,6 +23,7 @@ export const defaultState: FeatureToggleState = {
2223
hasFeatureToggle: false,
2324
isAccountInfoEmptyStateToggleEnabled: false,
2425
isAwsEc2InstancesToggleEnabled: false,
26+
isChartSkeletonToggleEnabled: false,
2527
isDebugToggleEnabled: false,
2628
isDetailsDateRangeToggleEnabled: false,
2729
isExportsToggleEnabled: false,
@@ -40,6 +42,7 @@ export function FeatureToggleReducer(state = defaultState, action: FeatureToggle
4042
hasFeatureToggle: true,
4143
isAccountInfoEmptyStateToggleEnabled: action.payload.isAccountInfoEmptyStateToggleEnabled,
4244
isAwsEc2InstancesToggleEnabled: action.payload.isAwsEc2InstancesToggleEnabled,
45+
isChartSkeletonToggleEnabled: action.payload.isChartSkeletonToggleEnabled,
4346
isDebugToggleEnabled: action.payload.isDebugToggleEnabled,
4447
isDetailsDateRangeToggleEnabled: action.payload.isDetailsDateRangeToggleEnabled,
4548
isExportsToggleEnabled: action.payload.isExportsToggleEnabled,

src/store/featureToggle/featureToggleSelectors.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export const selectIsAccountInfoEmptyStateToggleEnabled = (state: RootState) =>
1010
selectFeatureToggleState(state).isAccountInfoEmptyStateToggleEnabled;
1111
export const selectIsAwsEc2InstancesToggleEnabled = (state: RootState) =>
1212
selectFeatureToggleState(state).isAwsEc2InstancesToggleEnabled;
13+
export const selectIsChartSkeletonToggleEnabled = (state: RootState) =>
14+
selectFeatureToggleState(state).isChartSkeletonToggleEnabled;
1315
export const selectIsDebugToggleEnabled = (state: RootState) => selectFeatureToggleState(state).isDebugToggleEnabled;
1416
export const selectIsDetailsDateRangeToggleEnabled = (state: RootState) =>
1517
selectFeatureToggleState(state).isDetailsDateRangeToggleEnabled;

0 commit comments

Comments
 (0)