@electrolux-oss/plugin-infrawallet 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +258 -0
- package/dist/api/InfraWalletApi.esm.js +8 -0
- package/dist/api/InfraWalletApi.esm.js.map +1 -0
- package/dist/api/InfraWalletApiClient.esm.js +89 -0
- package/dist/api/InfraWalletApiClient.esm.js.map +1 -0
- package/dist/api/functions.esm.js +100 -0
- package/dist/api/functions.esm.js.map +1 -0
- package/dist/components/ColumnsChartComponent/ColumnsChartComponent.esm.js +168 -0
- package/dist/components/ColumnsChartComponent/ColumnsChartComponent.esm.js.map +1 -0
- package/dist/components/CostReportsTableComponent/CostReportsTableComponent.esm.js +144 -0
- package/dist/components/CostReportsTableComponent/CostReportsTableComponent.esm.js.map +1 -0
- package/dist/components/CostReportsTableComponent/TrendBarComponent.esm.js +48 -0
- package/dist/components/CostReportsTableComponent/TrendBarComponent.esm.js.map +1 -0
- package/dist/components/PieChartComponent/PieChartComponent.esm.js +134 -0
- package/dist/components/PieChartComponent/PieChartComponent.esm.js.map +1 -0
- package/dist/components/ReportsComponent/ReportsComponent.esm.js +126 -0
- package/dist/components/ReportsComponent/ReportsComponent.esm.js.map +1 -0
- package/dist/components/TopbarComponent/TopbarComponent.esm.js +93 -0
- package/dist/components/TopbarComponent/TopbarComponent.esm.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/plugin.esm.js +28 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/routes.esm.js +12 -0
- package/dist/routes.esm.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import Typography from '@material-ui/core/Typography';
|
|
2
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
3
|
+
import Box from '@mui/material/Box';
|
|
4
|
+
import { DataGrid } from '@mui/x-data-grid';
|
|
5
|
+
import humanFormat from 'human-format';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { getPreviousMonth } from '../../api/functions.esm.js';
|
|
8
|
+
import { TrendBarComponent } from './TrendBarComponent.esm.js';
|
|
9
|
+
|
|
10
|
+
const useStyles = makeStyles({
|
|
11
|
+
increase: {
|
|
12
|
+
color: "red"
|
|
13
|
+
},
|
|
14
|
+
decrease: {
|
|
15
|
+
color: "green"
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const CostReportsTableComponent = ({
|
|
19
|
+
reports,
|
|
20
|
+
aggregatedBy
|
|
21
|
+
}) => {
|
|
22
|
+
const classes = useStyles();
|
|
23
|
+
const customScale = humanFormat.Scale.create(["", "K", "M", "B"], 1e3);
|
|
24
|
+
const periods = Object.keys(reports[0].reports);
|
|
25
|
+
const columns = [
|
|
26
|
+
{
|
|
27
|
+
field: aggregatedBy,
|
|
28
|
+
headerName: aggregatedBy.toLocaleUpperCase("en-US"),
|
|
29
|
+
minWidth: 200,
|
|
30
|
+
flex: 2,
|
|
31
|
+
renderCell: (params) => {
|
|
32
|
+
return /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, params.formattedValue);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
field: "TREND",
|
|
37
|
+
headerName: "TREND",
|
|
38
|
+
width: 100,
|
|
39
|
+
renderCell: (params) => {
|
|
40
|
+
return /* @__PURE__ */ React.createElement(
|
|
41
|
+
TrendBarComponent,
|
|
42
|
+
{
|
|
43
|
+
categories: Object.keys(params.row.reports),
|
|
44
|
+
series: [
|
|
45
|
+
{
|
|
46
|
+
name: params.row.id,
|
|
47
|
+
data: periods.map(
|
|
48
|
+
(period) => params.row.reports[period] !== void 0 ? params.row.reports[period] : null
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
];
|
|
57
|
+
periods.forEach((period) => {
|
|
58
|
+
columns.push({
|
|
59
|
+
field: period,
|
|
60
|
+
headerName: period,
|
|
61
|
+
type: "number",
|
|
62
|
+
minWidth: 150,
|
|
63
|
+
flex: 1,
|
|
64
|
+
valueGetter: (_, row) => {
|
|
65
|
+
return row.reports[period] ? row.reports[period] : null;
|
|
66
|
+
},
|
|
67
|
+
valueFormatter: (value, row, column) => {
|
|
68
|
+
if (typeof value === "number") {
|
|
69
|
+
const previousPeriod = getPreviousMonth(column.field);
|
|
70
|
+
const formattedValue = humanFormat(value, {
|
|
71
|
+
scale: customScale,
|
|
72
|
+
separator: ""
|
|
73
|
+
});
|
|
74
|
+
if (previousPeriod in row.reports && row.reports[previousPeriod] > 0) {
|
|
75
|
+
const diff = row.reports[column.field] - row.reports[previousPeriod];
|
|
76
|
+
const percentage = diff / row.reports[previousPeriod] * 100;
|
|
77
|
+
const mark = diff > 0 ? "+" : "";
|
|
78
|
+
return `$${formattedValue} (${mark}${percentage.toFixed(2)}%)`;
|
|
79
|
+
}
|
|
80
|
+
return `$${formattedValue}`;
|
|
81
|
+
}
|
|
82
|
+
return "-";
|
|
83
|
+
},
|
|
84
|
+
renderCell: (params) => {
|
|
85
|
+
let className = "";
|
|
86
|
+
const percentageIndex = params.formattedValue.indexOf("(");
|
|
87
|
+
const costStr = percentageIndex === -1 ? params.formattedValue : params.formattedValue.substring(0, percentageIndex);
|
|
88
|
+
const percentageStr = percentageIndex === -1 ? "" : params.formattedValue.substring(percentageIndex);
|
|
89
|
+
if (percentageStr.includes("-")) {
|
|
90
|
+
className = classes.decrease;
|
|
91
|
+
} else if (percentageStr.includes("+")) {
|
|
92
|
+
className = classes.increase;
|
|
93
|
+
}
|
|
94
|
+
return /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, costStr, /* @__PURE__ */ React.createElement(Typography, { variant: "inherit", className }, percentageStr));
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
columns.push({
|
|
99
|
+
field: "TOTAL",
|
|
100
|
+
headerName: "TOTAL",
|
|
101
|
+
type: "number",
|
|
102
|
+
minWidth: 150,
|
|
103
|
+
flex: 1,
|
|
104
|
+
valueGetter: (_, row) => {
|
|
105
|
+
let total = 0;
|
|
106
|
+
periods.forEach((period) => {
|
|
107
|
+
total += row.reports[period] ? row.reports[period] : 0;
|
|
108
|
+
});
|
|
109
|
+
return total;
|
|
110
|
+
},
|
|
111
|
+
valueFormatter: (value) => {
|
|
112
|
+
if (typeof value === "number") {
|
|
113
|
+
return `$${humanFormat(value, { scale: customScale, separator: "" })}`;
|
|
114
|
+
}
|
|
115
|
+
return "-";
|
|
116
|
+
},
|
|
117
|
+
renderCell: (params) => {
|
|
118
|
+
return /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, params.formattedValue);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
|
|
122
|
+
DataGrid,
|
|
123
|
+
{
|
|
124
|
+
rows: reports,
|
|
125
|
+
rowHeight: 35,
|
|
126
|
+
columns,
|
|
127
|
+
initialState: {
|
|
128
|
+
sorting: {
|
|
129
|
+
sortModel: [{ field: "TOTAL", sort: "desc" }]
|
|
130
|
+
},
|
|
131
|
+
pagination: {
|
|
132
|
+
paginationModel: {
|
|
133
|
+
pageSize: 15
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
pageSizeOptions: [5, 15],
|
|
138
|
+
disableRowSelectionOnClick: true
|
|
139
|
+
}
|
|
140
|
+
));
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export { CostReportsTableComponent };
|
|
144
|
+
//# sourceMappingURL=CostReportsTableComponent.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CostReportsTableComponent.esm.js","sources":["../../../src/components/CostReportsTableComponent/CostReportsTableComponent.tsx"],"sourcesContent":["import Typography from '@material-ui/core/Typography';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Box from '@mui/material/Box';\nimport { DataGrid, GridColDef, GridRenderCellParams } from '@mui/x-data-grid';\nimport humanFormat from 'human-format';\nimport React, { FC } from 'react';\nimport { getPreviousMonth } from '../../api/functions';\nimport { CostReportsTableComponentProps } from '../types';\nimport { TrendBarComponent } from './TrendBarComponent';\n\nconst useStyles = makeStyles({\n increase: {\n color: 'red',\n },\n decrease: {\n color: 'green',\n },\n});\n\nexport const CostReportsTableComponent: FC<CostReportsTableComponentProps> = ({\n reports,\n aggregatedBy,\n}) => {\n const classes = useStyles();\n const customScale = humanFormat.Scale.create(['', 'K', 'M', 'B'], 1000);\n const periods = Object.keys(reports[0].reports);\n const columns: GridColDef[] = [\n {\n field: aggregatedBy,\n headerName: aggregatedBy.toLocaleUpperCase('en-US'),\n minWidth: 200,\n flex: 2,\n renderCell: (params: GridRenderCellParams): React.ReactNode => {\n return <Typography variant=\"body2\">{params.formattedValue}</Typography>;\n },\n },\n {\n field: 'TREND',\n headerName: 'TREND',\n width: 100,\n renderCell: (params: GridRenderCellParams): React.ReactNode => {\n return (\n <TrendBarComponent\n categories={Object.keys(params.row.reports)}\n series={[\n {\n name: params.row.id,\n data: periods.map(period =>\n params.row.reports[period] !== undefined\n ? params.row.reports[period]\n : null,\n ),\n },\n ]}\n />\n );\n },\n },\n ];\n\n periods.forEach(period => {\n columns.push({\n field: period,\n headerName: period,\n type: 'number',\n minWidth: 150,\n flex: 1,\n valueGetter: (_, row) => {\n return row.reports[period] ? row.reports[period] : null;\n },\n valueFormatter: (value, row, column) => {\n if (typeof value === 'number') {\n const previousPeriod = getPreviousMonth(column.field);\n const formattedValue = humanFormat(value, {\n scale: customScale,\n separator: '',\n });\n if (\n previousPeriod in row.reports &&\n row.reports[previousPeriod] > 0\n ) {\n const diff =\n row.reports[column.field] - row.reports[previousPeriod];\n const percentage = (diff / row.reports[previousPeriod]) * 100;\n const mark = diff > 0 ? '+' : '';\n return `$${formattedValue} (${mark}${percentage.toFixed(2)}%)`;\n }\n return `$${formattedValue}`;\n }\n return '-';\n },\n renderCell: (params: GridRenderCellParams): React.ReactNode => {\n let className = '';\n const percentageIndex = params.formattedValue.indexOf('(');\n const costStr =\n percentageIndex === -1\n ? params.formattedValue\n : params.formattedValue.substring(0, percentageIndex);\n const percentageStr =\n percentageIndex === -1\n ? ''\n : params.formattedValue.substring(percentageIndex);\n if (percentageStr.includes('-')) {\n className = classes.decrease;\n } else if (percentageStr.includes('+')) {\n className = classes.increase;\n }\n\n return (\n <Typography variant=\"body2\">\n {costStr}\n <Typography variant=\"inherit\" className={className}>\n {percentageStr}\n </Typography>\n </Typography>\n );\n },\n });\n });\n\n columns.push({\n field: 'TOTAL',\n headerName: 'TOTAL',\n type: 'number',\n minWidth: 150,\n flex: 1,\n valueGetter: (_, row) => {\n let total = 0;\n periods.forEach(period => {\n total += row.reports[period] ? row.reports[period] : 0;\n });\n return total;\n },\n valueFormatter: value => {\n if (typeof value === 'number') {\n return `$${humanFormat(value, { scale: customScale, separator: '' })}`;\n }\n return '-';\n },\n renderCell: (params: GridRenderCellParams): React.ReactNode => {\n return <Typography variant=\"body2\">{params.formattedValue}</Typography>;\n },\n });\n\n return (\n <Box>\n <DataGrid\n rows={reports}\n rowHeight={35}\n columns={columns}\n initialState={{\n sorting: {\n sortModel: [{ field: 'TOTAL', sort: 'desc' }],\n },\n pagination: {\n paginationModel: {\n pageSize: 15,\n },\n },\n }}\n pageSizeOptions={[5, 15]}\n disableRowSelectionOnClick\n />\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box } from '@material-ui/core';
|
|
3
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
4
|
+
import Chart from 'react-apexcharts';
|
|
5
|
+
|
|
6
|
+
const TrendBarComponent = ({
|
|
7
|
+
categories,
|
|
8
|
+
series,
|
|
9
|
+
height,
|
|
10
|
+
width
|
|
11
|
+
}) => {
|
|
12
|
+
const useStyles = makeStyles({
|
|
13
|
+
fixedBox: {
|
|
14
|
+
display: "flex",
|
|
15
|
+
height: height ? height : 25,
|
|
16
|
+
width: width ? width : 100
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const classes = useStyles();
|
|
20
|
+
const options = {
|
|
21
|
+
chart: {
|
|
22
|
+
width: width ? width : 100,
|
|
23
|
+
type: "bar",
|
|
24
|
+
animations: {
|
|
25
|
+
enabled: false
|
|
26
|
+
},
|
|
27
|
+
zoom: {
|
|
28
|
+
enabled: false
|
|
29
|
+
},
|
|
30
|
+
toolbar: {
|
|
31
|
+
show: false
|
|
32
|
+
},
|
|
33
|
+
sparkline: {
|
|
34
|
+
enabled: true
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
tooltip: {
|
|
38
|
+
enabled: false
|
|
39
|
+
},
|
|
40
|
+
xaxis: {
|
|
41
|
+
categories
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
return /* @__PURE__ */ React.createElement(Box, { className: classes.fixedBox }, /* @__PURE__ */ React.createElement(Chart, { options, series, type: "bar", height: "100%" }));
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export { TrendBarComponent };
|
|
48
|
+
//# sourceMappingURL=TrendBarComponent.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TrendBarComponent.esm.js","sources":["../../../src/components/CostReportsTableComponent/TrendBarComponent.tsx"],"sourcesContent":["import React, { FC } from 'react';\nimport { Box } from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { TrendBarComponentProps } from '../types';\nimport Chart from 'react-apexcharts';\nimport { ApexOptions } from 'apexcharts';\n\nexport const TrendBarComponent: FC<TrendBarComponentProps> = ({\n categories,\n series,\n height,\n width,\n}) => {\n const useStyles = makeStyles({\n fixedBox: {\n display: 'flex',\n height: height ? height : 25,\n width: width ? width : 100,\n },\n });\n const classes = useStyles();\n\n const options: ApexOptions = {\n chart: {\n width: width ? width : 100,\n type: 'bar',\n animations: {\n enabled: false,\n },\n zoom: {\n enabled: false,\n },\n toolbar: {\n show: false,\n },\n sparkline: {\n enabled: true,\n },\n },\n tooltip: {\n enabled: false,\n },\n xaxis: {\n categories: categories,\n },\n };\n\n return (\n <Box className={classes.fixedBox}>\n <Chart options={options} series={series} type=\"bar\" height=\"100%\" />\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;AAOO,MAAM,oBAAgD,CAAC;AAAA,EAC5D,UAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AACF,CAAM,KAAA;AACJ,EAAA,MAAM,YAAY,UAAW,CAAA;AAAA,IAC3B,QAAU,EAAA;AAAA,MACR,OAAS,EAAA,MAAA;AAAA,MACT,MAAA,EAAQ,SAAS,MAAS,GAAA,EAAA;AAAA,MAC1B,KAAA,EAAO,QAAQ,KAAQ,GAAA,GAAA;AAAA,KACzB;AAAA,GACD,CAAA,CAAA;AACD,EAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAE1B,EAAA,MAAM,OAAuB,GAAA;AAAA,IAC3B,KAAO,EAAA;AAAA,MACL,KAAA,EAAO,QAAQ,KAAQ,GAAA,GAAA;AAAA,MACvB,IAAM,EAAA,KAAA;AAAA,MACN,UAAY,EAAA;AAAA,QACV,OAAS,EAAA,KAAA;AAAA,OACX;AAAA,MACA,IAAM,EAAA;AAAA,QACJ,OAAS,EAAA,KAAA;AAAA,OACX;AAAA,MACA,OAAS,EAAA;AAAA,QACP,IAAM,EAAA,KAAA;AAAA,OACR;AAAA,MACA,SAAW,EAAA;AAAA,QACT,OAAS,EAAA,IAAA;AAAA,OACX;AAAA,KACF;AAAA,IACA,OAAS,EAAA;AAAA,MACP,OAAS,EAAA,KAAA;AAAA,KACX;AAAA,IACA,KAAO,EAAA;AAAA,MACL,UAAA;AAAA,KACF;AAAA,GACF,CAAA;AAEA,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,QACtB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,KAAM,EAAA,EAAA,OAAA,EAAkB,MAAgB,EAAA,IAAA,EAAK,KAAM,EAAA,MAAA,EAAO,QAAO,CACpE,CAAA,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { Paper } from '@material-ui/core';
|
|
2
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
3
|
+
import humanFormat from 'human-format';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import Chart from 'react-apexcharts';
|
|
6
|
+
|
|
7
|
+
const PieChartComponent = ({
|
|
8
|
+
categories,
|
|
9
|
+
series,
|
|
10
|
+
height
|
|
11
|
+
}) => {
|
|
12
|
+
const useStyles = makeStyles({
|
|
13
|
+
fixedHeightPaper: {
|
|
14
|
+
paddingTop: "10px",
|
|
15
|
+
overflow: "hidden",
|
|
16
|
+
height: height ? height : 300
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const classes = useStyles();
|
|
20
|
+
const customScale = humanFormat.Scale.create(["", "K", "M", "B"], 1e3);
|
|
21
|
+
const state = {
|
|
22
|
+
options: {
|
|
23
|
+
chart: {
|
|
24
|
+
animations: {
|
|
25
|
+
enabled: false
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
legend: {
|
|
29
|
+
show: false
|
|
30
|
+
},
|
|
31
|
+
labels: categories,
|
|
32
|
+
dataLabels: {
|
|
33
|
+
enabled: true,
|
|
34
|
+
formatter: (value, { seriesIndex, dataPointIndex, w }) => {
|
|
35
|
+
return `${w.config.labels[seriesIndex]} (${value.toFixed(0)}%)`;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
tooltip: {
|
|
39
|
+
y: {
|
|
40
|
+
formatter: (value) => {
|
|
41
|
+
return `$${humanFormat(value, {
|
|
42
|
+
scale: customScale,
|
|
43
|
+
separator: ""
|
|
44
|
+
})}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
plotOptions: {
|
|
49
|
+
pie: {
|
|
50
|
+
donut: {
|
|
51
|
+
labels: {
|
|
52
|
+
show: true,
|
|
53
|
+
value: {
|
|
54
|
+
formatter: (val) => {
|
|
55
|
+
const floatVal = parseFloat(val);
|
|
56
|
+
return `$${humanFormat(floatVal, {
|
|
57
|
+
scale: customScale,
|
|
58
|
+
separator: ""
|
|
59
|
+
})}`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
// there are only 5 colors by default, here we extend it to 50 different colors
|
|
67
|
+
colors: [
|
|
68
|
+
"#008FFB",
|
|
69
|
+
"#00E396",
|
|
70
|
+
"#FEB019",
|
|
71
|
+
"#FF4560",
|
|
72
|
+
"#775DD0",
|
|
73
|
+
"#3F51B5",
|
|
74
|
+
"#03A9F4",
|
|
75
|
+
"#4CAF50",
|
|
76
|
+
"#F9CE1D",
|
|
77
|
+
"#FF9800",
|
|
78
|
+
"#33B2DF",
|
|
79
|
+
"#546E7A",
|
|
80
|
+
"#D4526E",
|
|
81
|
+
"#13D8AA",
|
|
82
|
+
"#A5978B",
|
|
83
|
+
"#4ECDC4",
|
|
84
|
+
"#C7F464",
|
|
85
|
+
"#81D4FA",
|
|
86
|
+
"#546E7A",
|
|
87
|
+
"#FD6A6A",
|
|
88
|
+
"#2B908F",
|
|
89
|
+
"#F9A3A4",
|
|
90
|
+
"#90EE7E",
|
|
91
|
+
"#FA4443",
|
|
92
|
+
"#69D2E7",
|
|
93
|
+
"#449DD1",
|
|
94
|
+
"#F86624",
|
|
95
|
+
"#EA3546",
|
|
96
|
+
"#662E9B",
|
|
97
|
+
"#C5D86D",
|
|
98
|
+
"#D7263D",
|
|
99
|
+
"#1B998B",
|
|
100
|
+
"#2E294E",
|
|
101
|
+
"#F46036",
|
|
102
|
+
"#E2C044",
|
|
103
|
+
"#662E9B",
|
|
104
|
+
"#F86624",
|
|
105
|
+
"#F9C80E",
|
|
106
|
+
"#EA3546",
|
|
107
|
+
"#43BCCD",
|
|
108
|
+
"#5C4742",
|
|
109
|
+
"#A5978B",
|
|
110
|
+
"#8D5B4C",
|
|
111
|
+
"#5A2A27",
|
|
112
|
+
"#C4BBAF",
|
|
113
|
+
"#A300D6",
|
|
114
|
+
"#7D02EB",
|
|
115
|
+
"#5653FE",
|
|
116
|
+
"#2983FF",
|
|
117
|
+
"#00B1F2"
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
series
|
|
121
|
+
};
|
|
122
|
+
return /* @__PURE__ */ React.createElement(Paper, { className: classes.fixedHeightPaper }, /* @__PURE__ */ React.createElement(
|
|
123
|
+
Chart,
|
|
124
|
+
{
|
|
125
|
+
options: state.options,
|
|
126
|
+
series: state.series,
|
|
127
|
+
type: "donut",
|
|
128
|
+
height: height ? height : 300
|
|
129
|
+
}
|
|
130
|
+
));
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export { PieChartComponent };
|
|
134
|
+
//# sourceMappingURL=PieChartComponent.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PieChartComponent.esm.js","sources":["../../../src/components/PieChartComponent/PieChartComponent.tsx"],"sourcesContent":["import { Paper } from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\nimport humanFormat from 'human-format';\nimport React, { FC } from 'react';\nimport Chart from 'react-apexcharts';\nimport { PieChartComponentProps } from '../types';\n\nexport const PieChartComponent: FC<PieChartComponentProps> = ({\n categories,\n series,\n height,\n}) => {\n const useStyles = makeStyles({\n fixedHeightPaper: {\n paddingTop: '10px',\n overflow: 'hidden',\n height: height ? height : 300,\n },\n });\n const classes = useStyles();\n const customScale = humanFormat.Scale.create(['', 'K', 'M', 'B'], 1000);\n\n const state = {\n options: {\n chart: {\n animations: {\n enabled: false,\n },\n },\n legend: {\n show: false,\n },\n labels: categories,\n dataLabels: {\n enabled: true,\n formatter: (value, { seriesIndex, dataPointIndex, w }) => {\n return `${w.config.labels[seriesIndex]} (${value.toFixed(0)}%)`;\n },\n },\n tooltip: {\n y: {\n formatter: (value: number) => {\n return `$${humanFormat(value, {\n scale: customScale,\n separator: '',\n })}`;\n },\n },\n },\n plotOptions: {\n pie: {\n donut: {\n labels: {\n show: true,\n value: {\n formatter: (val: string) => {\n const floatVal = parseFloat(val);\n return `$${humanFormat(floatVal, {\n scale: customScale,\n separator: '',\n })}`;\n },\n },\n },\n },\n },\n },\n // there are only 5 colors by default, here we extend it to 50 different colors\n colors: [\n '#008FFB',\n '#00E396',\n '#FEB019',\n '#FF4560',\n '#775DD0',\n '#3F51B5',\n '#03A9F4',\n '#4CAF50',\n '#F9CE1D',\n '#FF9800',\n '#33B2DF',\n '#546E7A',\n '#D4526E',\n '#13D8AA',\n '#A5978B',\n '#4ECDC4',\n '#C7F464',\n '#81D4FA',\n '#546E7A',\n '#FD6A6A',\n '#2B908F',\n '#F9A3A4',\n '#90EE7E',\n '#FA4443',\n '#69D2E7',\n '#449DD1',\n '#F86624',\n '#EA3546',\n '#662E9B',\n '#C5D86D',\n '#D7263D',\n '#1B998B',\n '#2E294E',\n '#F46036',\n '#E2C044',\n '#662E9B',\n '#F86624',\n '#F9C80E',\n '#EA3546',\n '#43BCCD',\n '#5C4742',\n '#A5978B',\n '#8D5B4C',\n '#5A2A27',\n '#C4BBAF',\n '#A300D6',\n '#7D02EB',\n '#5653FE',\n '#2983FF',\n '#00B1F2',\n ],\n },\n series: series,\n };\n\n return (\n <Paper className={classes.fixedHeightPaper}>\n <Chart\n options={state.options}\n series={state.series}\n type=\"donut\"\n height={height ? height : 300}\n />\n </Paper>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Page, Header, Content, Progress } from '@backstage/core-components';
|
|
2
|
+
import { useApi, alertApiRef } from '@backstage/core-plugin-api';
|
|
3
|
+
import { Grid } from '@material-ui/core';
|
|
4
|
+
import { startOfMonth, addMonths, endOfMonth } from 'date-fns';
|
|
5
|
+
import React, { useState, useCallback, useEffect } from 'react';
|
|
6
|
+
import { infraWalletApiRef } from '../../api/InfraWalletApi.esm.js';
|
|
7
|
+
import { aggregateCostReports, mergeCostReports, getAllReportTags } from '../../api/functions.esm.js';
|
|
8
|
+
import { ColumnsChartComponent } from '../ColumnsChartComponent/ColumnsChartComponent.esm.js';
|
|
9
|
+
import { CostReportsTableComponent } from '../CostReportsTableComponent/CostReportsTableComponent.esm.js';
|
|
10
|
+
import { PieChartComponent } from '../PieChartComponent/PieChartComponent.esm.js';
|
|
11
|
+
import { TopbarComponent } from '../TopbarComponent/TopbarComponent.esm.js';
|
|
12
|
+
|
|
13
|
+
const getTotalCost = (report) => {
|
|
14
|
+
let total = 0;
|
|
15
|
+
Object.keys(report.reports).forEach((s) => {
|
|
16
|
+
total += report.reports[s];
|
|
17
|
+
});
|
|
18
|
+
return total;
|
|
19
|
+
};
|
|
20
|
+
const rearrangeData = (report, periods) => {
|
|
21
|
+
const costs = [];
|
|
22
|
+
periods.forEach((s) => {
|
|
23
|
+
if (report.reports[s] !== void 0) {
|
|
24
|
+
costs.push(report.reports[s]);
|
|
25
|
+
} else {
|
|
26
|
+
costs.push(null);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return costs;
|
|
30
|
+
};
|
|
31
|
+
const ReportsComponent = () => {
|
|
32
|
+
const MERGE_THRESHOLD = 8;
|
|
33
|
+
const [submittingState, setSubmittingState] = useState(false);
|
|
34
|
+
const [reports, setReports] = useState([]);
|
|
35
|
+
const [reportsAggregated, setReportsAggregated] = useState([]);
|
|
36
|
+
const [reportsAggregatedAndMerged, setReportsAggregatedAndMerged] = useState([]);
|
|
37
|
+
const [reportTags, setReportTags] = useState([]);
|
|
38
|
+
const [granularity, setGranularity] = useState("monthly");
|
|
39
|
+
const [aggregatedBy, setAggregatedBy] = useState("none");
|
|
40
|
+
const [filters, setFilters] = useState("");
|
|
41
|
+
const [groups, setGroups] = useState("");
|
|
42
|
+
const [monthRangeState, setMonthRangeState] = React.useState({
|
|
43
|
+
startMonth: startOfMonth(addMonths(/* @__PURE__ */ new Date(), -2)),
|
|
44
|
+
endMonth: endOfMonth(/* @__PURE__ */ new Date())
|
|
45
|
+
});
|
|
46
|
+
const alertApi = useApi(alertApiRef);
|
|
47
|
+
const infraWalletApi = useApi(infraWalletApiRef);
|
|
48
|
+
const fetchCostReportsCallback = useCallback(async () => {
|
|
49
|
+
setSubmittingState(true);
|
|
50
|
+
await infraWalletApi.getCostReports(
|
|
51
|
+
filters,
|
|
52
|
+
groups,
|
|
53
|
+
granularity,
|
|
54
|
+
monthRangeState.startMonth,
|
|
55
|
+
monthRangeState.endMonth
|
|
56
|
+
).then((reportsResponse) => {
|
|
57
|
+
if (reportsResponse.data && reportsResponse.data.length > 0) {
|
|
58
|
+
setReports(reportsResponse.data);
|
|
59
|
+
}
|
|
60
|
+
}).catch(
|
|
61
|
+
(e) => alertApi.post({ message: `${e.message}`, severity: "error" })
|
|
62
|
+
);
|
|
63
|
+
setSubmittingState(false);
|
|
64
|
+
}, [filters, groups, monthRangeState, granularity, infraWalletApi, alertApi]);
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (reports.length !== 0) {
|
|
67
|
+
const arrgegatedReports = aggregateCostReports(reports, aggregatedBy);
|
|
68
|
+
const aggregatedAndMergedReports = mergeCostReports(
|
|
69
|
+
arrgegatedReports,
|
|
70
|
+
MERGE_THRESHOLD
|
|
71
|
+
);
|
|
72
|
+
const allTags = getAllReportTags(reports);
|
|
73
|
+
setReportsAggregated(arrgegatedReports);
|
|
74
|
+
setReportsAggregatedAndMerged(aggregatedAndMergedReports);
|
|
75
|
+
setReportTags(allTags);
|
|
76
|
+
}
|
|
77
|
+
}, [reports, aggregatedBy]);
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
fetchCostReportsCallback();
|
|
80
|
+
}, [fetchCostReportsCallback]);
|
|
81
|
+
return /* @__PURE__ */ React.createElement(Page, { themeId: "tool" }, /* @__PURE__ */ React.createElement(Header, { title: "InfraWallet" }), /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 3 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(
|
|
82
|
+
TopbarComponent,
|
|
83
|
+
{
|
|
84
|
+
aggregatedBy,
|
|
85
|
+
aggregatedBySetter: setAggregatedBy,
|
|
86
|
+
tags: reportTags,
|
|
87
|
+
granularity,
|
|
88
|
+
granularitySetter: setGranularity,
|
|
89
|
+
monthRange: monthRangeState,
|
|
90
|
+
monthRangeSetter: setMonthRangeState
|
|
91
|
+
}
|
|
92
|
+
)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, submittingState ? /* @__PURE__ */ React.createElement(Progress, null) : null), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 4, lg: 3 }, reportsAggregatedAndMerged.length > 0 && /* @__PURE__ */ React.createElement(
|
|
93
|
+
PieChartComponent,
|
|
94
|
+
{
|
|
95
|
+
categories: reportsAggregatedAndMerged.map(
|
|
96
|
+
(item) => item.id
|
|
97
|
+
),
|
|
98
|
+
series: reportsAggregatedAndMerged.map(
|
|
99
|
+
(item) => getTotalCost(item)
|
|
100
|
+
),
|
|
101
|
+
height: 350
|
|
102
|
+
}
|
|
103
|
+
)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 8, lg: 9 }, reportsAggregatedAndMerged.length > 0 && /* @__PURE__ */ React.createElement(
|
|
104
|
+
ColumnsChartComponent,
|
|
105
|
+
{
|
|
106
|
+
categories: Object.keys(reportsAggregatedAndMerged[0].reports),
|
|
107
|
+
series: reportsAggregatedAndMerged.map((item) => ({
|
|
108
|
+
name: item.id,
|
|
109
|
+
data: rearrangeData(
|
|
110
|
+
item,
|
|
111
|
+
Object.keys(reportsAggregatedAndMerged[0].reports)
|
|
112
|
+
)
|
|
113
|
+
})),
|
|
114
|
+
height: 350
|
|
115
|
+
}
|
|
116
|
+
)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, reportsAggregated.length > 0 && /* @__PURE__ */ React.createElement(
|
|
117
|
+
CostReportsTableComponent,
|
|
118
|
+
{
|
|
119
|
+
reports: reportsAggregated,
|
|
120
|
+
aggregatedBy
|
|
121
|
+
}
|
|
122
|
+
)))));
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export { ReportsComponent };
|
|
126
|
+
//# sourceMappingURL=ReportsComponent.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReportsComponent.esm.js","sources":["../../../src/components/ReportsComponent/ReportsComponent.tsx"],"sourcesContent":["import {\n Content,\n Header,\n HeaderLabel,\n Page,\n Progress,\n} from '@backstage/core-components';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport { Grid } from '@material-ui/core';\nimport { addMonths, endOfMonth, startOfMonth } from 'date-fns';\nimport React, { useCallback, useEffect, useState } from 'react';\nimport { infraWalletApiRef } from '../../api/InfraWalletApi';\nimport {\n aggregateCostReports,\n mergeCostReports,\n getAllReportTags,\n} from '../../api/functions';\nimport { Report } from '../../api/types';\nimport { ColumnsChartComponent } from '../ColumnsChartComponent';\nimport { CostReportsTableComponent } from '../CostReportsTableComponent';\nimport { PieChartComponent } from '../PieChartComponent';\nimport { TopbarComponent } from '../TopbarComponent';\nimport { MonthRange } from '../types';\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\nexport const ReportsComponent = () => {\n const MERGE_THRESHOLD = 8;\n const [submittingState, setSubmittingState] = useState<Boolean>(false);\n const [reports, setReports] = useState<Report[]>([]);\n const [reportsAggregated, setReportsAggregated] = useState<Report[]>([]);\n const [reportsAggregatedAndMerged, setReportsAggregatedAndMerged] = useState<\n Report[]\n >([]);\n const [reportTags, setReportTags] = useState<string[]>([]);\n const [granularity, setGranularity] = useState<string>('monthly');\n const [aggregatedBy, setAggregatedBy] = useState<string>('none');\n const [filters, setFilters] = useState<string>('');\n const [groups, setGroups] = useState<string>('');\n const [monthRangeState, setMonthRangeState] = React.useState<MonthRange>({\n startMonth: startOfMonth(addMonths(new Date(), -2)),\n endMonth: endOfMonth(new Date()),\n });\n\n const alertApi = useApi(alertApiRef);\n const infraWalletApi = useApi(infraWalletApiRef);\n\n const fetchCostReportsCallback = useCallback(async () => {\n setSubmittingState(true);\n await infraWalletApi\n .getCostReports(\n filters,\n groups,\n granularity,\n monthRangeState.startMonth,\n monthRangeState.endMonth,\n )\n .then(reportsResponse => {\n if (reportsResponse.data && reportsResponse.data.length > 0) {\n setReports(reportsResponse.data);\n }\n })\n .catch(e =>\n alertApi.post({ message: `${e.message}`, severity: 'error' }),\n );\n setSubmittingState(false);\n }, [filters, groups, monthRangeState, granularity, infraWalletApi, alertApi]);\n\n useEffect(() => {\n if (reports.length !== 0) {\n const arrgegatedReports = aggregateCostReports(reports, aggregatedBy);\n const aggregatedAndMergedReports = mergeCostReports(\n arrgegatedReports,\n MERGE_THRESHOLD,\n );\n const allTags = getAllReportTags(reports);\n setReportsAggregated(arrgegatedReports);\n setReportsAggregatedAndMerged(aggregatedAndMergedReports);\n setReportTags(allTags);\n }\n }, [reports, aggregatedBy]);\n\n useEffect(() => {\n fetchCostReportsCallback();\n }, [fetchCostReportsCallback]);\n\n return (\n <Page themeId=\"tool\">\n <Header title=\"InfraWallet\" />\n <Content>\n <Grid container spacing={3}>\n <Grid item xs={12}>\n <TopbarComponent\n aggregatedBy={aggregatedBy}\n aggregatedBySetter={setAggregatedBy}\n tags={reportTags}\n granularity={granularity}\n granularitySetter={setGranularity}\n monthRange={monthRangeState}\n monthRangeSetter={setMonthRangeState}\n />\n </Grid>\n <Grid item xs={12}>\n {submittingState ? <Progress /> : null}\n </Grid>\n <Grid item xs={12} md={4} lg={3}>\n {reportsAggregatedAndMerged.length > 0 && (\n <PieChartComponent\n categories={reportsAggregatedAndMerged.map(\n (item: any) => item.id,\n )}\n series={reportsAggregatedAndMerged.map((item: any) =>\n getTotalCost(item),\n )}\n height={350}\n />\n )}\n </Grid>\n <Grid item xs={12} md={8} lg={9}>\n {reportsAggregatedAndMerged.length > 0 && (\n <ColumnsChartComponent\n categories={Object.keys(reportsAggregatedAndMerged[0].reports)}\n series={reportsAggregatedAndMerged.map((item: any) => ({\n name: item.id,\n data: rearrangeData(\n item,\n Object.keys(reportsAggregatedAndMerged[0].reports),\n ),\n }))}\n height={350}\n />\n )}\n </Grid>\n <Grid item xs={12}>\n {reportsAggregated.length > 0 && (\n <CostReportsTableComponent\n reports={reportsAggregated}\n aggregatedBy={aggregatedBy}\n />\n )}\n </Grid>\n </Grid>\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Box, FormControl, Select, MenuItem, FormHelperText, Grid, Button } from '@material-ui/core';
|
|
2
|
+
import Divider from '@material-ui/core/Divider';
|
|
3
|
+
import InputLabel from '@material-ui/core/InputLabel';
|
|
4
|
+
import ListSubheader from '@material-ui/core/ListSubheader';
|
|
5
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
6
|
+
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
|
7
|
+
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
|
|
8
|
+
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
|
9
|
+
import { startOfMonth, endOfMonth, addMonths } from 'date-fns';
|
|
10
|
+
import React from 'react';
|
|
11
|
+
|
|
12
|
+
const useStyles = makeStyles((theme) => ({
|
|
13
|
+
formControl: {
|
|
14
|
+
marginLeft: theme.spacing(1),
|
|
15
|
+
marginRight: theme.spacing(3),
|
|
16
|
+
minWidth: 120
|
|
17
|
+
}
|
|
18
|
+
}));
|
|
19
|
+
const TopbarComponent = ({
|
|
20
|
+
aggregatedBy,
|
|
21
|
+
aggregatedBySetter,
|
|
22
|
+
tags,
|
|
23
|
+
granularity,
|
|
24
|
+
granularitySetter,
|
|
25
|
+
monthRange,
|
|
26
|
+
monthRangeSetter
|
|
27
|
+
}) => {
|
|
28
|
+
const classes = useStyles();
|
|
29
|
+
const setPreDefinedMonthRange = (lastXMonth) => {
|
|
30
|
+
monthRangeSetter({
|
|
31
|
+
startMonth: startOfMonth(addMonths(/* @__PURE__ */ new Date(), lastXMonth * -1)),
|
|
32
|
+
endMonth: endOfMonth(/* @__PURE__ */ new Date())
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(FormControl, { className: classes.formControl }, /* @__PURE__ */ React.createElement(InputLabel, { shrink: true }, "Group by"), /* @__PURE__ */ React.createElement(
|
|
36
|
+
Select,
|
|
37
|
+
{
|
|
38
|
+
value: aggregatedBy,
|
|
39
|
+
onChange: (event) => aggregatedBySetter(event.target.value)
|
|
40
|
+
},
|
|
41
|
+
/* @__PURE__ */ React.createElement(MenuItem, { value: "none" }, /* @__PURE__ */ React.createElement("em", null, "None")),
|
|
42
|
+
/* @__PURE__ */ React.createElement(MenuItem, { value: "name" }, "Name"),
|
|
43
|
+
/* @__PURE__ */ React.createElement(MenuItem, { value: "provider" }, "Provider"),
|
|
44
|
+
/* @__PURE__ */ React.createElement(MenuItem, { value: "category" }, "Category"),
|
|
45
|
+
/* @__PURE__ */ React.createElement(MenuItem, { value: "service" }, "Cloud Service"),
|
|
46
|
+
/* @__PURE__ */ React.createElement(Divider, { light: true }),
|
|
47
|
+
/* @__PURE__ */ React.createElement(ListSubheader, { onClickCapture: (e) => e.stopPropagation() }, "Tags"),
|
|
48
|
+
tags.map((tag) => /* @__PURE__ */ React.createElement(MenuItem, { key: tag, value: tag }, `tag:${tag}`))
|
|
49
|
+
)), /* @__PURE__ */ React.createElement(FormControl, { className: classes.formControl, style: { display: "none" } }, /* @__PURE__ */ React.createElement(
|
|
50
|
+
Select,
|
|
51
|
+
{
|
|
52
|
+
value: granularity,
|
|
53
|
+
onChange: (event) => granularitySetter(event.target.value)
|
|
54
|
+
},
|
|
55
|
+
/* @__PURE__ */ React.createElement(MenuItem, { value: "daily" }, "Daily"),
|
|
56
|
+
/* @__PURE__ */ React.createElement(MenuItem, { value: "monthly" }, "Monthly")
|
|
57
|
+
), /* @__PURE__ */ React.createElement(FormHelperText, null, "Granularity")), /* @__PURE__ */ React.createElement(FormControl, { className: classes.formControl }, /* @__PURE__ */ React.createElement(LocalizationProvider, { dateAdapter: AdapterDateFns }, /* @__PURE__ */ React.createElement(
|
|
58
|
+
DatePicker,
|
|
59
|
+
{
|
|
60
|
+
value: monthRange.startMonth,
|
|
61
|
+
label: "From",
|
|
62
|
+
views: ["year", "month"],
|
|
63
|
+
slotProps: { textField: { variant: "standard" } },
|
|
64
|
+
onAccept: (value) => {
|
|
65
|
+
if (value) {
|
|
66
|
+
monthRangeSetter({
|
|
67
|
+
startMonth: startOfMonth(value),
|
|
68
|
+
endMonth: endOfMonth(monthRange.endMonth)
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
))), /* @__PURE__ */ React.createElement(FormControl, { className: classes.formControl }, /* @__PURE__ */ React.createElement(LocalizationProvider, { dateAdapter: AdapterDateFns }, /* @__PURE__ */ React.createElement(
|
|
74
|
+
DatePicker,
|
|
75
|
+
{
|
|
76
|
+
value: monthRange.endMonth,
|
|
77
|
+
label: "To",
|
|
78
|
+
views: ["year", "month"],
|
|
79
|
+
slotProps: { textField: { variant: "standard" } },
|
|
80
|
+
onAccept: (value) => {
|
|
81
|
+
if (value) {
|
|
82
|
+
monthRangeSetter({
|
|
83
|
+
startMonth: startOfMonth(monthRange.startMonth),
|
|
84
|
+
endMonth: endOfMonth(value)
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
))), /* @__PURE__ */ React.createElement(FormControl, { className: classes.formControl }, /* @__PURE__ */ React.createElement(FormHelperText, null, "Quick selections for month ranges"), /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 3 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Button, { color: "primary", onClick: () => setPreDefinedMonthRange(2) }, "Last 3 Months"), /* @__PURE__ */ React.createElement(Button, { color: "primary", onClick: () => setPreDefinedMonthRange(5) }, "Last 6 Months"), /* @__PURE__ */ React.createElement(Button, { color: "primary", onClick: () => setPreDefinedMonthRange(11) }, "Last 12 Months")))));
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export { TopbarComponent };
|
|
93
|
+
//# sourceMappingURL=TopbarComponent.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TopbarComponent.esm.js","sources":["../../../src/components/TopbarComponent/TopbarComponent.tsx"],"sourcesContent":["import {\n Box,\n Button,\n FormControl,\n FormHelperText,\n Grid,\n MenuItem,\n Select,\n} from '@material-ui/core';\nimport Divider from '@material-ui/core/Divider';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport ListSubheader from '@material-ui/core/ListSubheader';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';\nimport { DatePicker } from '@mui/x-date-pickers/DatePicker';\nimport { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';\nimport { addMonths, endOfMonth, startOfMonth } from 'date-fns';\nimport React, { FC } from 'react';\nimport { TopbarComponentProps } from '../types';\n\nconst useStyles = makeStyles(theme => ({\n formControl: {\n marginLeft: theme.spacing(1),\n marginRight: theme.spacing(3),\n minWidth: 120,\n },\n}));\n\nexport const TopbarComponent: FC<TopbarComponentProps> = ({\n aggregatedBy,\n aggregatedBySetter,\n tags,\n granularity,\n granularitySetter,\n monthRange,\n monthRangeSetter,\n}) => {\n const classes = useStyles();\n\n const setPreDefinedMonthRange = (lastXMonth: number) => {\n monthRangeSetter({\n startMonth: startOfMonth(addMonths(new Date(), lastXMonth * -1)),\n endMonth: endOfMonth(new Date()),\n });\n };\n\n return (\n <Box>\n <FormControl className={classes.formControl}>\n <InputLabel shrink>Group by</InputLabel>\n <Select\n value={aggregatedBy}\n onChange={event => aggregatedBySetter(event.target.value)}\n >\n <MenuItem value=\"none\">\n <em>None</em>\n </MenuItem>\n <MenuItem value=\"name\">Name</MenuItem>\n <MenuItem value=\"provider\">Provider</MenuItem>\n <MenuItem value=\"category\">Category</MenuItem>\n <MenuItem value=\"service\">Cloud Service</MenuItem>\n <Divider light />\n <ListSubheader onClickCapture={e => e.stopPropagation()}>\n Tags\n </ListSubheader>\n {tags.map(tag => (\n <MenuItem key={tag} value={tag}>\n {`tag:${tag}`}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n\n <FormControl className={classes.formControl} style={{ display: 'none' }}>\n <Select\n value={granularity}\n onChange={event => granularitySetter(event.target.value)}\n >\n <MenuItem value=\"daily\">Daily</MenuItem>\n <MenuItem value=\"monthly\">Monthly</MenuItem>\n </Select>\n <FormHelperText>Granularity</FormHelperText>\n </FormControl>\n\n <FormControl className={classes.formControl}>\n <LocalizationProvider dateAdapter={AdapterDateFns}>\n <DatePicker\n value={monthRange.startMonth}\n label=\"From\"\n views={['year', 'month']}\n slotProps={{ textField: { variant: 'standard' } }}\n onAccept={value => {\n if (value) {\n monthRangeSetter({\n startMonth: startOfMonth(value),\n endMonth: endOfMonth(monthRange.endMonth),\n });\n }\n }}\n />\n </LocalizationProvider>\n </FormControl>\n\n <FormControl className={classes.formControl}>\n <LocalizationProvider dateAdapter={AdapterDateFns}>\n <DatePicker\n value={monthRange.endMonth}\n label=\"To\"\n views={['year', 'month']}\n slotProps={{ textField: { variant: 'standard' } }}\n onAccept={value => {\n if (value) {\n monthRangeSetter({\n startMonth: startOfMonth(monthRange.startMonth),\n endMonth: endOfMonth(value),\n });\n }\n }}\n />\n </LocalizationProvider>\n </FormControl>\n\n <FormControl className={classes.formControl}>\n <FormHelperText>Quick selections for month ranges</FormHelperText>\n <Grid container spacing={3}>\n <Grid item xs={12}>\n <Button color=\"primary\" onClick={() => setPreDefinedMonthRange(2)}>\n Last 3 Months\n </Button>\n <Button color=\"primary\" onClick={() => setPreDefinedMonthRange(5)}>\n Last 6 Months\n </Button>\n <Button color=\"primary\" onClick={() => setPreDefinedMonthRange(11)}>\n Last 12 Months\n </Button>\n </Grid>\n </Grid>\n </FormControl>\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
|
|
4
|
+
|
|
5
|
+
declare const infraWalletPlugin: _backstage_core_plugin_api.BackstagePlugin<{
|
|
6
|
+
root: _backstage_core_plugin_api.RouteRef<undefined>;
|
|
7
|
+
}, {}, {}>;
|
|
8
|
+
declare const InfraWalletPage: () => react.JSX.Element;
|
|
9
|
+
|
|
10
|
+
export { InfraWalletPage, infraWalletPlugin };
|