@electrolux-oss/plugin-infrawallet 1.1.0-20260112100533-68a81f8 → 1.1.0-20260115072023-d6f33e2
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/dist/components/ColumnsChartComponent/ColumnsChartComponent.esm.js +125 -43
- package/dist/components/ColumnsChartComponent/ColumnsChartComponent.esm.js.map +1 -1
- package/dist/components/ReportsComponent/ReportsComponent.esm.js +17 -0
- package/dist/components/ReportsComponent/ReportsComponent.esm.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,9 +2,10 @@ import Grid from '@mui/material/Grid';
|
|
|
2
2
|
import Paper from '@mui/material/Paper';
|
|
3
3
|
import Skeleton from '@mui/material/Skeleton';
|
|
4
4
|
import Switch from '@mui/material/Switch';
|
|
5
|
+
import { useTheme } from '@mui/material/styles';
|
|
5
6
|
import { ResponsiveChartContainer, ChartsGrid, BarPlot, LinePlot, MarkPlot, LineHighlightPlot, ChartsXAxis, ChartsYAxis, ChartsTooltip, ChartsLegend, DefaultChartsLegend } from '@mui/x-charts';
|
|
6
7
|
import React, { useState, useCallback, useEffect } from 'react';
|
|
7
|
-
import { formatCurrency } from '../../api/functions.esm.js';
|
|
8
|
+
import { formatCurrency, calculateBudgetAnalytics } from '../../api/functions.esm.js';
|
|
8
9
|
import { colorList } from '../constants.esm.js';
|
|
9
10
|
|
|
10
11
|
const ColumnsChartComponent = ({
|
|
@@ -13,62 +14,143 @@ const ColumnsChartComponent = ({
|
|
|
13
14
|
periods,
|
|
14
15
|
costs,
|
|
15
16
|
metrics,
|
|
17
|
+
budgets,
|
|
18
|
+
forecasts,
|
|
16
19
|
height,
|
|
17
20
|
highlightedItem,
|
|
18
21
|
highlightedItemSetter
|
|
19
22
|
}) => {
|
|
23
|
+
const theme = useTheme();
|
|
20
24
|
const [costsSeries, setCostsSeries] = useState(void 0);
|
|
21
25
|
const [metricsSeries, setMetricsSeries] = useState(void 0);
|
|
22
26
|
const [showMetrics, setShowMetrics] = useState(false);
|
|
23
27
|
const [maxCostsYaxis, setMaxCostsYaxis] = useState(void 0);
|
|
28
|
+
const calculateCostSums = useCallback((costsData) => {
|
|
29
|
+
const sums = [];
|
|
30
|
+
for (const s of costsData) {
|
|
31
|
+
for (let i = 0; i < s.data.length; i++) {
|
|
32
|
+
if (sums[i] === void 0) {
|
|
33
|
+
sums[i] = 0;
|
|
34
|
+
}
|
|
35
|
+
sums[i] += s.data[i];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return sums;
|
|
39
|
+
}, []);
|
|
40
|
+
const createBaseCostsSeries = useCallback((costsData) => {
|
|
41
|
+
return costsData.map((s) => ({
|
|
42
|
+
id: s.name,
|
|
43
|
+
data: s.data,
|
|
44
|
+
type: "bar",
|
|
45
|
+
label: `${s.name} Actual Spend`,
|
|
46
|
+
yAxisId: "costsAxis",
|
|
47
|
+
valueFormatter: (value) => formatCurrency(value || 0),
|
|
48
|
+
highlightScope: { highlight: "series", fade: "global" },
|
|
49
|
+
stack: "stack1",
|
|
50
|
+
stackOrder: "descending"
|
|
51
|
+
}));
|
|
52
|
+
}, []);
|
|
53
|
+
const buildMonthlyCosts = useCallback(
|
|
54
|
+
(seriesData) => {
|
|
55
|
+
const monthlyCosts = {};
|
|
56
|
+
periods.forEach((period, index) => {
|
|
57
|
+
monthlyCosts[period] = seriesData[index] || 0;
|
|
58
|
+
});
|
|
59
|
+
return monthlyCosts;
|
|
60
|
+
},
|
|
61
|
+
[periods]
|
|
62
|
+
);
|
|
63
|
+
const createProjectedSeries = useCallback(
|
|
64
|
+
(series, budget, forecast) => {
|
|
65
|
+
const effectiveBudget = budget?.amount ? budget : { amount: 1e5, provider: series.name };
|
|
66
|
+
if (!effectiveBudget?.amount) return null;
|
|
67
|
+
const monthlyCosts = buildMonthlyCosts(series.data);
|
|
68
|
+
const analytics = calculateBudgetAnalytics(monthlyCosts, effectiveBudget.amount, forecast);
|
|
69
|
+
const lastIndex = series.data.length - 1;
|
|
70
|
+
const lastActualCost = lastIndex >= 0 ? series.data[lastIndex] : 0;
|
|
71
|
+
const projectedDelta = analytics.projectedCurrentMonthCost - lastActualCost;
|
|
72
|
+
if (lastIndex < 0 || projectedDelta <= 0) return null;
|
|
73
|
+
const deltaData = series.data.map((_, i) => i === lastIndex ? projectedDelta : 0);
|
|
74
|
+
return {
|
|
75
|
+
id: `${series.name}-projected`,
|
|
76
|
+
data: deltaData,
|
|
77
|
+
type: "bar",
|
|
78
|
+
label: `${series.name} Forecast`,
|
|
79
|
+
yAxisId: "costsAxis",
|
|
80
|
+
color: theme.palette.warning.main,
|
|
81
|
+
valueFormatter: (value) => {
|
|
82
|
+
if (value === 0) return null;
|
|
83
|
+
return `${formatCurrency(projectedDelta)}`;
|
|
84
|
+
},
|
|
85
|
+
highlightScope: { highlight: "series", fade: "global" },
|
|
86
|
+
stack: "stack1",
|
|
87
|
+
stackOrder: "descending"
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
[buildMonthlyCosts, theme.palette.warning.main]
|
|
91
|
+
);
|
|
92
|
+
const createProjectedDeltaSeries = useCallback(
|
|
93
|
+
(costsData) => {
|
|
94
|
+
if (granularity !== "monthly") return [];
|
|
95
|
+
const projectedSeries = [];
|
|
96
|
+
for (const s of costsData) {
|
|
97
|
+
const budget = budgets?.find((b) => b.provider.toLowerCase() === s.name.toLowerCase());
|
|
98
|
+
const forecast = forecasts?.[s.name];
|
|
99
|
+
const projectedData = createProjectedSeries(s, budget, forecast);
|
|
100
|
+
if (projectedData) {
|
|
101
|
+
projectedSeries.push(projectedData);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return projectedSeries;
|
|
105
|
+
},
|
|
106
|
+
[granularity, budgets, forecasts, createProjectedSeries]
|
|
107
|
+
);
|
|
108
|
+
const calculateMaxYAxis = useCallback((baseSums, projectedSeries) => {
|
|
109
|
+
const allSums = [...baseSums];
|
|
110
|
+
for (const deltaSeries of projectedSeries) {
|
|
111
|
+
for (let i = 0; i < deltaSeries.data.length; i++) {
|
|
112
|
+
if (deltaSeries.data[i] > 0) {
|
|
113
|
+
allSums[i] = (allSums[i] || 0) + deltaSeries.data[i];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return Math.max(...allSums);
|
|
118
|
+
}, []);
|
|
119
|
+
const createMetricsSeriesData = useCallback(() => {
|
|
120
|
+
if (!metrics || !showMetrics) return void 0;
|
|
121
|
+
return metrics.map((s) => ({
|
|
122
|
+
data: s.data,
|
|
123
|
+
type: "line",
|
|
124
|
+
label: s.name,
|
|
125
|
+
curve: "natural",
|
|
126
|
+
yAxisId: "metricsAxis",
|
|
127
|
+
highlightScope: { highlight: "series", fade: "global" },
|
|
128
|
+
showMark: granularity === "monthly"
|
|
129
|
+
}));
|
|
130
|
+
}, [metrics, showMetrics, granularity]);
|
|
24
131
|
const initChartCallback = useCallback(async () => {
|
|
25
132
|
setCostsSeries(void 0);
|
|
26
133
|
setMetricsSeries(void 0);
|
|
27
134
|
if (costs) {
|
|
28
|
-
const sums =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
sums[i] += s.data[i];
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
setMaxCostsYaxis(Math.max(...sums));
|
|
38
|
-
setCostsSeries(
|
|
39
|
-
costs.map((s) => {
|
|
40
|
-
return {
|
|
41
|
-
id: s.name,
|
|
42
|
-
data: s.data,
|
|
43
|
-
type: "bar",
|
|
44
|
-
label: s.name,
|
|
45
|
-
yAxisId: "costsAxis",
|
|
46
|
-
valueFormatter: (value) => {
|
|
47
|
-
return formatCurrency(value ? value : 0);
|
|
48
|
-
},
|
|
49
|
-
highlightScope: { highlight: "series", fade: "global" },
|
|
50
|
-
stack: "total",
|
|
51
|
-
stackOrder: "descending"
|
|
52
|
-
};
|
|
53
|
-
})
|
|
54
|
-
);
|
|
135
|
+
const sums = calculateCostSums(costs);
|
|
136
|
+
const baseCostsSeries = createBaseCostsSeries(costs);
|
|
137
|
+
const projectedDeltaSeries = createProjectedDeltaSeries(costs);
|
|
138
|
+
const maxYValue = calculateMaxYAxis(sums, projectedDeltaSeries);
|
|
139
|
+
setMaxCostsYaxis(maxYValue);
|
|
140
|
+
setCostsSeries([...baseCostsSeries, ...projectedDeltaSeries]);
|
|
55
141
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
data: s.data,
|
|
61
|
-
type: "line",
|
|
62
|
-
label: s.name,
|
|
63
|
-
curve: "natural",
|
|
64
|
-
yAxisId: "metricsAxis",
|
|
65
|
-
highlightScope: { highlight: "series", fade: "global" },
|
|
66
|
-
showMark: granularity === "monthly"
|
|
67
|
-
};
|
|
68
|
-
})
|
|
69
|
-
);
|
|
142
|
+
const metricsData = createMetricsSeriesData();
|
|
143
|
+
if (metricsData) {
|
|
144
|
+
setMetricsSeries(metricsData);
|
|
70
145
|
}
|
|
71
|
-
}, [
|
|
146
|
+
}, [
|
|
147
|
+
costs,
|
|
148
|
+
calculateCostSums,
|
|
149
|
+
createBaseCostsSeries,
|
|
150
|
+
createProjectedDeltaSeries,
|
|
151
|
+
calculateMaxYAxis,
|
|
152
|
+
createMetricsSeriesData
|
|
153
|
+
]);
|
|
72
154
|
useEffect(() => {
|
|
73
155
|
initChartCallback();
|
|
74
156
|
}, [initChartCallback]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColumnsChartComponent.esm.js","sources":["../../../src/components/ColumnsChartComponent/ColumnsChartComponent.tsx"],"sourcesContent":["import Grid from '@mui/material/Grid';\nimport Paper from '@mui/material/Paper';\nimport Skeleton from '@mui/material/Skeleton';\nimport Switch from '@mui/material/Switch';\nimport {\n BarPlot,\n ChartsGrid,\n ChartsLegend,\n ChartsTooltip,\n ChartsXAxis,\n ChartsYAxis,\n DefaultChartsLegend,\n LineHighlightPlot,\n LinePlot,\n MarkPlot,\n ResponsiveChartContainer,\n} from '@mui/x-charts';\nimport { FC, default as React, useCallback, useEffect, useState } from 'react';\nimport { formatCurrency } from '../../api/functions';\nimport { colorList } from '../constants';\nimport { ColumnsChartComponentProps } from '../types';\n\nexport const ColumnsChartComponent: FC<ColumnsChartComponentProps> = ({\n granularity,\n granularitySetter,\n periods,\n costs,\n metrics,\n height,\n highlightedItem,\n highlightedItemSetter,\n}) => {\n const [costsSeries, setCostsSeries] = useState<any[] | undefined>(undefined);\n const [metricsSeries, setMetricsSeries] = useState<any[] | undefined>(undefined);\n const [showMetrics, setShowMetrics] = useState<boolean>(false);\n const [maxCostsYaxis, setMaxCostsYaxis] = useState<number | undefined>(undefined);\n\n const initChartCallback = useCallback(async () => {\n setCostsSeries(undefined);\n setMetricsSeries(undefined);\n\n if (costs) {\n const sums = [];\n for (const s of costs) {\n for (let i = 0; i < s.data.length; i++) {\n if (sums[i] === undefined) {\n sums[i] = 0;\n }\n sums[i] += s.data[i];\n }\n }\n setMaxCostsYaxis(Math.max(...sums));\n\n setCostsSeries(\n costs.map(s => {\n return {\n id: s.name,\n data: s.data,\n type: 'bar',\n label: s.name,\n yAxisId: 'costsAxis',\n valueFormatter: (value: number) => {\n return formatCurrency(value ? value : 0);\n },\n highlightScope: { highlight: 'series', fade: 'global' },\n stack: 'total',\n stackOrder: 'descending',\n };\n }),\n );\n }\n\n if (metrics && showMetrics) {\n setMetricsSeries(\n metrics.map(s => {\n return {\n data: s.data,\n type: 'line',\n label: s.name,\n curve: 'natural',\n yAxisId: 'metricsAxis',\n highlightScope: { highlight: 'series', fade: 'global' },\n showMark: granularity === 'monthly',\n };\n }),\n );\n }\n }, [costs, metrics, showMetrics, granularity]);\n\n useEffect(() => {\n initChartCallback();\n }, [initChartCallback]);\n\n return (\n <Paper\n sx={{\n padding: '16px',\n display: 'flex',\n flexDirection: 'column',\n height: height ? height : 300,\n }}\n >\n <Grid container justifyContent=\"flex-end\" spacing={1}>\n <Grid item>Monthly</Grid>\n <Grid item>\n <Switch size=\"small\" onChange={event => granularitySetter(event.target.checked ? 'daily' : 'monthly')} />\n </Grid>\n <Grid item>Daily</Grid>\n <Grid item> | </Grid>\n <Grid item>\n <Switch size=\"small\" checked={showMetrics} onChange={_ => setShowMetrics((ori: boolean) => !ori)} />\n </Grid>\n <Grid item>Show Metrics</Grid>\n </Grid>\n {costs !== undefined && costsSeries !== undefined ? (\n <ResponsiveChartContainer\n margin={{\n bottom: 6 * costsSeries.length + 80,\n }}\n series={[...costsSeries, ...(metricsSeries ? metricsSeries : [])]}\n xAxis={[\n {\n data: periods,\n scaleType: 'band',\n },\n ]}\n yAxis={[\n {\n id: 'costsAxis',\n max: maxCostsYaxis,\n valueFormatter: value => formatCurrency(value),\n },\n {\n id: 'metricsAxis',\n },\n ]}\n colors={colorList}\n highlightedItem={highlightedItem ? { seriesId: highlightedItem } : null}\n onHighlightChange={highlighted => {\n highlightedItemSetter(highlighted?.seriesId);\n }}\n >\n <ChartsGrid horizontal />\n <BarPlot />\n <LinePlot />\n <MarkPlot />\n <LineHighlightPlot />\n <ChartsXAxis\n tickLabelStyle={{\n angle: periods.length > 12 ? -45 : 0,\n textAnchor: periods.length > 12 ? 'end' : 'middle',\n }}\n />\n <ChartsYAxis />\n <ChartsTooltip trigger=\"item\" />\n <ChartsLegend\n slots={{\n legend: props => {\n // keep legend items for costs only (from bar chart)\n const seriesToDisplay = [];\n for (const s of props.seriesToDisplay) {\n if (props.series.bar?.seriesOrder && props.series.bar.seriesOrder.indexOf(s.id) !== -1) {\n seriesToDisplay.push(s);\n }\n }\n\n return (\n <DefaultChartsLegend\n series={props.series}\n seriesToDisplay={seriesToDisplay}\n drawingArea={props.drawingArea}\n direction=\"row\"\n position={{ vertical: 'bottom', horizontal: 'middle' }}\n itemMarkHeight={10}\n itemMarkWidth={10}\n itemGap={costsSeries.length > 5 ? 5 : 10}\n labelStyle={{\n fontSize: '0.9em',\n }}\n onItemClick={(_, legendItem) => {\n // highlight the clicked item\n const clickedLegend = legendItem.seriesId;\n if (clickedLegend === highlightedItem) {\n highlightedItemSetter(undefined);\n } else {\n highlightedItemSetter(clickedLegend);\n }\n }}\n />\n );\n },\n }}\n />\n </ResponsiveChartContainer>\n ) : (\n <div style={{ width: '60%', margin: 'auto' }}>\n <Skeleton />\n <Skeleton />\n <Skeleton />\n </div>\n )}\n </Paper>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;AAsBO,MAAM,wBAAwD,CAAC;AAAA,EACpE,WAAA;AAAA,EACA,iBAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,eAAA;AAAA,EACA;AACF,CAAA,KAAM;AACJ,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAA4B,MAAS,CAAA;AAC3E,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAI,SAA4B,MAAS,CAAA;AAC/E,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAkB,KAAK,CAAA;AAC7D,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAI,SAA6B,MAAS,CAAA;AAEhF,EAAA,MAAM,iBAAA,GAAoB,YAAY,YAAY;AAChD,IAAA,cAAA,CAAe,MAAS,CAAA;AACxB,IAAA,gBAAA,CAAiB,MAAS,CAAA;AAE1B,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,MAAM,OAAO,EAAC;AACd,MAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,QAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,IAAA,CAAK,QAAQ,CAAA,EAAA,EAAK;AACtC,UAAA,IAAI,IAAA,CAAK,CAAC,CAAA,KAAM,MAAA,EAAW;AACzB,YAAA,IAAA,CAAK,CAAC,CAAA,GAAI,CAAA;AAAA;AAEZ,UAAA,IAAA,CAAK,CAAC,CAAA,IAAK,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA;AAAA;AACrB;AAEF,MAAA,gBAAA,CAAiB,IAAA,CAAK,GAAA,CAAI,GAAG,IAAI,CAAC,CAAA;AAElC,MAAA,cAAA;AAAA,QACE,KAAA,CAAM,IAAI,CAAA,CAAA,KAAK;AACb,UAAA,OAAO;AAAA,YACL,IAAI,CAAA,CAAE,IAAA;AAAA,YACN,MAAM,CAAA,CAAE,IAAA;AAAA,YACR,IAAA,EAAM,KAAA;AAAA,YACN,OAAO,CAAA,CAAE,IAAA;AAAA,YACT,OAAA,EAAS,WAAA;AAAA,YACT,cAAA,EAAgB,CAAC,KAAA,KAAkB;AACjC,cAAA,OAAO,cAAA,CAAe,KAAA,GAAQ,KAAA,GAAQ,CAAC,CAAA;AAAA,aACzC;AAAA,YACA,cAAA,EAAgB,EAAE,SAAA,EAAW,QAAA,EAAU,MAAM,QAAA,EAAS;AAAA,YACtD,KAAA,EAAO,OAAA;AAAA,YACP,UAAA,EAAY;AAAA,WACd;AAAA,SACD;AAAA,OACH;AAAA;AAGF,IAAA,IAAI,WAAW,WAAA,EAAa;AAC1B,MAAA,gBAAA;AAAA,QACE,OAAA,CAAQ,IAAI,CAAA,CAAA,KAAK;AACf,UAAA,OAAO;AAAA,YACL,MAAM,CAAA,CAAE,IAAA;AAAA,YACR,IAAA,EAAM,MAAA;AAAA,YACN,OAAO,CAAA,CAAE,IAAA;AAAA,YACT,KAAA,EAAO,SAAA;AAAA,YACP,OAAA,EAAS,aAAA;AAAA,YACT,cAAA,EAAgB,EAAE,SAAA,EAAW,QAAA,EAAU,MAAM,QAAA,EAAS;AAAA,YACtD,UAAU,WAAA,KAAgB;AAAA,WAC5B;AAAA,SACD;AAAA,OACH;AAAA;AACF,KACC,CAAC,KAAA,EAAO,OAAA,EAAS,WAAA,EAAa,WAAW,CAAC,CAAA;AAE7C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,iBAAA,EAAkB;AAAA,GACpB,EAAG,CAAC,iBAAiB,CAAC,CAAA;AAEtB,EAAA,uBACE,KAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,EAAA,EAAI;AAAA,QACF,OAAA,EAAS,MAAA;AAAA,QACT,OAAA,EAAS,MAAA;AAAA,QACT,aAAA,EAAe,QAAA;AAAA,QACf,MAAA,EAAQ,SAAS,MAAA,GAAS;AAAA;AAC5B,KAAA;AAAA,oBAEA,KAAA,CAAA,aAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAS,IAAA,EAAC,gBAAe,UAAA,EAAW,OAAA,EAAS,CAAA,EAAA,kBACjD,KAAA,CAAA,aAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAI,IAAA,EAAA,EAAC,SAAO,mBAClB,KAAA,CAAA,aAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAI,IAAA,EAAA,kBACR,KAAA,CAAA,aAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAK,OAAA,EAAQ,UAAU,CAAA,KAAA,KAAS,iBAAA,CAAkB,KAAA,CAAM,MAAA,CAAO,UAAU,OAAA,GAAU,SAAS,CAAA,EAAG,CACzG,mBACA,KAAA,CAAA,aAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAI,IAAA,EAAA,EAAC,OAAK,CAAA,kBAChB,KAAA,CAAA,aAAA,CAAC,IAAA,EAAA,EAAK,MAAI,IAAA,EAAA,EAAC,KAAG,CAAA,kBACd,KAAA,CAAA,aAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAI,IAAA,EAAA,kBACR,KAAA,CAAA,aAAA,CAAC,UAAO,IAAA,EAAK,OAAA,EAAQ,OAAA,EAAS,WAAA,EAAa,QAAA,EAAU,CAAA,CAAA,KAAK,cAAA,CAAe,CAAC,QAAiB,CAAC,GAAG,CAAA,EAAG,CACpG,mBACA,KAAA,CAAA,aAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAI,IAAA,EAAA,EAAC,cAAY,CACzB,CAAA;AAAA,IACC,KAAA,KAAU,MAAA,IAAa,WAAA,KAAgB,MAAA,mBACtC,KAAA,CAAA,aAAA;AAAA,MAAC,wBAAA;AAAA,MAAA;AAAA,QACC,MAAA,EAAQ;AAAA,UACN,MAAA,EAAQ,CAAA,GAAI,WAAA,CAAY,MAAA,GAAS;AAAA,SACnC;AAAA,QACA,MAAA,EAAQ,CAAC,GAAG,WAAA,EAAa,GAAI,aAAA,GAAgB,aAAA,GAAgB,EAAG,CAAA;AAAA,QAChE,KAAA,EAAO;AAAA,UACL;AAAA,YACE,IAAA,EAAM,OAAA;AAAA,YACN,SAAA,EAAW;AAAA;AACb,SACF;AAAA,QACA,KAAA,EAAO;AAAA,UACL;AAAA,YACE,EAAA,EAAI,WAAA;AAAA,YACJ,GAAA,EAAK,aAAA;AAAA,YACL,cAAA,EAAgB,CAAA,KAAA,KAAS,cAAA,CAAe,KAAK;AAAA,WAC/C;AAAA,UACA;AAAA,YACE,EAAA,EAAI;AAAA;AACN,SACF;AAAA,QACA,MAAA,EAAQ,SAAA;AAAA,QACR,eAAA,EAAiB,eAAA,GAAkB,EAAE,QAAA,EAAU,iBAAgB,GAAI,IAAA;AAAA,QACnE,mBAAmB,CAAA,WAAA,KAAe;AAChC,UAAA,qBAAA,CAAsB,aAAa,QAAQ,CAAA;AAAA;AAC7C,OAAA;AAAA,sBAEA,KAAA,CAAA,aAAA,CAAC,UAAA,EAAA,EAAW,UAAA,EAAU,IAAA,EAAC,CAAA;AAAA,0CACtB,OAAA,EAAA,IAAQ,CAAA;AAAA,0CACR,QAAA,EAAA,IAAS,CAAA;AAAA,0CACT,QAAA,EAAA,IAAS,CAAA;AAAA,0CACT,iBAAA,EAAA,IAAkB,CAAA;AAAA,sBACnB,KAAA,CAAA,aAAA;AAAA,QAAC,WAAA;AAAA,QAAA;AAAA,UACC,cAAA,EAAgB;AAAA,YACd,KAAA,EAAO,OAAA,CAAQ,MAAA,GAAS,EAAA,GAAK,GAAA,GAAM,CAAA;AAAA,YACnC,UAAA,EAAY,OAAA,CAAQ,MAAA,GAAS,EAAA,GAAK,KAAA,GAAQ;AAAA;AAC5C;AAAA,OACF;AAAA,0CACC,WAAA,EAAA,IAAY,CAAA;AAAA,sBACb,KAAA,CAAA,aAAA,CAAC,aAAA,EAAA,EAAc,OAAA,EAAQ,MAAA,EAAO,CAAA;AAAA,sBAC9B,KAAA,CAAA,aAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO;AAAA,YACL,QAAQ,CAAA,KAAA,KAAS;AAEf,cAAA,MAAM,kBAAkB,EAAC;AACzB,cAAA,KAAA,MAAW,CAAA,IAAK,MAAM,eAAA,EAAiB;AACrC,gBAAA,IAAI,KAAA,CAAM,MAAA,CAAO,GAAA,EAAK,WAAA,IAAe,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,WAAA,CAAY,OAAA,CAAQ,CAAA,CAAE,EAAE,CAAA,KAAM,EAAA,EAAI;AACtF,kBAAA,eAAA,CAAgB,KAAK,CAAC,CAAA;AAAA;AACxB;AAGF,cAAA,uBACE,KAAA,CAAA,aAAA;AAAA,gBAAC,mBAAA;AAAA,gBAAA;AAAA,kBACC,QAAQ,KAAA,CAAM,MAAA;AAAA,kBACd,eAAA;AAAA,kBACA,aAAa,KAAA,CAAM,WAAA;AAAA,kBACnB,SAAA,EAAU,KAAA;AAAA,kBACV,QAAA,EAAU,EAAE,QAAA,EAAU,QAAA,EAAU,YAAY,QAAA,EAAS;AAAA,kBACrD,cAAA,EAAgB,EAAA;AAAA,kBAChB,aAAA,EAAe,EAAA;AAAA,kBACf,OAAA,EAAS,WAAA,CAAY,MAAA,GAAS,CAAA,GAAI,CAAA,GAAI,EAAA;AAAA,kBACtC,UAAA,EAAY;AAAA,oBACV,QAAA,EAAU;AAAA,mBACZ;AAAA,kBACA,WAAA,EAAa,CAAC,CAAA,EAAG,UAAA,KAAe;AAE9B,oBAAA,MAAM,gBAAgB,UAAA,CAAW,QAAA;AACjC,oBAAA,IAAI,kBAAkB,eAAA,EAAiB;AACrC,sBAAA,qBAAA,CAAsB,MAAS,CAAA;AAAA,qBACjC,MAAO;AACL,sBAAA,qBAAA,CAAsB,aAAa,CAAA;AAAA;AACrC;AACF;AAAA,eACF;AAAA;AAEJ;AACF;AAAA;AACF,wBAGF,KAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,OAAO,EAAE,KAAA,EAAO,OAAO,MAAA,EAAQ,MAAA,EAAO,EAAA,kBACzC,KAAA,CAAA,aAAA,CAAC,cAAS,CAAA,kBACV,KAAA,CAAA,aAAA,CAAC,cAAS,CAAA,kBACV,KAAA,CAAA,aAAA,CAAC,cAAS,CACZ;AAAA,GAEJ;AAEJ;;;;"}
|
|
1
|
+
{"version":3,"file":"ColumnsChartComponent.esm.js","sources":["../../../src/components/ColumnsChartComponent/ColumnsChartComponent.tsx"],"sourcesContent":["import Grid from '@mui/material/Grid';\nimport Paper from '@mui/material/Paper';\nimport Skeleton from '@mui/material/Skeleton';\nimport Switch from '@mui/material/Switch';\nimport { useTheme } from '@mui/material/styles';\nimport {\n BarPlot,\n ChartsGrid,\n ChartsLegend,\n ChartsTooltip,\n ChartsXAxis,\n ChartsYAxis,\n DefaultChartsLegend,\n LineHighlightPlot,\n LinePlot,\n MarkPlot,\n ResponsiveChartContainer,\n} from '@mui/x-charts';\nimport React, { FC, useCallback, useEffect, useState } from 'react';\nimport { formatCurrency, calculateBudgetAnalytics } from '../../api/functions';\nimport { colorList } from '../constants';\nimport { ColumnsChartComponentProps } from '../types';\n\nexport const ColumnsChartComponent: FC<ColumnsChartComponentProps> = ({\n granularity,\n granularitySetter,\n periods,\n costs,\n metrics,\n budgets,\n forecasts,\n height,\n highlightedItem,\n highlightedItemSetter,\n}) => {\n const theme = useTheme();\n const [costsSeries, setCostsSeries] = useState<any[] | undefined>(undefined);\n const [metricsSeries, setMetricsSeries] = useState<any[] | undefined>(undefined);\n const [showMetrics, setShowMetrics] = useState<boolean>(false);\n const [maxCostsYaxis, setMaxCostsYaxis] = useState<number | undefined>(undefined);\n\n // Helper: Calculate cost sums across all series\n const calculateCostSums = useCallback((costsData: any[]) => {\n const sums = [];\n for (const s of costsData) {\n for (let i = 0; i < s.data.length; i++) {\n if (sums[i] === undefined) {\n sums[i] = 0;\n }\n sums[i] += s.data[i];\n }\n }\n return sums;\n }, []);\n\n // Helper: Create base costs series\n const createBaseCostsSeries = useCallback((costsData: any[]) => {\n return costsData.map(s => ({\n id: s.name,\n data: s.data,\n type: 'bar' as const,\n label: `${s.name} Actual Spend`,\n yAxisId: 'costsAxis',\n valueFormatter: (value: number) => formatCurrency(value || 0),\n highlightScope: { highlight: 'series', fade: 'global' } as const,\n stack: 'stack1',\n stackOrder: 'descending' as const,\n }));\n }, []);\n\n // Helper: Build monthly costs lookup\n const buildMonthlyCosts = useCallback(\n (seriesData: number[]) => {\n const monthlyCosts: Record<string, number> = {};\n periods.forEach((period, index) => {\n monthlyCosts[period] = seriesData[index] || 0;\n });\n return monthlyCosts;\n },\n [periods],\n );\n\n // Helper: Create single projected series\n const createProjectedSeries = useCallback(\n (series: any, budget: any, forecast: any) => {\n const effectiveBudget = budget?.amount ? budget : { amount: 100000, provider: series.name };\n if (!effectiveBudget?.amount) return null;\n\n const monthlyCosts = buildMonthlyCosts(series.data);\n const analytics = calculateBudgetAnalytics(monthlyCosts, effectiveBudget.amount, forecast);\n\n const lastIndex = series.data.length - 1;\n const lastActualCost = lastIndex >= 0 ? series.data[lastIndex] : 0;\n const projectedDelta = analytics.projectedCurrentMonthCost - lastActualCost;\n\n if (lastIndex < 0 || projectedDelta <= 0) return null;\n\n const deltaData = series.data.map((_: any, i: number) => (i === lastIndex ? projectedDelta : 0));\n\n return {\n id: `${series.name}-projected`,\n data: deltaData,\n type: 'bar' as const,\n label: `${series.name} Forecast`,\n yAxisId: 'costsAxis',\n color: theme.palette.warning.main,\n valueFormatter: (value: number) => {\n if (value === 0) return null;\n return `${formatCurrency(projectedDelta)}`;\n },\n highlightScope: { highlight: 'series', fade: 'global' } as const,\n stack: 'stack1',\n stackOrder: 'descending' as const,\n };\n },\n [buildMonthlyCosts, theme.palette.warning.main],\n );\n\n // Helper: Create all projected delta series\n const createProjectedDeltaSeries = useCallback(\n (costsData: any[]) => {\n if (granularity !== 'monthly') return [];\n\n const projectedSeries: any[] = [];\n for (const s of costsData) {\n const budget = budgets?.find(b => b.provider.toLowerCase() === s.name.toLowerCase());\n const forecast = forecasts?.[s.name];\n const projectedData = createProjectedSeries(s, budget, forecast);\n\n if (projectedData) {\n projectedSeries.push(projectedData);\n }\n }\n return projectedSeries;\n },\n [granularity, budgets, forecasts, createProjectedSeries],\n );\n\n // Helper: Calculate maximum Y-axis value\n const calculateMaxYAxis = useCallback((baseSums: number[], projectedSeries: any[]) => {\n const allSums = [...baseSums];\n for (const deltaSeries of projectedSeries) {\n for (let i = 0; i < deltaSeries.data.length; i++) {\n if (deltaSeries.data[i] > 0) {\n allSums[i] = (allSums[i] || 0) + deltaSeries.data[i];\n }\n }\n }\n return Math.max(...allSums);\n }, []);\n\n // Helper: Create metrics series\n const createMetricsSeriesData = useCallback(() => {\n if (!metrics || !showMetrics) return undefined;\n\n return metrics.map(s => ({\n data: s.data,\n type: 'line' as const,\n label: s.name,\n curve: 'natural' as const,\n yAxisId: 'metricsAxis',\n highlightScope: { highlight: 'series', fade: 'global' } as const,\n showMark: granularity === 'monthly',\n }));\n }, [metrics, showMetrics, granularity]);\n\n const initChartCallback = useCallback(async () => {\n setCostsSeries(undefined);\n setMetricsSeries(undefined);\n\n if (costs) {\n const sums = calculateCostSums(costs);\n const baseCostsSeries = createBaseCostsSeries(costs);\n const projectedDeltaSeries = createProjectedDeltaSeries(costs);\n const maxYValue = calculateMaxYAxis(sums, projectedDeltaSeries);\n\n setMaxCostsYaxis(maxYValue);\n setCostsSeries([...baseCostsSeries, ...projectedDeltaSeries]);\n }\n\n const metricsData = createMetricsSeriesData();\n if (metricsData) {\n setMetricsSeries(metricsData);\n }\n }, [\n costs,\n calculateCostSums,\n createBaseCostsSeries,\n createProjectedDeltaSeries,\n calculateMaxYAxis,\n createMetricsSeriesData,\n ]);\n\n useEffect(() => {\n initChartCallback();\n }, [initChartCallback]);\n\n return (\n <Paper\n sx={{\n padding: '16px',\n display: 'flex',\n flexDirection: 'column',\n height: height ? height : 300,\n }}\n >\n <Grid container justifyContent=\"flex-end\" spacing={1}>\n <Grid item>Monthly</Grid>\n <Grid item>\n <Switch size=\"small\" onChange={event => granularitySetter(event.target.checked ? 'daily' : 'monthly')} />\n </Grid>\n <Grid item>Daily</Grid>\n <Grid item> | </Grid>\n <Grid item>\n <Switch size=\"small\" checked={showMetrics} onChange={_ => setShowMetrics((ori: boolean) => !ori)} />\n </Grid>\n <Grid item>Show Metrics</Grid>\n </Grid>\n {costs !== undefined && costsSeries !== undefined ? (\n <ResponsiveChartContainer\n margin={{\n bottom: 6 * costsSeries.length + 80,\n }}\n series={[...costsSeries, ...(metricsSeries ? metricsSeries : [])]}\n xAxis={[\n {\n data: periods,\n scaleType: 'band',\n },\n ]}\n yAxis={[\n {\n id: 'costsAxis',\n max: maxCostsYaxis,\n valueFormatter: value => formatCurrency(value),\n },\n {\n id: 'metricsAxis',\n },\n ]}\n colors={colorList}\n highlightedItem={highlightedItem ? { seriesId: highlightedItem } : null}\n onHighlightChange={highlighted => {\n highlightedItemSetter(highlighted?.seriesId);\n }}\n >\n <ChartsGrid horizontal />\n <BarPlot />\n <LinePlot />\n <MarkPlot />\n <LineHighlightPlot />\n <ChartsXAxis\n tickLabelStyle={{\n angle: periods.length > 12 ? -45 : 0,\n textAnchor: periods.length > 12 ? 'end' : 'middle',\n }}\n />\n <ChartsYAxis />\n <ChartsTooltip trigger=\"item\" />\n <ChartsLegend\n slots={{\n legend: props => {\n // keep legend items for costs only (from bar chart)\n const seriesToDisplay = [];\n for (const s of props.seriesToDisplay) {\n if (props.series.bar?.seriesOrder && props.series.bar.seriesOrder.indexOf(s.id) !== -1) {\n seriesToDisplay.push(s);\n }\n }\n\n return (\n <DefaultChartsLegend\n series={props.series}\n seriesToDisplay={seriesToDisplay}\n drawingArea={props.drawingArea}\n direction=\"row\"\n position={{ vertical: 'bottom', horizontal: 'middle' }}\n itemMarkHeight={10}\n itemMarkWidth={10}\n itemGap={costsSeries.length > 5 ? 5 : 10}\n labelStyle={{\n fontSize: '0.9em',\n }}\n onItemClick={(_, legendItem) => {\n // highlight the clicked item\n const clickedLegend = legendItem.seriesId;\n if (clickedLegend === highlightedItem) {\n highlightedItemSetter(undefined);\n } else {\n highlightedItemSetter(clickedLegend);\n }\n }}\n />\n );\n },\n }}\n />\n </ResponsiveChartContainer>\n ) : (\n <div style={{ width: '60%', margin: 'auto' }}>\n <Skeleton />\n <Skeleton />\n <Skeleton />\n </div>\n )}\n </Paper>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -89,6 +89,8 @@ const ReportsComponent = (props) => {
|
|
|
89
89
|
const [selectedTags, setSelectedTags] = useState(initialState.selectedTags);
|
|
90
90
|
const [reports, setReports] = useState(void 0);
|
|
91
91
|
const [metrics, setMetrics] = useState([]);
|
|
92
|
+
const [budgets, setBudgets] = useState([]);
|
|
93
|
+
const [forecasts, setForecasts] = useState({});
|
|
92
94
|
const [filters, setFilters] = useState(initialState.filters);
|
|
93
95
|
const [cloudProviderErrors, setCloudProviderErrors] = useState([]);
|
|
94
96
|
const [reportsAggregated, setReportsAggregated] = useState(void 0);
|
|
@@ -109,6 +111,7 @@ const ReportsComponent = (props) => {
|
|
|
109
111
|
if (reportsResponse.data) {
|
|
110
112
|
setReports(reportsResponse.data);
|
|
111
113
|
setPeriods(getPeriodStrings(granularity, monthRange.startMonth, monthRange.endMonth));
|
|
114
|
+
setForecasts(reportsResponse.forecasts || {});
|
|
112
115
|
}
|
|
113
116
|
if (reportsResponse.status === 207 && reportsResponse.errors) {
|
|
114
117
|
setCloudProviderErrors(reportsResponse.errors);
|
|
@@ -140,6 +143,17 @@ const ReportsComponent = (props) => {
|
|
|
140
143
|
fetchCostReportsCallback();
|
|
141
144
|
fetchMetricsCallback();
|
|
142
145
|
}, [fetchCostReportsCallback, fetchMetricsCallback]);
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
const fetchBudgets = async () => {
|
|
148
|
+
try {
|
|
149
|
+
const response = await infraWalletApi.getBudgets(params.name ?? "default");
|
|
150
|
+
setBudgets(response.data || []);
|
|
151
|
+
} catch (error) {
|
|
152
|
+
alertApi.post({ message: `Error fetching budgets: ${error}`, severity: "error" });
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
fetchBudgets();
|
|
156
|
+
}, [infraWalletApi, params.name, alertApi]);
|
|
143
157
|
useEffect(() => {
|
|
144
158
|
if (params.selectedView) {
|
|
145
159
|
switch (params.selectedView) {
|
|
@@ -239,6 +253,9 @@ const ReportsComponent = (props) => {
|
|
|
239
253
|
group: item.group,
|
|
240
254
|
data: rearrangeData(item, periods)
|
|
241
255
|
})),
|
|
256
|
+
budgets,
|
|
257
|
+
forecasts,
|
|
258
|
+
monthRange,
|
|
242
259
|
height: 450,
|
|
243
260
|
highlightedItem,
|
|
244
261
|
highlightedItemSetter: setHighlightedItem
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportsComponent.esm.js","sources":["../../../src/components/ReportsComponent/ReportsComponent.tsx"],"sourcesContent":["import { Content, Header, HeaderTabs, Page } from '@backstage/core-components';\nimport { alertApiRef, configApiRef, useApi } from '@backstage/core-plugin-api';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\nimport Accordion from '@mui/material/Accordion';\nimport AccordionDetails from '@mui/material/AccordionDetails';\nimport AccordionSummary from '@mui/material/AccordionSummary';\nimport Chip from '@mui/material/Chip';\nimport Grid from '@mui/material/Grid';\nimport Typography from '@mui/material/Typography';\nimport { addMonths, endOfMonth, startOfMonth } from 'date-fns';\nimport { default as React, useCallback, useEffect, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { infraWalletApiRef } from '../../api/InfraWalletApi';\nimport {\n aggregateCostReports,\n filterCostReports,\n getAllReportTags,\n getPeriodStrings,\n mergeCostReports,\n} from '../../api/functions';\nimport { CloudProviderError, Filters, Metric, Report, Tag } from '../../api/types';\nimport { useInfraWalletLuceneParams } from '../../hooks/useInfraWalletLuceneParams';\nimport { Budgets } from '../Budgets';\nimport { ColumnsChartComponent } from '../ColumnsChartComponent';\nimport { CostReportsTableComponent } from '../CostReportsTableComponent';\nimport { CustomCostsComponent } from '../CustomCostsComponent';\nimport { ErrorsAlertComponent } from '../ErrorsAlertComponent';\nimport { FiltersComponent } from '../FiltersComponent';\nimport { PieChartComponent } from '../PieChartComponent';\nimport { SettingsComponent } from '../SettingsComponent';\nimport { TopbarComponent } from '../TopbarComponent';\nimport { MonthRange } from '../types';\n\nexport interface ReportsComponentProps {\n title?: string;\n subTitle?: string;\n}\n\nconst getTotalCost = (report: Report): number => {\n let total = 0;\n Object.keys(report.reports).forEach((s: string) => {\n total += report.reports[s];\n });\n return total;\n};\n\nconst rearrangeData = (report: Report, periods: string[]): any[] => {\n const costs: any[] = [];\n periods.forEach((s: string) => {\n if (report.reports[s] !== undefined) {\n costs.push(report.reports[s]);\n } else {\n costs.push(null);\n }\n });\n return costs;\n};\n\nconst checkIfFiltersActivated = (filters: Filters): boolean => {\n let activated = false;\n Object.keys(filters).forEach((key: string) => {\n if (filters[key].length > 0) {\n activated = true;\n }\n });\n return activated;\n};\n\nexport const ReportsComponent = (props: ReportsComponentProps) => {\n const { title, subTitle } = props;\n const configApi = useApi(configApiRef);\n const params = useParams();\n\n let defaultGroupBy = configApi.getOptionalString('infraWallet.settings.defaultGroupBy') ?? 'none';\n const budgetsEnabled = configApi.getOptionalBoolean('infraWallet.settings.budgets.enabled') ?? true;\n const customCostsEnabled = configApi.getOptionalBoolean('infraWallet.settings.customCosts.enabled') ?? true;\n const businessMetricsEnabled = configApi.getOptionalBoolean('infraWallet.settings.businessMetrics.enabled') ?? true;\n const tabsToShow = ['Overview'];\n if (budgetsEnabled) {\n tabsToShow.push('Budgets');\n }\n if (customCostsEnabled) {\n tabsToShow.push('Custom Costs');\n }\n if (businessMetricsEnabled) {\n tabsToShow.push('Business Metrics');\n }\n // \"name\" is renamed to \"account\", make it backward compatibility\n if (defaultGroupBy === 'name') {\n defaultGroupBy = 'account';\n }\n\n const defaultShowLastXMonths = configApi.getOptionalNumber('infraWallet.settings.defaultShowLastXMonths') ?? 3;\n\n const MERGE_THRESHOLD = 8;\n\n // Initialize URL search params hook with defaults\n const defaultMonthRange: MonthRange = {\n startMonth: startOfMonth(addMonths(new Date(), defaultShowLastXMonths * -1 + 1)),\n endMonth: endOfMonth(new Date()),\n };\n\n const { getInitialState, updateUrlState, isInitialMount } = useInfraWalletLuceneParams({\n defaultFilters: {},\n defaultTags: [],\n defaultMonthRange,\n defaultGranularity: 'monthly',\n defaultAggregatedBy: defaultGroupBy,\n });\n\n // Get initial state from URL or defaults\n const initialState = getInitialState();\n\n const [selectedView, setSelectedView] = useState<string>('Overview');\n\n const [selectedTags, setSelectedTags] = useState<Tag[]>(initialState.selectedTags);\n const [reports, setReports] = useState<Report[] | undefined>(undefined);\n const [metrics, setMetrics] = useState<Metric[]>([]);\n const [filters, setFilters] = useState<Filters>(initialState.filters);\n const [cloudProviderErrors, setCloudProviderErrors] = useState<CloudProviderError[]>([]);\n const [reportsAggregated, setReportsAggregated] = useState<Report[] | undefined>(undefined);\n const [reportsAggregatedAndMerged, setReportsAggregatedAndMerged] = useState<Report[] | undefined>(undefined);\n const [reportTags, setReportTags] = useState<string[]>([]);\n const [granularity, setGranularity] = useState<string>(initialState.granularity);\n const [aggregatedBy, setAggregatedBy] = useState<string>(initialState.aggregatedBy);\n const [groups] = useState<string>('');\n const [monthRange, setMonthRange] = useState<MonthRange>(initialState.monthRange);\n const [periods, setPeriods] = useState<string[]>([]);\n const [highlightedItem, setHighlightedItem] = useState<string | undefined>(undefined);\n\n const alertApi = useApi(alertApiRef);\n const infraWalletApi = useApi(infraWalletApiRef);\n\n const fetchCostReportsCallback = useCallback(async () => {\n setReportsAggregated(undefined);\n setReportsAggregatedAndMerged(undefined);\n await infraWalletApi\n .getCostReports('', selectedTags, groups, granularity, monthRange.startMonth, monthRange.endMonth)\n .then(reportsResponse => {\n if (reportsResponse.data) {\n setReports(reportsResponse.data);\n setPeriods(getPeriodStrings(granularity, monthRange.startMonth, monthRange.endMonth));\n }\n if (reportsResponse.status === 207 && reportsResponse.errors) {\n setCloudProviderErrors(reportsResponse.errors);\n }\n })\n .catch(e => alertApi.post({ message: `${e.message}`, severity: 'error' }));\n }, [groups, monthRange, granularity, selectedTags, infraWalletApi, alertApi]);\n\n const fetchMetricsCallback = useCallback(async () => {\n await infraWalletApi\n .getMetrics(params.name ?? 'default', granularity, monthRange.startMonth, monthRange.endMonth)\n .then(metricsResponse => {\n if (metricsResponse.data && metricsResponse.data.length > 0) {\n setMetrics(metricsResponse.data);\n }\n if (metricsResponse.status === 207 && metricsResponse.errors) {\n setCloudProviderErrors(metricsResponse.errors);\n }\n })\n .catch(e => alertApi.post({ message: `${e.message}`, severity: 'error' }));\n }, [params.name, monthRange, granularity, infraWalletApi, alertApi]);\n\n useEffect(() => {\n if (reports !== undefined) {\n const filteredReports = filterCostReports(reports, filters);\n const aggregatedReports = aggregateCostReports(filteredReports, aggregatedBy);\n const aggregatedAndMergedReports = mergeCostReports(aggregatedReports, MERGE_THRESHOLD);\n const allTags = getAllReportTags(reports);\n setReportsAggregated(aggregatedReports);\n setReportsAggregatedAndMerged(aggregatedAndMergedReports);\n setReportTags(allTags);\n }\n }, [filters, reports, aggregatedBy, granularity, monthRange]);\n\n useEffect(() => {\n fetchCostReportsCallback();\n fetchMetricsCallback();\n }, [fetchCostReportsCallback, fetchMetricsCallback]);\n\n // provide a way for users to access these tabs, if they are configfured to be hidden\n useEffect(() => {\n if (params.selectedView) {\n switch (params.selectedView) {\n case 'budgets': {\n setSelectedView('Budgets');\n break;\n }\n case 'custom_costs': {\n setSelectedView('Custom Costs');\n break;\n }\n case 'business_metrics': {\n setSelectedView('Business Metrics');\n break;\n }\n default: {\n setSelectedView('Overview');\n break;\n }\n }\n }\n }, [params]);\n\n // Sync state changes to URL (skip initial mount to avoid overwriting URL params)\n useEffect(() => {\n if (!isInitialMount) {\n updateUrlState({ filters });\n }\n }, [filters, updateUrlState, isInitialMount]);\n\n useEffect(() => {\n if (!isInitialMount) {\n updateUrlState({ selectedTags });\n }\n }, [selectedTags, updateUrlState, isInitialMount]);\n\n useEffect(() => {\n if (!isInitialMount) {\n updateUrlState({ monthRange });\n }\n }, [monthRange, updateUrlState, isInitialMount]);\n\n useEffect(() => {\n if (!isInitialMount) {\n updateUrlState({ granularity });\n }\n }, [granularity, updateUrlState, isInitialMount]);\n\n useEffect(() => {\n if (!isInitialMount) {\n updateUrlState({ aggregatedBy });\n }\n }, [aggregatedBy, updateUrlState, isInitialMount]);\n\n return (\n <Page themeId=\"tool\">\n <Header title={title ?? 'InfraWallet'} subtitle={subTitle ?? ''} />\n <HeaderTabs\n tabs={tabsToShow.map(tab => {\n return { id: tab, label: tab };\n })}\n onChange={index => setSelectedView(tabsToShow[index])}\n />\n <Content>\n <Grid container spacing={3}>\n {cloudProviderErrors.length > 0 && (\n <Grid item xs={12}>\n <ErrorsAlertComponent errors={cloudProviderErrors} />\n </Grid>\n )}\n {selectedView === 'Overview' && (\n <>\n <Grid item xs={12}>\n <TopbarComponent\n aggregatedBy={aggregatedBy}\n aggregatedBySetter={setAggregatedBy}\n tags={reportTags}\n monthRange={monthRange}\n monthRangeSetter={setMonthRange}\n />\n </Grid>\n <Grid item xs={12}>\n <Accordion>\n <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls=\"filters-content\" id=\"filters-header\">\n <Typography>\n Filters {checkIfFiltersActivated(filters) && <Chip size=\"small\" label=\"active\" color=\"primary\" />}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <FiltersComponent\n reports={reports}\n filters={filters}\n monthRange={monthRange}\n filtersSetter={setFilters}\n selectedTags={selectedTags}\n selectedTagsSetter={setSelectedTags}\n providerErrorsSetter={setCloudProviderErrors}\n />\n </AccordionDetails>\n </Accordion>\n </Grid>\n <Grid item xs={12} md={4} lg={3}>\n <PieChartComponent\n categories={\n reportsAggregatedAndMerged ? reportsAggregatedAndMerged.map((item: any) => item.id) : undefined\n }\n series={\n reportsAggregatedAndMerged\n ? reportsAggregatedAndMerged.map((item: any) => getTotalCost(item))\n : undefined\n }\n height={450}\n highlightedItem={highlightedItem}\n highlightedItemSetter={setHighlightedItem}\n />\n </Grid>\n <Grid item xs={12} md={8} lg={9}>\n <ColumnsChartComponent\n granularity={granularity}\n granularitySetter={setGranularity}\n periods={periods}\n costs={\n reportsAggregatedAndMerged\n ? reportsAggregatedAndMerged.map((item: any) => ({\n name: item.id,\n data: rearrangeData(item, periods),\n }))\n : undefined\n }\n metrics={metrics.map((item: any) => ({\n name: item.name,\n group: item.group,\n data: rearrangeData(item, periods),\n }))}\n height={450}\n highlightedItem={highlightedItem}\n highlightedItemSetter={setHighlightedItem}\n />\n </Grid>\n <Grid item xs={12}>\n <CostReportsTableComponent reports={reportsAggregated} aggregatedBy={aggregatedBy} periods={periods} />\n </Grid>\n </>\n )}\n {selectedView === 'Budgets' && (\n <Grid item xs={12}>\n <Budgets providerErrorsSetter={setCloudProviderErrors} />\n </Grid>\n )}\n {selectedView === 'Custom Costs' && (\n <Grid item xs={12}>\n <CustomCostsComponent />\n </Grid>\n )}\n {selectedView === 'Business Metrics' && (\n <Grid item xs={12}>\n <SettingsComponent />\n </Grid>\n )}\n </Grid>\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ReportsComponent.esm.js","sources":["../../../src/components/ReportsComponent/ReportsComponent.tsx"],"sourcesContent":["import { Content, Header, HeaderTabs, Page } from '@backstage/core-components';\nimport { alertApiRef, configApiRef, useApi } from '@backstage/core-plugin-api';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\nimport Accordion from '@mui/material/Accordion';\nimport AccordionDetails from '@mui/material/AccordionDetails';\nimport AccordionSummary from '@mui/material/AccordionSummary';\nimport Chip from '@mui/material/Chip';\nimport Grid from '@mui/material/Grid';\nimport Typography from '@mui/material/Typography';\nimport { addMonths, endOfMonth, startOfMonth } from 'date-fns';\nimport { default as React, useCallback, useEffect, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { infraWalletApiRef } from '../../api/InfraWalletApi';\nimport {\n aggregateCostReports,\n filterCostReports,\n getAllReportTags,\n getPeriodStrings,\n mergeCostReports,\n} from '../../api/functions';\nimport { CloudProviderError, Filters, Metric, Report, Tag, Budget } from '../../api/types';\nimport { useInfraWalletLuceneParams } from '../../hooks/useInfraWalletLuceneParams';\nimport { Budgets } from '../Budgets';\nimport { ColumnsChartComponent } from '../ColumnsChartComponent';\nimport { CostReportsTableComponent } from '../CostReportsTableComponent';\nimport { CustomCostsComponent } from '../CustomCostsComponent';\nimport { ErrorsAlertComponent } from '../ErrorsAlertComponent';\nimport { FiltersComponent } from '../FiltersComponent';\nimport { PieChartComponent } from '../PieChartComponent';\nimport { SettingsComponent } from '../SettingsComponent';\nimport { TopbarComponent } from '../TopbarComponent';\nimport { MonthRange } from '../types';\n\nexport interface ReportsComponentProps {\n title?: string;\n subTitle?: string;\n}\n\nconst getTotalCost = (report: Report): number => {\n let total = 0;\n Object.keys(report.reports).forEach((s: string) => {\n total += report.reports[s];\n });\n return total;\n};\n\nconst rearrangeData = (report: Report, periods: string[]): any[] => {\n const costs: any[] = [];\n periods.forEach((s: string) => {\n if (report.reports[s] !== undefined) {\n costs.push(report.reports[s]);\n } else {\n costs.push(null);\n }\n });\n return costs;\n};\n\nconst checkIfFiltersActivated = (filters: Filters): boolean => {\n let activated = false;\n Object.keys(filters).forEach((key: string) => {\n if (filters[key].length > 0) {\n activated = true;\n }\n });\n return activated;\n};\n\nexport const ReportsComponent = (props: ReportsComponentProps) => {\n const { title, subTitle } = props;\n const configApi = useApi(configApiRef);\n const params = useParams();\n\n let defaultGroupBy = configApi.getOptionalString('infraWallet.settings.defaultGroupBy') ?? 'none';\n const budgetsEnabled = configApi.getOptionalBoolean('infraWallet.settings.budgets.enabled') ?? true;\n const customCostsEnabled = configApi.getOptionalBoolean('infraWallet.settings.customCosts.enabled') ?? true;\n const businessMetricsEnabled = configApi.getOptionalBoolean('infraWallet.settings.businessMetrics.enabled') ?? true;\n const tabsToShow = ['Overview'];\n if (budgetsEnabled) {\n tabsToShow.push('Budgets');\n }\n if (customCostsEnabled) {\n tabsToShow.push('Custom Costs');\n }\n if (businessMetricsEnabled) {\n tabsToShow.push('Business Metrics');\n }\n // \"name\" is renamed to \"account\", make it backward compatibility\n if (defaultGroupBy === 'name') {\n defaultGroupBy = 'account';\n }\n\n const defaultShowLastXMonths = configApi.getOptionalNumber('infraWallet.settings.defaultShowLastXMonths') ?? 3;\n\n const MERGE_THRESHOLD = 8;\n\n // Initialize URL search params hook with defaults\n const defaultMonthRange: MonthRange = {\n startMonth: startOfMonth(addMonths(new Date(), defaultShowLastXMonths * -1 + 1)),\n endMonth: endOfMonth(new Date()),\n };\n\n const { getInitialState, updateUrlState, isInitialMount } = useInfraWalletLuceneParams({\n defaultFilters: {},\n defaultTags: [],\n defaultMonthRange,\n defaultGranularity: 'monthly',\n defaultAggregatedBy: defaultGroupBy,\n });\n\n // Get initial state from URL or defaults\n const initialState = getInitialState();\n\n const [selectedView, setSelectedView] = useState<string>('Overview');\n\n const [selectedTags, setSelectedTags] = useState<Tag[]>(initialState.selectedTags);\n const [reports, setReports] = useState<Report[] | undefined>(undefined);\n const [metrics, setMetrics] = useState<Metric[]>([]);\n const [budgets, setBudgets] = useState<Budget[]>([]);\n const [forecasts, setForecasts] = useState<Record<string, number>>({});\n const [filters, setFilters] = useState<Filters>(initialState.filters);\n const [cloudProviderErrors, setCloudProviderErrors] = useState<CloudProviderError[]>([]);\n const [reportsAggregated, setReportsAggregated] = useState<Report[] | undefined>(undefined);\n const [reportsAggregatedAndMerged, setReportsAggregatedAndMerged] = useState<Report[] | undefined>(undefined);\n const [reportTags, setReportTags] = useState<string[]>([]);\n const [granularity, setGranularity] = useState<string>(initialState.granularity);\n const [aggregatedBy, setAggregatedBy] = useState<string>(initialState.aggregatedBy);\n const [groups] = useState<string>('');\n const [monthRange, setMonthRange] = useState<MonthRange>(initialState.monthRange);\n const [periods, setPeriods] = useState<string[]>([]);\n const [highlightedItem, setHighlightedItem] = useState<string | undefined>(undefined);\n\n const alertApi = useApi(alertApiRef);\n const infraWalletApi = useApi(infraWalletApiRef);\n\n const fetchCostReportsCallback = useCallback(async () => {\n setReportsAggregated(undefined);\n setReportsAggregatedAndMerged(undefined);\n await infraWalletApi\n .getCostReports('', selectedTags, groups, granularity, monthRange.startMonth, monthRange.endMonth)\n .then(reportsResponse => {\n if (reportsResponse.data) {\n setReports(reportsResponse.data);\n setPeriods(getPeriodStrings(granularity, monthRange.startMonth, monthRange.endMonth));\n setForecasts(reportsResponse.forecasts || {});\n }\n if (reportsResponse.status === 207 && reportsResponse.errors) {\n setCloudProviderErrors(reportsResponse.errors);\n }\n })\n .catch(e => alertApi.post({ message: `${e.message}`, severity: 'error' }));\n }, [groups, monthRange, granularity, selectedTags, infraWalletApi, alertApi]);\n\n const fetchMetricsCallback = useCallback(async () => {\n await infraWalletApi\n .getMetrics(params.name ?? 'default', granularity, monthRange.startMonth, monthRange.endMonth)\n .then(metricsResponse => {\n if (metricsResponse.data && metricsResponse.data.length > 0) {\n setMetrics(metricsResponse.data);\n }\n if (metricsResponse.status === 207 && metricsResponse.errors) {\n setCloudProviderErrors(metricsResponse.errors);\n }\n })\n .catch(e => alertApi.post({ message: `${e.message}`, severity: 'error' }));\n }, [params.name, monthRange, granularity, infraWalletApi, alertApi]);\n\n useEffect(() => {\n if (reports !== undefined) {\n const filteredReports = filterCostReports(reports, filters);\n const aggregatedReports = aggregateCostReports(filteredReports, aggregatedBy);\n const aggregatedAndMergedReports = mergeCostReports(aggregatedReports, MERGE_THRESHOLD);\n const allTags = getAllReportTags(reports);\n setReportsAggregated(aggregatedReports);\n setReportsAggregatedAndMerged(aggregatedAndMergedReports);\n setReportTags(allTags);\n }\n }, [filters, reports, aggregatedBy, granularity, monthRange]);\n\n useEffect(() => {\n fetchCostReportsCallback();\n fetchMetricsCallback();\n }, [fetchCostReportsCallback, fetchMetricsCallback]);\n\n useEffect(() => {\n const fetchBudgets = async () => {\n try {\n const response = await infraWalletApi.getBudgets(params.name ?? 'default');\n setBudgets(response.data || []);\n } catch (error) {\n alertApi.post({ message: `Error fetching budgets: ${error}`, severity: 'error' });\n }\n };\n fetchBudgets();\n }, [infraWalletApi, params.name, alertApi]);\n\n // provide a way for users to access these tabs, if they are configfured to be hidden\n useEffect(() => {\n if (params.selectedView) {\n switch (params.selectedView) {\n case 'budgets': {\n setSelectedView('Budgets');\n break;\n }\n case 'custom_costs': {\n setSelectedView('Custom Costs');\n break;\n }\n case 'business_metrics': {\n setSelectedView('Business Metrics');\n break;\n }\n default: {\n setSelectedView('Overview');\n break;\n }\n }\n }\n }, [params]);\n\n // Sync state changes to URL (skip initial mount to avoid overwriting URL params)\n useEffect(() => {\n if (!isInitialMount) {\n updateUrlState({ filters });\n }\n }, [filters, updateUrlState, isInitialMount]);\n\n useEffect(() => {\n if (!isInitialMount) {\n updateUrlState({ selectedTags });\n }\n }, [selectedTags, updateUrlState, isInitialMount]);\n\n useEffect(() => {\n if (!isInitialMount) {\n updateUrlState({ monthRange });\n }\n }, [monthRange, updateUrlState, isInitialMount]);\n\n useEffect(() => {\n if (!isInitialMount) {\n updateUrlState({ granularity });\n }\n }, [granularity, updateUrlState, isInitialMount]);\n\n useEffect(() => {\n if (!isInitialMount) {\n updateUrlState({ aggregatedBy });\n }\n }, [aggregatedBy, updateUrlState, isInitialMount]);\n\n return (\n <Page themeId=\"tool\">\n <Header title={title ?? 'InfraWallet'} subtitle={subTitle ?? ''} />\n <HeaderTabs\n tabs={tabsToShow.map(tab => {\n return { id: tab, label: tab };\n })}\n onChange={index => setSelectedView(tabsToShow[index])}\n />\n <Content>\n <Grid container spacing={3}>\n {cloudProviderErrors.length > 0 && (\n <Grid item xs={12}>\n <ErrorsAlertComponent errors={cloudProviderErrors} />\n </Grid>\n )}\n {selectedView === 'Overview' && (\n <>\n <Grid item xs={12}>\n <TopbarComponent\n aggregatedBy={aggregatedBy}\n aggregatedBySetter={setAggregatedBy}\n tags={reportTags}\n monthRange={monthRange}\n monthRangeSetter={setMonthRange}\n />\n </Grid>\n <Grid item xs={12}>\n <Accordion>\n <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls=\"filters-content\" id=\"filters-header\">\n <Typography>\n Filters {checkIfFiltersActivated(filters) && <Chip size=\"small\" label=\"active\" color=\"primary\" />}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <FiltersComponent\n reports={reports}\n filters={filters}\n monthRange={monthRange}\n filtersSetter={setFilters}\n selectedTags={selectedTags}\n selectedTagsSetter={setSelectedTags}\n providerErrorsSetter={setCloudProviderErrors}\n />\n </AccordionDetails>\n </Accordion>\n </Grid>\n <Grid item xs={12} md={4} lg={3}>\n <PieChartComponent\n categories={\n reportsAggregatedAndMerged ? reportsAggregatedAndMerged.map((item: any) => item.id) : undefined\n }\n series={\n reportsAggregatedAndMerged\n ? reportsAggregatedAndMerged.map((item: any) => getTotalCost(item))\n : undefined\n }\n height={450}\n highlightedItem={highlightedItem}\n highlightedItemSetter={setHighlightedItem}\n />\n </Grid>\n <Grid item xs={12} md={8} lg={9}>\n <ColumnsChartComponent\n granularity={granularity}\n granularitySetter={setGranularity}\n periods={periods}\n costs={\n reportsAggregatedAndMerged\n ? reportsAggregatedAndMerged.map((item: any) => ({\n name: item.id,\n data: rearrangeData(item, periods),\n }))\n : undefined\n }\n metrics={metrics.map((item: any) => ({\n name: item.name,\n group: item.group,\n data: rearrangeData(item, periods),\n }))}\n budgets={budgets}\n forecasts={forecasts}\n monthRange={monthRange}\n height={450}\n highlightedItem={highlightedItem}\n highlightedItemSetter={setHighlightedItem}\n />\n </Grid>\n <Grid item xs={12}>\n <CostReportsTableComponent reports={reportsAggregated} aggregatedBy={aggregatedBy} periods={periods} />\n </Grid>\n </>\n )}\n {selectedView === 'Budgets' && (\n <Grid item xs={12}>\n <Budgets providerErrorsSetter={setCloudProviderErrors} />\n </Grid>\n )}\n {selectedView === 'Custom Costs' && (\n <Grid item xs={12}>\n <CustomCostsComponent />\n </Grid>\n )}\n {selectedView === 'Business Metrics' && (\n <Grid item xs={12}>\n <SettingsComponent />\n </Grid>\n )}\n </Grid>\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|