@electrolux-oss/plugin-infrawallet 0.1.10 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/README.md +45 -21
  2. package/dist/api/InfraWalletApi.esm.js.map +1 -1
  3. package/dist/api/InfraWalletApiClient.esm.js +12 -2
  4. package/dist/api/InfraWalletApiClient.esm.js.map +1 -1
  5. package/dist/api/functions.esm.js +33 -4
  6. package/dist/api/functions.esm.js.map +1 -1
  7. package/dist/components/ColumnsChartComponent/ColumnsChartComponent.esm.js +45 -28
  8. package/dist/components/ColumnsChartComponent/ColumnsChartComponent.esm.js.map +1 -1
  9. package/dist/components/CostReportsTableComponent/CostReportsTableComponent.esm.js +42 -37
  10. package/dist/components/CostReportsTableComponent/CostReportsTableComponent.esm.js.map +1 -1
  11. package/dist/components/ErrorsAlertComponent/ErrorsAlertComponent.esm.js +3 -2
  12. package/dist/components/ErrorsAlertComponent/ErrorsAlertComponent.esm.js.map +1 -1
  13. package/dist/components/FiltersComponent/FiltersComponent.esm.js +216 -10
  14. package/dist/components/FiltersComponent/FiltersComponent.esm.js.map +1 -1
  15. package/dist/components/MetricConfigurationComponent/MetricConfigurationComponent.esm.js +7 -0
  16. package/dist/components/MetricConfigurationComponent/MetricConfigurationComponent.esm.js.map +1 -1
  17. package/dist/components/ProviderIcons/ProviderIcons.esm.js +322 -0
  18. package/dist/components/ProviderIcons/ProviderIcons.esm.js.map +1 -0
  19. package/dist/components/ReportsComponent/ReportsComponent.esm.js +30 -15
  20. package/dist/components/ReportsComponent/ReportsComponent.esm.js.map +1 -1
  21. package/dist/components/TopbarComponent/TopbarComponent.esm.js +1 -1
  22. package/dist/components/TopbarComponent/TopbarComponent.esm.js.map +1 -1
  23. package/package.json +4 -6
  24. package/dist/components/CostReportsTableComponent/TrendBarComponent.esm.js +0 -43
  25. package/dist/components/CostReportsTableComponent/TrendBarComponent.esm.js.map +0 -1
@@ -1,14 +1,14 @@
1
- import Chip from '@material-ui/core/Chip';
2
1
  import Typography from '@material-ui/core/Typography';
3
2
  import { makeStyles } from '@material-ui/core/styles';
4
3
  import Box from '@mui/material/Box';
5
4
  import { DataGrid, GridToolbarContainer, GridToolbarExport } from '@mui/x-data-grid';
6
5
  import humanFormat from 'human-format';
7
6
  import React from 'react';
8
- import { getPreviousMonth } from '../../api/functions.esm.js';
9
- import { TrendBarComponent } from './TrendBarComponent.esm.js';
7
+ import { extractAccountInfo, getPreviousMonth } from '../../api/functions.esm.js';
8
+ import { getProviderIcon } from '../ProviderIcons/ProviderIcons.esm.js';
9
+ import { SparkLineChart } from '@mui/x-charts/SparkLineChart';
10
10
 
11
- const useStyles = makeStyles((theme) => ({
11
+ const useStyles = makeStyles({
12
12
  increase: {
13
13
  color: "red"
14
14
  },
@@ -18,15 +18,16 @@ const useStyles = makeStyles((theme) => ({
18
18
  container: {
19
19
  display: "flex",
20
20
  alignItems: "center"
21
- },
22
- clip: {
23
- backgroundColor: "#deebff",
24
- color: "#0052cc",
25
- marginLeft: theme.spacing(1)
26
21
  }
27
- }));
22
+ });
28
23
  function CustomToolbar() {
29
- return /* @__PURE__ */ React.createElement(GridToolbarContainer, null, /* @__PURE__ */ React.createElement(GridToolbarExport, { printOptions: { disableToolbarButton: true } }));
24
+ return /* @__PURE__ */ React.createElement(GridToolbarContainer, null, /* @__PURE__ */ React.createElement(
25
+ GridToolbarExport,
26
+ {
27
+ csvOptions: { fileName: "InfraWallet-export" },
28
+ printOptions: { disableToolbarButton: true }
29
+ }
30
+ ));
30
31
  }
31
32
  const CostReportsTableComponent = ({ reports, aggregatedBy, periods }) => {
32
33
  const classes = useStyles();
@@ -52,7 +53,19 @@ const CostReportsTableComponent = ({ reports, aggregatedBy, periods }) => {
52
53
  }
53
54
  return "-";
54
55
  };
55
- const columns = [
56
+ const columns = [];
57
+ if (["account", "provider", "service"].includes(aggregatedBy)) {
58
+ columns.push({
59
+ field: "PROVIDER",
60
+ headerName: "",
61
+ width: 30,
62
+ disableExport: true,
63
+ renderCell: (params) => {
64
+ return getProviderIcon(params.row.provider);
65
+ }
66
+ });
67
+ }
68
+ columns.push(
56
69
  {
57
70
  field: aggregatedBy,
58
71
  headerName: aggregatedBy.toLocaleUpperCase("en-US"),
@@ -60,15 +73,18 @@ const CostReportsTableComponent = ({ reports, aggregatedBy, periods }) => {
60
73
  flex: 2,
61
74
  renderCell: (params) => {
62
75
  let formattedValue = params.formattedValue;
63
- let chipLabel = null;
64
- if (aggregatedBy === "service" || aggregatedBy === "name") {
76
+ if (aggregatedBy === "service" || aggregatedBy === "account") {
65
77
  if (params.formattedValue !== void 0 && params.formattedValue.indexOf("/") !== -1) {
66
- const splitValue = params.formattedValue.split("/");
67
- formattedValue = splitValue[1];
68
- chipLabel = splitValue[0].toLowerCase();
78
+ formattedValue = params.formattedValue.split("/")[1];
79
+ }
80
+ if (aggregatedBy === "account" && formattedValue) {
81
+ const account = extractAccountInfo(formattedValue);
82
+ const accountName = account.accountName;
83
+ const accountId = account.accountId;
84
+ return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.container }, accountName), /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.container, color: "textSecondary" }, accountId));
69
85
  }
70
86
  }
71
- return /* @__PURE__ */ React.createElement(Typography, { variant: "body2", component: "div", className: classes.container }, formattedValue, chipLabel && /* @__PURE__ */ React.createElement(Chip, { size: "small", label: chipLabel, className: classes.clip }));
87
+ return /* @__PURE__ */ React.createElement(Typography, { variant: "body2", component: "div", className: classes.container }, formattedValue);
72
88
  }
73
89
  },
74
90
  {
@@ -76,24 +92,13 @@ const CostReportsTableComponent = ({ reports, aggregatedBy, periods }) => {
76
92
  headerName: "TREND",
77
93
  width: 100,
78
94
  disableExport: true,
79
- renderCell: (params) => {
80
- return /* @__PURE__ */ React.createElement(
81
- TrendBarComponent,
82
- {
83
- categories: periods,
84
- series: [
85
- {
86
- name: params.row.id,
87
- data: periods.map(
88
- (period) => params.row.reports[period] !== void 0 ? params.row.reports[period] : null
89
- )
90
- }
91
- ]
92
- }
93
- );
94
- }
95
+ hideSortIcons: true,
96
+ renderCell: (params) => /* @__PURE__ */ React.createElement(SparkLineChart, { data: params.value ? params.value[0] : null, plotType: "bar" }),
97
+ valueGetter: (_, row) => [
98
+ periods.map((period) => row.reports[period] !== void 0 ? row.reports[period] : null)
99
+ ]
95
100
  }
96
- ];
101
+ );
97
102
  periods.forEach((period) => {
98
103
  columns.push({
99
104
  field: period,
@@ -150,7 +155,6 @@ const CostReportsTableComponent = ({ reports, aggregatedBy, periods }) => {
150
155
  DataGrid,
151
156
  {
152
157
  rows: reports,
153
- rowHeight: 35,
154
158
  columns,
155
159
  initialState: {
156
160
  sorting: {
@@ -165,7 +169,8 @@ const CostReportsTableComponent = ({ reports, aggregatedBy, periods }) => {
165
169
  pageSizeOptions: [15],
166
170
  slots: { toolbar: CustomToolbar },
167
171
  disableRowSelectionOnClick: true,
168
- disableColumnMenu: true
172
+ disableColumnMenu: true,
173
+ density: aggregatedBy === "account" ? "standard" : "compact"
169
174
  }
170
175
  ));
171
176
  };
@@ -1 +1 @@
1
- {"version":3,"file":"CostReportsTableComponent.esm.js","sources":["../../../src/components/CostReportsTableComponent/CostReportsTableComponent.tsx"],"sourcesContent":["import Chip from '@material-ui/core/Chip';\nimport Typography from '@material-ui/core/Typography';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Box from '@mui/material/Box';\nimport { DataGrid, GridColDef, GridRenderCellParams, GridToolbarContainer, GridToolbarExport } 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(theme => ({\n increase: {\n color: 'red',\n },\n decrease: {\n color: 'green',\n },\n container: {\n display: 'flex',\n alignItems: 'center',\n },\n clip: {\n backgroundColor: '#deebff',\n color: '#0052cc',\n marginLeft: theme.spacing(1),\n },\n}));\n\nfunction CustomToolbar() {\n return (\n <GridToolbarContainer>\n <GridToolbarExport printOptions={{ disableToolbarButton: true }} />\n </GridToolbarContainer>\n );\n}\n\nexport const CostReportsTableComponent: FC<CostReportsTableComponentProps> = ({ reports, aggregatedBy, periods }) => {\n const classes = useStyles();\n const customScale = humanFormat.Scale.create(['', 'K', 'M', 'B'], 1000);\n\n const formatCostValue = (params: GridRenderCellParams, period: string): string => {\n const value = params.value;\n if (typeof value === 'number') {\n const previousPeriod = period.length === 7 ? getPreviousMonth(params.field) : '';\n const formattedValue = humanFormat(value, {\n scale: customScale,\n separator: '',\n decimals: 2,\n });\n if (periods.includes(previousPeriod) && params.row.reports[previousPeriod] > 0) {\n const diff = params.row.reports[params.field] - params.row.reports[previousPeriod];\n const percentage = Math.round((diff / params.row.reports[previousPeriod]) * 100);\n const mark = diff > 0 ? '+' : '';\n // only display percentage change if it is larger than 1% or less than -1%\n if (percentage >= 1 || percentage <= -1) {\n return `$${formattedValue} (${mark}${percentage}%)`;\n }\n }\n return `$${formattedValue}`;\n }\n return '-';\n };\n\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 let formattedValue = params.formattedValue;\n let chipLabel = null;\n\n if (aggregatedBy === 'service' || aggregatedBy === 'name') {\n if (params.formattedValue !== undefined && params.formattedValue.indexOf('/') !== -1) {\n const splitValue = params.formattedValue.split('/');\n formattedValue = splitValue[1];\n chipLabel = splitValue[0].toLowerCase();\n }\n }\n\n return (\n <Typography variant=\"body2\" component=\"div\" className={classes.container}>\n {formattedValue}\n {chipLabel && <Chip size=\"small\" label={chipLabel} className={classes.clip} />}\n </Typography>\n );\n },\n },\n {\n field: 'TREND',\n headerName: 'TREND',\n width: 100,\n disableExport: true,\n renderCell: (params: GridRenderCellParams): React.ReactNode => {\n return (\n <TrendBarComponent\n categories={periods}\n series={[\n {\n name: params.row.id,\n data: periods.map(period =>\n params.row.reports[period] !== undefined ? params.row.reports[period] : 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 renderCell: (params: GridRenderCellParams): React.ReactNode => {\n const formattedValue = formatCostValue(params, period);\n let className = '';\n const percentageIndex = formattedValue.indexOf('(');\n const costStr = percentageIndex === -1 ? formattedValue : formattedValue.substring(0, percentageIndex);\n let percentageStr = percentageIndex === -1 ? '' : formattedValue.substring(percentageIndex);\n if (percentageStr.includes('-')) {\n className = classes.decrease;\n percentageStr = percentageStr.replace('-', '▼');\n } else if (percentageStr.includes('+')) {\n className = classes.increase;\n percentageStr = percentageStr.replace('+', '▲');\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 renderCell: (params: GridRenderCellParams): React.ReactNode => {\n let formattedValue = '-';\n if (typeof params.value === 'number') {\n formattedValue = `$${humanFormat(params.value, {\n scale: customScale,\n separator: '',\n decimals: 2,\n })}`;\n }\n return <Typography variant=\"body2\">{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={[15]}\n slots={{ toolbar: CustomToolbar }}\n disableRowSelectionOnClick\n disableColumnMenu\n />\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
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, GridToolbarContainer, GridToolbarExport } from '@mui/x-data-grid';\nimport humanFormat from 'human-format';\nimport React, { FC } from 'react';\nimport { extractAccountInfo, getPreviousMonth } from '../../api/functions';\nimport { CostReportsTableComponentProps } from '../types';\nimport { getProviderIcon } from '../ProviderIcons';\nimport { SparkLineChart } from '@mui/x-charts/SparkLineChart';\n\nconst useStyles = makeStyles({\n increase: {\n color: 'red',\n },\n decrease: {\n color: 'green',\n },\n container: {\n display: 'flex',\n alignItems: 'center',\n },\n});\n\nfunction CustomToolbar() {\n return (\n <GridToolbarContainer>\n <GridToolbarExport\n csvOptions={{ fileName: 'InfraWallet-export' }}\n printOptions={{ disableToolbarButton: true }}\n />\n </GridToolbarContainer>\n );\n}\n\nexport const CostReportsTableComponent: FC<CostReportsTableComponentProps> = ({ reports, aggregatedBy, periods }) => {\n const classes = useStyles();\n const customScale = humanFormat.Scale.create(['', 'K', 'M', 'B'], 1000);\n\n const formatCostValue = (params: GridRenderCellParams, period: string): string => {\n const value = params.value;\n if (typeof value === 'number') {\n const previousPeriod = period.length === 7 ? getPreviousMonth(params.field) : '';\n const formattedValue = humanFormat(value, {\n scale: customScale,\n separator: '',\n decimals: 2,\n });\n if (periods.includes(previousPeriod) && params.row.reports[previousPeriod] > 0) {\n const diff = params.row.reports[params.field] - params.row.reports[previousPeriod];\n const percentage = Math.round((diff / params.row.reports[previousPeriod]) * 100);\n const mark = diff > 0 ? '+' : '';\n // only display percentage change if it is larger than 1% or less than -1%\n if (percentage >= 1 || percentage <= -1) {\n return `$${formattedValue} (${mark}${percentage}%)`;\n }\n }\n return `$${formattedValue}`;\n }\n return '-';\n };\n\n const columns: GridColDef[] = [];\n if (['account', 'provider', 'service'].includes(aggregatedBy)) {\n columns.push({\n field: 'PROVIDER',\n headerName: '',\n width: 30,\n disableExport: true,\n renderCell: (params: GridRenderCellParams): React.ReactNode => {\n return getProviderIcon(params.row.provider);\n },\n });\n }\n\n columns.push(\n {\n field: aggregatedBy,\n headerName: aggregatedBy.toLocaleUpperCase('en-US'),\n minWidth: 200,\n flex: 2,\n renderCell: (params: GridRenderCellParams): React.ReactNode => {\n let formattedValue = params.formattedValue;\n\n if (aggregatedBy === 'service' || aggregatedBy === 'account') {\n // remove provider names\n if (params.formattedValue !== undefined && params.formattedValue.indexOf('/') !== -1) {\n formattedValue = params.formattedValue.split('/')[1];\n }\n\n if (aggregatedBy === 'account' && formattedValue) {\n const account = extractAccountInfo(formattedValue);\n const accountName = account.accountName;\n const accountId = account.accountId;\n\n return (\n <div>\n <Typography variant=\"body2\" className={classes.container}>\n {accountName}\n </Typography>\n <Typography variant=\"caption\" className={classes.container} color=\"textSecondary\">\n {accountId}\n </Typography>\n </div>\n );\n }\n }\n\n return (\n <Typography variant=\"body2\" component=\"div\" className={classes.container}>\n {formattedValue}\n </Typography>\n );\n },\n },\n {\n field: 'TREND',\n headerName: 'TREND',\n width: 100,\n disableExport: true,\n hideSortIcons: true,\n renderCell: (params: GridRenderCellParams) => (\n <SparkLineChart data={params.value ? params.value[0] : null} plotType=\"bar\" />\n ),\n valueGetter: (_, row) => [\n periods.map(period => (row.reports[period] !== undefined ? row.reports[period] : null)),\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 renderCell: (params: GridRenderCellParams): React.ReactNode => {\n const formattedValue = formatCostValue(params, period);\n let className = '';\n const percentageIndex = formattedValue.indexOf('(');\n const costStr = percentageIndex === -1 ? formattedValue : formattedValue.substring(0, percentageIndex);\n let percentageStr = percentageIndex === -1 ? '' : formattedValue.substring(percentageIndex);\n if (percentageStr.includes('-')) {\n className = classes.decrease;\n percentageStr = percentageStr.replace('-', '▼');\n } else if (percentageStr.includes('+')) {\n className = classes.increase;\n percentageStr = percentageStr.replace('+', '▲');\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 renderCell: (params: GridRenderCellParams): React.ReactNode => {\n let formattedValue = '-';\n if (typeof params.value === 'number') {\n formattedValue = `$${humanFormat(params.value, {\n scale: customScale,\n separator: '',\n decimals: 2,\n })}`;\n }\n return <Typography variant=\"body2\">{formattedValue}</Typography>;\n },\n });\n\n return (\n <Box>\n <DataGrid\n rows={reports}\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={[15]}\n slots={{ toolbar: CustomToolbar }}\n disableRowSelectionOnClick\n disableColumnMenu\n density={aggregatedBy === 'account' ? 'standard' : 'compact'}\n />\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ import TableHead from '@material-ui/core/TableHead';
9
9
  import TableRow from '@material-ui/core/TableRow';
10
10
  import CancelIcon from '@material-ui/icons/Close';
11
11
  import Alert from '@material-ui/lab/Alert';
12
+ import AlertTitle from '@material-ui/lab/AlertTitle';
12
13
  import React from 'react';
13
14
 
14
15
  const ErrorsAlertComponent = ({ errors }) => {
@@ -31,8 +32,8 @@ const ErrorsAlertComponent = ({ errors }) => {
31
32
  /* @__PURE__ */ React.createElement(CancelIcon, { fontSize: "inherit" })
32
33
  )
33
34
  },
34
- /* @__PURE__ */ React.createElement("p", null, "InfraWallet failed to fetch cloud costs from some of the configured accounts. Here are the list of errors."),
35
- /* @__PURE__ */ React.createElement(TableContainer, { component: Paper }, /* @__PURE__ */ React.createElement(Table, { "aria-label": "errors table" }, /* @__PURE__ */ React.createElement(TableHead, null, /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(TableCell, { style: { minWidth: "150px" } }, "Account Name"), /* @__PURE__ */ React.createElement(TableCell, null, "Error Message"))), /* @__PURE__ */ React.createElement(TableBody, null, errors.map((row) => /* @__PURE__ */ React.createElement(TableRow, { key: row.name }, /* @__PURE__ */ React.createElement(TableCell, null, row.name), /* @__PURE__ */ React.createElement(TableCell, null, row.error))))))
35
+ /* @__PURE__ */ React.createElement(AlertTitle, null, "InfraWallet failed to fetch data from some accounts. Here is the list of errors."),
36
+ /* @__PURE__ */ React.createElement(TableContainer, { component: Paper }, /* @__PURE__ */ React.createElement(Table, { "aria-label": "errors table" }, /* @__PURE__ */ React.createElement(TableHead, null, /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(TableCell, { style: { minWidth: "150px" } }, "Account/Integration"), /* @__PURE__ */ React.createElement(TableCell, null, "Error Message"))), /* @__PURE__ */ React.createElement(TableBody, null, errors.map((row) => /* @__PURE__ */ React.createElement(TableRow, { key: row.name }, /* @__PURE__ */ React.createElement(TableCell, null, row.name), /* @__PURE__ */ React.createElement(TableCell, null, row.error))))))
36
37
  ));
37
38
  };
38
39
 
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorsAlertComponent.esm.js","sources":["../../../src/components/ErrorsAlertComponent/ErrorsAlertComponent.tsx"],"sourcesContent":["import Collapse from '@material-ui/core/Collapse';\nimport IconButton from '@material-ui/core/IconButton';\nimport Paper from '@material-ui/core/Paper';\nimport Table from '@material-ui/core/Table';\nimport TableBody from '@material-ui/core/TableBody';\nimport TableCell from '@material-ui/core/TableCell';\nimport TableContainer from '@material-ui/core/TableContainer';\nimport TableHead from '@material-ui/core/TableHead';\nimport TableRow from '@material-ui/core/TableRow';\nimport CloseIcon from '@material-ui/icons/Close';\nimport Alert from '@material-ui/lab/Alert';\nimport React, { FC } from 'react';\nimport { CloudProviderError } from '../../api/types';\n\nexport const ErrorsAlertComponent: FC<{ errors: CloudProviderError[] }> = ({ errors }) => {\n const [open, setOpen] = React.useState(true);\n\n return (\n <Collapse in={open}>\n <Alert\n severity=\"warning\"\n style={{ maxHeight: '300px', overflow: 'auto' }}\n action={\n <IconButton\n aria-label=\"close\"\n color=\"inherit\"\n size=\"small\"\n onClick={() => {\n setOpen(false);\n }}\n >\n <CloseIcon fontSize=\"inherit\" />\n </IconButton>\n }\n >\n <p>\n InfraWallet failed to fetch cloud costs from some of the configured accounts. Here are the list of errors.\n </p>\n <TableContainer component={Paper}>\n <Table aria-label=\"errors table\">\n <TableHead>\n <TableRow>\n <TableCell style={{ minWidth: '150px' }}>Account Name</TableCell>\n <TableCell>Error Message</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {errors.map(row => (\n <TableRow key={row.name}>\n <TableCell>{row.name}</TableCell>\n <TableCell>{row.error}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </TableContainer>\n </Alert>\n </Collapse>\n );\n};\n"],"names":["CloseIcon"],"mappings":";;;;;;;;;;;;;AAcO,MAAM,oBAA6D,GAAA,CAAC,EAAE,MAAA,EAAa,KAAA;AACxF,EAAA,MAAM,CAAC,IAAM,EAAA,OAAO,CAAI,GAAA,KAAA,CAAM,SAAS,IAAI,CAAA,CAAA;AAE3C,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,QAAS,EAAA,EAAA,EAAA,EAAI,IACZ,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,QAAS,EAAA,SAAA;AAAA,MACT,KAAO,EAAA,EAAE,SAAW,EAAA,OAAA,EAAS,UAAU,MAAO,EAAA;AAAA,MAC9C,MACE,kBAAA,KAAA,CAAA,aAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,YAAW,EAAA,OAAA;AAAA,UACX,KAAM,EAAA,SAAA;AAAA,UACN,IAAK,EAAA,OAAA;AAAA,UACL,SAAS,MAAM;AACb,YAAA,OAAA,CAAQ,KAAK,CAAA,CAAA;AAAA,WACf;AAAA,SAAA;AAAA,wBAEA,KAAA,CAAA,aAAA,CAACA,UAAU,EAAA,EAAA,QAAA,EAAS,SAAU,EAAA,CAAA;AAAA,OAChC;AAAA,KAAA;AAAA,oBAGF,KAAA,CAAA,aAAA,CAAC,WAAE,4GAEH,CAAA;AAAA,oBACA,KAAA,CAAA,aAAA,CAAC,kBAAe,SAAW,EAAA,KAAA,EAAA,sCACxB,KAAM,EAAA,EAAA,YAAA,EAAW,cAChB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,SACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,gCACE,KAAA,CAAA,aAAA,CAAA,SAAA,EAAA,EAAU,KAAO,EAAA,EAAE,QAAU,EAAA,OAAA,MAAW,cAAY,CAAA,kBACpD,KAAA,CAAA,aAAA,CAAA,SAAA,EAAA,IAAA,EAAU,eAAa,CAC1B,CACF,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,iBACE,MAAO,CAAA,GAAA,CAAI,yBACT,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,GAAK,EAAA,GAAA,CAAI,IACjB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,iBAAW,GAAI,CAAA,IAAK,CACrB,kBAAA,KAAA,CAAA,aAAA,CAAC,SAAW,EAAA,IAAA,EAAA,GAAA,CAAI,KAAM,CACxB,CACD,CACH,CACF,CACF,CAAA;AAAA,GAEJ,CAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"ErrorsAlertComponent.esm.js","sources":["../../../src/components/ErrorsAlertComponent/ErrorsAlertComponent.tsx"],"sourcesContent":["import Collapse from '@material-ui/core/Collapse';\nimport IconButton from '@material-ui/core/IconButton';\nimport Paper from '@material-ui/core/Paper';\nimport Table from '@material-ui/core/Table';\nimport TableBody from '@material-ui/core/TableBody';\nimport TableCell from '@material-ui/core/TableCell';\nimport TableContainer from '@material-ui/core/TableContainer';\nimport TableHead from '@material-ui/core/TableHead';\nimport TableRow from '@material-ui/core/TableRow';\nimport CloseIcon from '@material-ui/icons/Close';\nimport Alert from '@material-ui/lab/Alert';\nimport AlertTitle from '@material-ui/lab/AlertTitle';\nimport React, { FC } from 'react';\nimport { CloudProviderError } from '../../api/types';\n\nexport const ErrorsAlertComponent: FC<{ errors: CloudProviderError[] }> = ({ errors }) => {\n const [open, setOpen] = React.useState(true);\n\n return (\n <Collapse in={open}>\n <Alert\n severity=\"warning\"\n style={{ maxHeight: '300px', overflow: 'auto' }}\n action={\n <IconButton\n aria-label=\"close\"\n color=\"inherit\"\n size=\"small\"\n onClick={() => {\n setOpen(false);\n }}\n >\n <CloseIcon fontSize=\"inherit\" />\n </IconButton>\n }\n >\n <AlertTitle>InfraWallet failed to fetch data from some accounts. Here is the list of errors.</AlertTitle>\n <TableContainer component={Paper}>\n <Table aria-label=\"errors table\">\n <TableHead>\n <TableRow>\n <TableCell style={{ minWidth: '150px' }}>Account/Integration</TableCell>\n <TableCell>Error Message</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {errors.map(row => (\n <TableRow key={row.name}>\n <TableCell>{row.name}</TableCell>\n <TableCell>{row.error}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </TableContainer>\n </Alert>\n </Collapse>\n );\n};\n"],"names":["CloseIcon"],"mappings":";;;;;;;;;;;;;;AAeO,MAAM,oBAA6D,GAAA,CAAC,EAAE,MAAA,EAAa,KAAA;AACxF,EAAA,MAAM,CAAC,IAAM,EAAA,OAAO,CAAI,GAAA,KAAA,CAAM,SAAS,IAAI,CAAA,CAAA;AAE3C,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,QAAS,EAAA,EAAA,EAAA,EAAI,IACZ,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,QAAS,EAAA,SAAA;AAAA,MACT,KAAO,EAAA,EAAE,SAAW,EAAA,OAAA,EAAS,UAAU,MAAO,EAAA;AAAA,MAC9C,MACE,kBAAA,KAAA,CAAA,aAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,YAAW,EAAA,OAAA;AAAA,UACX,KAAM,EAAA,SAAA;AAAA,UACN,IAAK,EAAA,OAAA;AAAA,UACL,SAAS,MAAM;AACb,YAAA,OAAA,CAAQ,KAAK,CAAA,CAAA;AAAA,WACf;AAAA,SAAA;AAAA,wBAEA,KAAA,CAAA,aAAA,CAACA,UAAU,EAAA,EAAA,QAAA,EAAS,SAAU,EAAA,CAAA;AAAA,OAChC;AAAA,KAAA;AAAA,oBAGF,KAAA,CAAA,aAAA,CAAC,kBAAW,kFAAgF,CAAA;AAAA,oBAC5F,KAAA,CAAA,aAAA,CAAC,kBAAe,SAAW,EAAA,KAAA,EAAA,sCACxB,KAAM,EAAA,EAAA,YAAA,EAAW,cAChB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,SACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,gCACE,KAAA,CAAA,aAAA,CAAA,SAAA,EAAA,EAAU,KAAO,EAAA,EAAE,QAAU,EAAA,OAAA,MAAW,qBAAmB,CAAA,kBAC3D,KAAA,CAAA,aAAA,CAAA,SAAA,EAAA,IAAA,EAAU,eAAa,CAC1B,CACF,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,iBACE,MAAO,CAAA,GAAA,CAAI,yBACT,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,GAAK,EAAA,GAAA,CAAI,IACjB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,iBAAW,GAAI,CAAA,IAAK,CACrB,kBAAA,KAAA,CAAA,aAAA,CAAC,SAAW,EAAA,IAAA,EAAA,GAAA,CAAI,KAAM,CACxB,CACD,CACH,CACF,CACF,CAAA;AAAA,GAEJ,CAAA,CAAA;AAEJ;;;;"}
@@ -1,13 +1,16 @@
1
- import { Box, FormControl } from '@material-ui/core';
1
+ import { Tooltip, Grid, FormControl, Typography, Divider, CircularProgress, Chip } from '@material-ui/core';
2
2
  import Button from '@material-ui/core/Button';
3
3
  import Checkbox from '@material-ui/core/Checkbox';
4
4
  import TextField from '@material-ui/core/TextField';
5
- import { makeStyles } from '@material-ui/core/styles';
5
+ import { makeStyles, withStyles } from '@material-ui/core/styles';
6
6
  import CheckBoxIcon from '@material-ui/icons/CheckBox';
7
7
  import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
8
8
  import Autocomplete from '@material-ui/lab/Autocomplete';
9
- import React from 'react';
10
- import { getReportKeyAndValues } from '../../api/functions.esm.js';
9
+ import React, { useState, useEffect } from 'react';
10
+ import { getReportKeyAndValues, extractProvider, extractAccountInfo, tagExists } from '../../api/functions.esm.js';
11
+ import { useApi, alertApiRef } from '@backstage/core-plugin-api';
12
+ import { infraWalletApiRef } from '../../api/InfraWalletApi.esm.js';
13
+ import { getProviderIcon } from '../ProviderIcons/ProviderIcons.esm.js';
11
14
 
12
15
  const useStyles = makeStyles((theme) => ({
13
16
  formControl: {
@@ -18,25 +21,228 @@ const useStyles = makeStyles((theme) => ({
18
21
  }));
19
22
  const icon = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
20
23
  const checkedIcon = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
21
- const FiltersComponent = ({ reports, filters, filtersSetter }) => {
24
+ const HtmlTooltip = withStyles((theme) => ({
25
+ tooltip: {
26
+ backgroundColor: "#f5f5f9",
27
+ color: "rgba(0, 0, 0, 0.87)",
28
+ maxWidth: 400,
29
+ fontSize: theme.typography.pxToRem(14),
30
+ border: "1px solid #dadde9"
31
+ }
32
+ }))(Tooltip);
33
+ const FiltersComponent = ({
34
+ reports,
35
+ filters,
36
+ monthRange,
37
+ filtersSetter,
38
+ selectedTagsSetter,
39
+ providerErrorsSetter
40
+ }) => {
22
41
  const classes = useStyles();
23
42
  const keyValues = getReportKeyAndValues(reports);
43
+ const [tagProviders, _setTagProviders] = useState(["AWS", "Azure"]);
44
+ const [tagProvider, setTagProvider] = useState();
45
+ const [openTagKey, setOpenTagKey] = useState(false);
46
+ const [tagKeys, setTagKeys] = useState([]);
47
+ const [selectedTagKey, setSelectedTagKey] = useState(null);
48
+ const [resetTagKeys, setResetTagKeys] = useState(false);
49
+ const loadingTagKeys = openTagKey && tagKeys.length === 0;
50
+ const [openTagValue, setOpenTagValue] = useState(false);
51
+ const [tagValues, setTagValues] = useState([]);
52
+ const [resetTagValues, setResetTagValues] = useState(false);
53
+ const loadingTagValues = openTagValue && tagValues.length === 0;
54
+ const [selectedTags, setSelectedTags] = useState([]);
55
+ const infraWalletApi = useApi(infraWalletApiRef);
56
+ const alertApi = useApi(alertApiRef);
24
57
  const handleFiltersChange = (key, newValue) => {
25
58
  filtersSetter({ ...filters, [key]: newValue });
26
59
  };
27
- return /* @__PURE__ */ React.createElement(Box, null, Object.keys(keyValues).map((key) => /* @__PURE__ */ React.createElement(FormControl, { className: classes.formControl, key: `form-${key}` }, /* @__PURE__ */ React.createElement(
60
+ const handleTagProviderChange = (provider) => {
61
+ setTagProvider("");
62
+ setOpenTagKey(false);
63
+ setResetTagKeys((prev) => !prev);
64
+ setTagKeys([]);
65
+ setSelectedTagKey(null);
66
+ setOpenTagValue(false);
67
+ setTagValues([]);
68
+ if (provider) {
69
+ setTagProvider(provider);
70
+ setOpenTagKey(true);
71
+ }
72
+ };
73
+ const handleTagKeyChange = (tagKey) => {
74
+ setSelectedTagKey(null);
75
+ setTagValues([]);
76
+ setResetTagValues((prev) => !prev);
77
+ if (typeof tagKey === "string") {
78
+ return;
79
+ }
80
+ if (tagKey) {
81
+ setSelectedTagKey(tagKey);
82
+ setOpenTagValue(true);
83
+ }
84
+ };
85
+ const handleTagValueSelection = (tag) => {
86
+ if (typeof tag === "string") {
87
+ return;
88
+ }
89
+ if (tag && !tagExists(selectedTags, tag)) {
90
+ setResetTagValues((prev) => !prev);
91
+ setSelectedTags([...selectedTags, tag]);
92
+ }
93
+ };
94
+ const handleDeleteTag = (tagToDelete) => () => {
95
+ setSelectedTags(
96
+ selectedTags.filter(
97
+ (tag) => !(tag.provider === tagToDelete.provider && tag.key === tagToDelete.key && tag.value === tagToDelete.value)
98
+ )
99
+ );
100
+ };
101
+ useEffect(() => {
102
+ if (!loadingTagKeys) {
103
+ return;
104
+ }
105
+ (async () => {
106
+ if (tagProvider) {
107
+ await infraWalletApi.getTagKeys(tagProvider, monthRange.startMonth, monthRange.endMonth).then((response) => {
108
+ if (response.data && response.data.length > 0) {
109
+ setTagKeys(response.data);
110
+ }
111
+ if (response.status === 207 && response.errors) {
112
+ providerErrorsSetter(response.errors);
113
+ }
114
+ }).catch((e) => alertApi.post({ message: `${e.message}`, severity: "error" }));
115
+ }
116
+ })();
117
+ }, [loadingTagKeys, tagProvider, monthRange, infraWalletApi, alertApi, providerErrorsSetter]);
118
+ useEffect(() => {
119
+ if (!loadingTagValues) {
120
+ return;
121
+ }
122
+ (async () => {
123
+ if (selectedTagKey) {
124
+ await infraWalletApi.getTagValues(selectedTagKey, monthRange.startMonth, monthRange.endMonth).then((response) => {
125
+ if (response.data && response.data.length > 0) {
126
+ setTagValues(response.data);
127
+ }
128
+ if (response.status === 207 && response.errors) {
129
+ providerErrorsSetter(response.errors);
130
+ }
131
+ }).catch((e) => alertApi.post({ message: `${e.message}`, severity: "error" }));
132
+ }
133
+ })();
134
+ }, [loadingTagValues, selectedTagKey, monthRange, infraWalletApi, alertApi, providerErrorsSetter]);
135
+ return /* @__PURE__ */ React.createElement(Grid, { container: true }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, Object.keys(keyValues).map((key) => /* @__PURE__ */ React.createElement(FormControl, { className: classes.formControl, key: `form-${key}` }, /* @__PURE__ */ React.createElement(
28
136
  Autocomplete,
29
137
  {
30
138
  multiple: true,
31
139
  id: `checkboxes-${key}`,
32
- options: keyValues[key],
140
+ options: keyValues[key].sort(),
33
141
  value: filters[key] || [],
34
142
  onChange: (_event, value, _reason) => handleFiltersChange(key, value),
35
143
  disableCloseOnSelect: true,
36
- renderOption: (option, { selected }) => /* @__PURE__ */ React.createElement(React.Fragment, { key: `option-${option}` }, /* @__PURE__ */ React.createElement(Checkbox, { icon, checkedIcon, style: { marginRight: 8 }, checked: selected }), option),
37
- renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, { ...params, variant: "standard", label: key })
144
+ renderOption: (option, { selected }) => {
145
+ let provider = void 0;
146
+ let providerIcon = void 0;
147
+ let accountName = void 0;
148
+ let accountId = void 0;
149
+ if (key === "provider") {
150
+ provider = option;
151
+ providerIcon = getProviderIcon(provider);
152
+ } else if (["account", "service"].includes(key)) {
153
+ provider = extractProvider(option);
154
+ providerIcon = getProviderIcon(provider);
155
+ }
156
+ if (key === "account") {
157
+ const account = extractAccountInfo(option.replace(`${provider}/`, ""));
158
+ accountName = account.accountName;
159
+ accountId = account.accountId;
160
+ }
161
+ return /* @__PURE__ */ React.createElement(React.Fragment, { key: `option-${option}` }, /* @__PURE__ */ React.createElement(Checkbox, { icon, checkedIcon, style: { marginRight: 8 }, checked: selected }), providerIcon && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, null, providerIcon), "\xA0\xA0"), key === "account" ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, accountName), /* @__PURE__ */ React.createElement(Typography, { variant: "caption", color: "textSecondary" }, accountId)) : /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, option.replace(`${provider}/`, "")));
162
+ },
163
+ renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, { ...params, variant: "standard", label: key.charAt(0).toUpperCase() + key.slice(1) })
164
+ }
165
+ ))), /* @__PURE__ */ React.createElement(FormControl, { style: { marginTop: 10 } }, /* @__PURE__ */ React.createElement(Button, { variant: "contained", color: "primary", onClick: () => filtersSetter({}) }, "Clear filters"))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, null)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(FormControl, { className: classes.formControl }, /* @__PURE__ */ React.createElement(
166
+ Autocomplete,
167
+ {
168
+ id: "tag-providers",
169
+ options: tagProviders,
170
+ onChange: (_, provider) => handleTagProviderChange(provider),
171
+ renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, { ...params, variant: "standard", label: "Tag provider" }),
172
+ renderOption: (option) => /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, option))
173
+ }
174
+ )), /* @__PURE__ */ React.createElement(FormControl, { className: classes.formControl }, /* @__PURE__ */ React.createElement(
175
+ Autocomplete,
176
+ {
177
+ id: "tag-keys",
178
+ key: String(resetTagKeys),
179
+ freeSolo: true,
180
+ disabled: tagProvider ? false : true,
181
+ open: openTagKey,
182
+ onOpen: () => setOpenTagKey(true),
183
+ onClose: () => setOpenTagKey(false),
184
+ options: tagKeys,
185
+ getOptionLabel: (tag) => tag.key,
186
+ loading: loadingTagKeys,
187
+ onChange: (_, tagKey) => handleTagKeyChange(tagKey),
188
+ renderInput: (params) => /* @__PURE__ */ React.createElement(
189
+ TextField,
190
+ {
191
+ ...params,
192
+ variant: "standard",
193
+ label: "Tag keys",
194
+ InputProps: {
195
+ ...params.InputProps,
196
+ endAdornment: /* @__PURE__ */ React.createElement(React.Fragment, null, loadingTagKeys ? /* @__PURE__ */ React.createElement(CircularProgress, { color: "inherit", size: 20 }) : null, params.InputProps && params.InputProps.endAdornment)
197
+ }
198
+ }
199
+ ),
200
+ renderOption: (option) => /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, option.key))
201
+ }
202
+ )), /* @__PURE__ */ React.createElement(FormControl, { className: classes.formControl }, /* @__PURE__ */ React.createElement(
203
+ Autocomplete,
204
+ {
205
+ id: "tag-values",
206
+ key: String(resetTagValues),
207
+ freeSolo: true,
208
+ disabled: selectedTagKey ? false : true,
209
+ open: openTagValue,
210
+ onOpen: () => setOpenTagValue(true),
211
+ onClose: () => setOpenTagValue(false),
212
+ options: tagValues,
213
+ getOptionLabel: (tag) => (tag == null ? void 0 : tag.value) || "",
214
+ getOptionDisabled: (tag) => tagExists(selectedTags, tag),
215
+ loading: loadingTagValues,
216
+ onChange: (_, tag) => handleTagValueSelection(tag),
217
+ renderInput: (params) => /* @__PURE__ */ React.createElement(
218
+ TextField,
219
+ {
220
+ ...params,
221
+ variant: "standard",
222
+ label: "Tag values",
223
+ InputProps: {
224
+ ...params.InputProps,
225
+ endAdornment: /* @__PURE__ */ React.createElement(React.Fragment, null, loadingTagValues ? /* @__PURE__ */ React.createElement(CircularProgress, { color: "inherit", size: 20 }) : null, params.InputProps && params.InputProps.endAdornment)
226
+ }
227
+ }
228
+ ),
229
+ renderOption: (option) => /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, option.value))
230
+ }
231
+ )), /* @__PURE__ */ React.createElement(FormControl, { style: { marginTop: 10 } }, /* @__PURE__ */ React.createElement(
232
+ HtmlTooltip,
233
+ {
234
+ title: /* @__PURE__ */ React.createElement(React.Fragment, null, "You can apply ", /* @__PURE__ */ React.createElement("b", null, "tags"), " to ", /* @__PURE__ */ React.createElement("em", null, "one or more"), " providers. ", /* @__PURE__ */ React.createElement("b", null, "Tags"), " will only filter the costs for the ", /* @__PURE__ */ React.createElement("b", null, "selected providers"), ", while ", /* @__PURE__ */ React.createElement("em", null, "others remain unchanged"), ".")
235
+ },
236
+ /* @__PURE__ */ React.createElement(Button, { variant: "contained", color: "primary", onClick: () => selectedTagsSetter(selectedTags) }, "Apply")
237
+ ))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, selectedTags.map((tag) => /* @__PURE__ */ React.createElement(
238
+ Chip,
239
+ {
240
+ size: "small",
241
+ key: `${tag.provider}/${tag.key}=${tag.value}`,
242
+ label: `${tag.provider}/${tag.key}=${tag.value}`,
243
+ onDelete: handleDeleteTag(tag)
38
244
  }
39
- ))), /* @__PURE__ */ React.createElement(FormControl, { className: classes.formControl, style: { marginTop: 10 } }, /* @__PURE__ */ React.createElement(Button, { variant: "contained", color: "primary", onClick: () => filtersSetter({}) }, "Clear filters")));
245
+ ))));
40
246
  };
41
247
 
42
248
  export { FiltersComponent };
@@ -1 +1 @@
1
- {"version":3,"file":"FiltersComponent.esm.js","sources":["../../../src/components/FiltersComponent/FiltersComponent.tsx"],"sourcesContent":["import { Box, FormControl } from '@material-ui/core';\nimport Button from '@material-ui/core/Button';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport TextField from '@material-ui/core/TextField';\nimport { makeStyles } from '@material-ui/core/styles';\nimport CheckBoxIcon from '@material-ui/icons/CheckBox';\nimport CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport React, { FC } from 'react';\nimport { getReportKeyAndValues } from '../../api/functions';\nimport { FiltersComponentProps } from '../types';\n\nconst useStyles = makeStyles(theme => ({\n formControl: {\n marginLeft: theme.spacing(1),\n marginRight: theme.spacing(3),\n width: 300,\n },\n}));\nconst icon = <CheckBoxOutlineBlankIcon fontSize=\"small\" />;\nconst checkedIcon = <CheckBoxIcon fontSize=\"small\" />;\n\nexport const FiltersComponent: FC<FiltersComponentProps> = ({ reports, filters, filtersSetter }) => {\n const classes = useStyles();\n const keyValues: { [key: string]: string[] } = getReportKeyAndValues(reports);\n const handleFiltersChange = (key: string, newValue: string[]): void => {\n filtersSetter({ ...filters, [key]: newValue });\n };\n\n return (\n <Box>\n {Object.keys(keyValues).map(key => (\n <FormControl className={classes.formControl} key={`form-${key}`}>\n <Autocomplete\n multiple\n id={`checkboxes-${key}`}\n options={keyValues[key]}\n value={filters[key] || []}\n onChange={(_event, value: string[], _reason) => handleFiltersChange(key, value)}\n disableCloseOnSelect\n renderOption={(option, { selected }) => (\n <React.Fragment key={`option-${option}`}>\n <Checkbox icon={icon} checkedIcon={checkedIcon} style={{ marginRight: 8 }} checked={selected} />\n {option}\n </React.Fragment>\n )}\n renderInput={params => <TextField {...params} variant=\"standard\" label={key} />}\n />\n </FormControl>\n ))}\n <FormControl className={classes.formControl} style={{ marginTop: 10 }}>\n <Button variant=\"contained\" color=\"primary\" onClick={() => filtersSetter({})}>\n Clear filters\n </Button>\n </FormControl>\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AAYA,MAAM,SAAA,GAAY,WAAW,CAAU,KAAA,MAAA;AAAA,EACrC,WAAa,EAAA;AAAA,IACX,UAAA,EAAY,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC3B,WAAA,EAAa,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC5B,KAAO,EAAA,GAAA;AAAA,GACT;AACF,CAAE,CAAA,CAAA,CAAA;AACF,MAAM,IAAO,mBAAA,KAAA,CAAA,aAAA,CAAC,wBAAyB,EAAA,EAAA,QAAA,EAAS,OAAQ,EAAA,CAAA,CAAA;AACxD,MAAM,WAAc,mBAAA,KAAA,CAAA,aAAA,CAAC,YAAa,EAAA,EAAA,QAAA,EAAS,OAAQ,EAAA,CAAA,CAAA;AAE5C,MAAM,mBAA8C,CAAC,EAAE,OAAS,EAAA,OAAA,EAAS,eAAoB,KAAA;AAClG,EAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAC1B,EAAM,MAAA,SAAA,GAAyC,sBAAsB,OAAO,CAAA,CAAA;AAC5E,EAAM,MAAA,mBAAA,GAAsB,CAAC,GAAA,EAAa,QAA6B,KAAA;AACrE,IAAA,aAAA,CAAc,EAAE,GAAG,OAAA,EAAS,CAAC,GAAG,GAAG,UAAU,CAAA,CAAA;AAAA,GAC/C,CAAA;AAEA,EAAA,2CACG,GACE,EAAA,IAAA,EAAA,MAAA,CAAO,IAAK,CAAA,SAAS,EAAE,GAAI,CAAA,CAAA,GAAA,qBACzB,KAAA,CAAA,aAAA,CAAA,WAAA,EAAA,EAAY,WAAW,OAAQ,CAAA,WAAA,EAAa,GAAK,EAAA,CAAA,KAAA,EAAQ,GAAG,CAC3D,CAAA,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MACC,QAAQ,EAAA,IAAA;AAAA,MACR,EAAA,EAAI,cAAc,GAAG,CAAA,CAAA;AAAA,MACrB,OAAA,EAAS,UAAU,GAAG,CAAA;AAAA,MACtB,KAAO,EAAA,OAAA,CAAQ,GAAG,CAAA,IAAK,EAAC;AAAA,MACxB,UAAU,CAAC,MAAA,EAAQ,OAAiB,OAAY,KAAA,mBAAA,CAAoB,KAAK,KAAK,CAAA;AAAA,MAC9E,oBAAoB,EAAA,IAAA;AAAA,MACpB,YAAA,EAAc,CAAC,MAAA,EAAQ,EAAE,QAAA,EACvB,qBAAA,KAAA,CAAA,aAAA,CAAC,KAAM,CAAA,QAAA,EAAN,EAAe,GAAA,EAAK,CAAU,OAAA,EAAA,MAAM,sBAClC,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,IAAY,EAAA,WAAA,EAA0B,KAAO,EAAA,EAAE,WAAa,EAAA,CAAA,EAAK,EAAA,OAAA,EAAS,QAAU,EAAA,CAAA,EAC7F,MACH,CAAA;AAAA,MAEF,WAAA,EAAa,4BAAW,KAAA,CAAA,aAAA,CAAA,SAAA,EAAA,EAAW,GAAG,MAAQ,EAAA,OAAA,EAAQ,UAAW,EAAA,KAAA,EAAO,GAAK,EAAA,CAAA;AAAA,KAAA;AAAA,GAEjF,CACD,CAAA,kBACA,KAAA,CAAA,aAAA,CAAA,WAAA,EAAA,EAAY,SAAW,EAAA,OAAA,CAAQ,WAAa,EAAA,KAAA,EAAO,EAAE,SAAA,EAAW,EAAG,EAAA,EAAA,kBACjE,KAAA,CAAA,aAAA,CAAA,MAAA,EAAA,EAAO,OAAQ,EAAA,WAAA,EAAY,KAAM,EAAA,SAAA,EAAU,OAAS,EAAA,MAAM,aAAc,CAAA,EAAE,CAAA,EAAA,EAAG,eAE9E,CACF,CACF,CAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"FiltersComponent.esm.js","sources":["../../../src/components/FiltersComponent/FiltersComponent.tsx"],"sourcesContent":["import { Chip, CircularProgress, Divider, FormControl, Grid, Tooltip, Typography } from '@material-ui/core';\nimport Button from '@material-ui/core/Button';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport TextField from '@material-ui/core/TextField';\nimport { Theme, makeStyles, withStyles } from '@material-ui/core/styles';\nimport CheckBoxIcon from '@material-ui/icons/CheckBox';\nimport CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport React, { FC, useEffect, useState } from 'react';\nimport { extractAccountInfo, extractProvider, getReportKeyAndValues, tagExists } from '../../api/functions';\nimport { FiltersComponentProps } from '../types';\nimport { Tag } from '../../api/types';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport { infraWalletApiRef } from '../../api/InfraWalletApi';\nimport { getProviderIcon } from '../ProviderIcons';\n\nconst useStyles = makeStyles(theme => ({\n formControl: {\n marginLeft: theme.spacing(1),\n marginRight: theme.spacing(3),\n width: 300,\n },\n}));\n\nconst icon = <CheckBoxOutlineBlankIcon fontSize=\"small\" />;\nconst checkedIcon = <CheckBoxIcon fontSize=\"small\" />;\n\nconst HtmlTooltip = withStyles((theme: Theme) => ({\n tooltip: {\n backgroundColor: '#f5f5f9',\n color: 'rgba(0, 0, 0, 0.87)',\n maxWidth: 400,\n fontSize: theme.typography.pxToRem(14),\n border: '1px solid #dadde9',\n },\n}))(Tooltip);\n\nexport const FiltersComponent: FC<FiltersComponentProps> = ({\n reports,\n filters,\n monthRange,\n filtersSetter,\n selectedTagsSetter,\n providerErrorsSetter,\n}) => {\n const classes = useStyles();\n const keyValues: { [key: string]: string[] } = getReportKeyAndValues(reports);\n\n // tag providers\n const [tagProviders, _setTagProviders] = useState<string[]>(['AWS', 'Azure']);\n const [tagProvider, setTagProvider] = useState<string>();\n\n // tag keys\n const [openTagKey, setOpenTagKey] = useState(false);\n const [tagKeys, setTagKeys] = useState<Tag[]>([]);\n const [selectedTagKey, setSelectedTagKey] = useState<Tag | null>(null);\n const [resetTagKeys, setResetTagKeys] = useState(false);\n const loadingTagKeys = openTagKey && tagKeys.length === 0;\n\n // tag values\n const [openTagValue, setOpenTagValue] = useState(false);\n const [tagValues, setTagValues] = useState<Tag[]>([]);\n const [resetTagValues, setResetTagValues] = useState(false);\n const loadingTagValues = openTagValue && tagValues.length === 0;\n\n // user selected tags\n const [selectedTags, setSelectedTags] = useState<Tag[]>([]);\n\n const infraWalletApi = useApi(infraWalletApiRef);\n const alertApi = useApi(alertApiRef);\n\n const handleFiltersChange = (key: string, newValue: string[]): void => {\n filtersSetter({ ...filters, [key]: newValue });\n };\n\n const handleTagProviderChange = (provider: string | null) => {\n setTagProvider('');\n setOpenTagKey(false);\n setResetTagKeys(prev => !prev);\n setTagKeys([]);\n setSelectedTagKey(null);\n setOpenTagValue(false);\n setTagValues([]);\n\n if (provider) {\n setTagProvider(provider);\n setOpenTagKey(true);\n }\n };\n\n const handleTagKeyChange = (tagKey: Tag | string | null) => {\n setSelectedTagKey(null);\n setTagValues([]);\n setResetTagValues(prev => !prev);\n\n if (typeof tagKey === 'string') {\n return;\n }\n\n if (tagKey) {\n setSelectedTagKey(tagKey);\n setOpenTagValue(true);\n }\n };\n\n const handleTagValueSelection = (tag: Tag | string | null) => {\n if (typeof tag === 'string') {\n return;\n }\n\n if (tag && !tagExists(selectedTags, tag)) {\n setResetTagValues(prev => !prev);\n setSelectedTags([...selectedTags, tag]);\n }\n };\n\n const handleDeleteTag = (tagToDelete: Tag) => () => {\n setSelectedTags(\n selectedTags.filter(\n tag =>\n !(tag.provider === tagToDelete.provider && tag.key === tagToDelete.key && tag.value === tagToDelete.value),\n ),\n );\n };\n\n useEffect(() => {\n if (!loadingTagKeys) {\n return;\n }\n\n (async () => {\n if (tagProvider) {\n await infraWalletApi\n .getTagKeys(tagProvider, monthRange.startMonth, monthRange.endMonth)\n .then(response => {\n if (response.data && response.data.length > 0) {\n setTagKeys(response.data);\n }\n if (response.status === 207 && response.errors) {\n providerErrorsSetter(response.errors);\n }\n })\n .catch(e => alertApi.post({ message: `${e.message}`, severity: 'error' }));\n }\n })();\n }, [loadingTagKeys, tagProvider, monthRange, infraWalletApi, alertApi, providerErrorsSetter]);\n\n useEffect(() => {\n if (!loadingTagValues) {\n return;\n }\n\n (async () => {\n if (selectedTagKey) {\n await infraWalletApi\n .getTagValues(selectedTagKey, monthRange.startMonth, monthRange.endMonth)\n .then(response => {\n if (response.data && response.data.length > 0) {\n setTagValues(response.data);\n }\n if (response.status === 207 && response.errors) {\n providerErrorsSetter(response.errors);\n }\n })\n .catch(e => alertApi.post({ message: `${e.message}`, severity: 'error' }));\n }\n })();\n }, [loadingTagValues, selectedTagKey, monthRange, infraWalletApi, alertApi, providerErrorsSetter]);\n\n return (\n <Grid container>\n <Grid item xs={12}>\n {Object.keys(keyValues).map(key => (\n <FormControl className={classes.formControl} key={`form-${key}`}>\n <Autocomplete\n multiple\n id={`checkboxes-${key}`}\n options={keyValues[key].sort()}\n value={filters[key] || []}\n onChange={(_event, value: string[], _reason) => handleFiltersChange(key, value)}\n disableCloseOnSelect\n renderOption={(option, { selected }) => {\n let provider = undefined;\n let providerIcon = undefined;\n let accountName = undefined;\n let accountId = undefined;\n if (key === 'provider') {\n provider = option;\n providerIcon = getProviderIcon(provider);\n } else if (['account', 'service'].includes(key)) {\n provider = extractProvider(option);\n providerIcon = getProviderIcon(provider);\n }\n\n if (key === 'account') {\n const account = extractAccountInfo(option.replace(`${provider}/`, ''));\n accountName = account.accountName;\n accountId = account.accountId;\n }\n\n return (\n <React.Fragment key={`option-${option}`}>\n <Checkbox icon={icon} checkedIcon={checkedIcon} style={{ marginRight: 8 }} checked={selected} />\n {providerIcon && (\n <>\n <Typography>{providerIcon}</Typography>\n &nbsp;&nbsp;\n </>\n )}\n {key === 'account' ? (\n <div>\n <Typography variant=\"body2\">{accountName}</Typography>\n <Typography variant=\"caption\" color=\"textSecondary\">\n {accountId}\n </Typography>\n </div>\n ) : (\n <Typography variant=\"body2\">{option.replace(`${provider}/`, '')}</Typography>\n )}\n </React.Fragment>\n );\n }}\n renderInput={params => (\n <TextField {...params} variant=\"standard\" label={key.charAt(0).toUpperCase() + key.slice(1)} />\n )}\n />\n </FormControl>\n ))}\n <FormControl style={{ marginTop: 10 }}>\n <Button variant=\"contained\" color=\"primary\" onClick={() => filtersSetter({})}>\n Clear filters\n </Button>\n </FormControl>\n </Grid>\n <Grid item xs={12}>\n <Divider />\n </Grid>\n <Grid item xs={12}>\n <FormControl className={classes.formControl}>\n <Autocomplete\n id=\"tag-providers\"\n options={tagProviders}\n onChange={(_, provider) => handleTagProviderChange(provider)}\n renderInput={params => <TextField {...params} variant=\"standard\" label=\"Tag provider\" />}\n renderOption={option => (\n <React.Fragment>\n <Typography variant=\"body2\">{option}</Typography>\n </React.Fragment>\n )}\n />\n </FormControl>\n <FormControl className={classes.formControl}>\n <Autocomplete\n id=\"tag-keys\"\n key={String(resetTagKeys)}\n freeSolo\n disabled={tagProvider ? false : true}\n open={openTagKey}\n onOpen={() => setOpenTagKey(true)}\n onClose={() => setOpenTagKey(false)}\n options={tagKeys}\n getOptionLabel={tag => tag.key}\n loading={loadingTagKeys}\n onChange={(_, tagKey) => handleTagKeyChange(tagKey)}\n renderInput={params => (\n <TextField\n {...params}\n variant=\"standard\"\n label=\"Tag keys\"\n InputProps={{\n ...params.InputProps,\n endAdornment: (\n <React.Fragment>\n {loadingTagKeys ? <CircularProgress color=\"inherit\" size={20} /> : null}\n {params.InputProps && params.InputProps.endAdornment}\n </React.Fragment>\n ),\n }}\n />\n )}\n renderOption={option => (\n <React.Fragment>\n <Typography variant=\"body2\">{option.key}</Typography>\n </React.Fragment>\n )}\n />\n </FormControl>\n <FormControl className={classes.formControl}>\n <Autocomplete\n id=\"tag-values\"\n key={String(resetTagValues)}\n freeSolo\n disabled={selectedTagKey ? false : true}\n open={openTagValue}\n onOpen={() => setOpenTagValue(true)}\n onClose={() => setOpenTagValue(false)}\n options={tagValues}\n getOptionLabel={tag => tag?.value || ''}\n getOptionDisabled={tag => tagExists(selectedTags, tag)}\n loading={loadingTagValues}\n onChange={(_, tag) => handleTagValueSelection(tag)}\n renderInput={params => (\n <TextField\n {...params}\n variant=\"standard\"\n label=\"Tag values\"\n InputProps={{\n ...params.InputProps,\n endAdornment: (\n <React.Fragment>\n {loadingTagValues ? <CircularProgress color=\"inherit\" size={20} /> : null}\n {params.InputProps && params.InputProps.endAdornment}\n </React.Fragment>\n ),\n }}\n />\n )}\n renderOption={option => (\n <React.Fragment>\n <Typography variant=\"body2\">{option.value}</Typography>\n </React.Fragment>\n )}\n />\n </FormControl>\n <FormControl style={{ marginTop: 10 }}>\n <HtmlTooltip\n title={\n <React.Fragment>\n You can apply <b>tags</b> to <em>one or more</em> providers. <b>Tags</b> will only filter the costs for\n the <b>selected providers</b>, while <em>others remain unchanged</em>.\n </React.Fragment>\n }\n >\n <Button variant=\"contained\" color=\"primary\" onClick={() => selectedTagsSetter(selectedTags)}>\n Apply\n </Button>\n </HtmlTooltip>\n </FormControl>\n </Grid>\n <Grid item xs={12}>\n {selectedTags.map(tag => (\n <Chip\n size=\"small\"\n key={`${tag.provider}/${tag.key}=${tag.value}`}\n label={`${tag.provider}/${tag.key}=${tag.value}`}\n onDelete={handleDeleteTag(tag)}\n />\n ))}\n </Grid>\n </Grid>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -32,6 +32,7 @@ const MetricConfigurationComponent = ({ wallet }) => {
32
32
  config_name: "",
33
33
  metric_name: "",
34
34
  description: "",
35
+ group: "",
35
36
  query: "",
36
37
  isNew: true
37
38
  }
@@ -142,6 +143,12 @@ const MetricConfigurationComponent = ({ wallet }) => {
142
143
  width: 220,
143
144
  editable: !readOnly
144
145
  },
146
+ {
147
+ field: "group",
148
+ headerName: "Group",
149
+ width: 100,
150
+ editable: !readOnly
151
+ },
145
152
  {
146
153
  field: "query",
147
154
  headerName: "Query",