diff --git a/.changeset/slow-queens-visit.md b/.changeset/slow-queens-visit.md
index 2081215287..2df948e477 100644
--- a/.changeset/slow-queens-visit.md
+++ b/.changeset/slow-queens-visit.md
@@ -1,5 +1,5 @@
---
-'@backstage/plugin-opencost': major
+'@backstage/plugin-opencost': minor
---
New OpenCost plugin provides an port of the latest OpenCost UI to Backstage with updated dependencies. The plugin's README covers installation and configuration
diff --git a/plugins/opencost/README.md b/plugins/opencost/README.md
index d034f1b3dd..39c5e7ee2e 100644
--- a/plugins/opencost/README.md
+++ b/plugins/opencost/README.md
@@ -15,18 +15,18 @@ All of the code was originally ported from https://github.com/opencost/opencost/
```
2. Add the `OpenCostPage` to your `packages/app/src/App.tsx`:
-```tsx
-import { OpenCostPage } from '@backstage/plugin-opencost';
-```
+ ```tsx
+ import { OpenCostPage } from '@backstage/plugin-opencost';
+ ```
and
-```tsx
-
- …
- } />
-
-```
+ ```tsx
+
+ …
+ } />
+
+ ```
3. Add link to OpenCost to your sidebar
@@ -74,6 +74,6 @@ opencost:
- Allow for user-provided default reports and/or disabling controls
- Support multiple hard-coded reports
- clean up deprecation warnings and upgrade to all the latest React components
-- Fork(?) to support Kubecost, which could provide Alerts and Recommendations, similar to the Cost Explorer plugin
+- Fork(?) to support `Kubecost`, which could provide Alerts and Recommendations, similar to the Cost Explorer plugin

diff --git a/plugins/opencost/config.d.ts b/plugins/opencost/config.d.ts
index 0ff11bd1ed..0070bec7b7 100644
--- a/plugins/opencost/config.d.ts
+++ b/plugins/opencost/config.d.ts
@@ -15,13 +15,14 @@
*/
export interface Config {
- /** Configurations for the OpenCost plugin
- * opencost config
+ /**
+ * Configurations for the OpenCost plugin
+ *
* @visibility frontend
*/
opencost?: {
/**
- * The ppbase URL for the OpenCost API
+ * The base URL for the OpenCost API
* @visibility frontend
*/
baseUrl: string;
diff --git a/plugins/opencost/package.json b/plugins/opencost/package.json
index e5de3defa8..2dde15362b 100644
--- a/plugins/opencost/package.json
+++ b/plugins/opencost/package.json
@@ -31,10 +31,11 @@
"@material-ui/lab": "^4.0.0-alpha.60",
"@material-ui/pickers": "^3.3.10",
"@material-ui/styles": "^4.11.5",
+ "axios": "^1.4.0",
"date-fns": "^2.30.0",
"lodash": "^4.17.21",
"react-use": "^17.2.4",
- "recharts": "^2.7.0"
+ "recharts": "^2.5.0"
},
"peerDependencies": {
"react": "^16.13.1 || ^17.0.0",
@@ -48,7 +49,6 @@
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^12.1.3",
"@testing-library/user-event": "^14.0.0",
- "@types/node": "*",
"cross-fetch": "^3.1.5",
"msw": "^1.0.0"
},
diff --git a/plugins/opencost/src/components/AllocationChart/RangeChart.js b/plugins/opencost/src/components/AllocationChart/RangeChart.js
index d95981f42a..b1ce5a34ee 100644
--- a/plugins/opencost/src/components/AllocationChart/RangeChart.js
+++ b/plugins/opencost/src/components/AllocationChart/RangeChart.js
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import React from 'react';
import {
BarChart,
diff --git a/plugins/opencost/src/components/AllocationChart/SummaryChart.js b/plugins/opencost/src/components/AllocationChart/SummaryChart.js
index 9ac59cdbca..53c0842845 100644
--- a/plugins/opencost/src/components/AllocationChart/SummaryChart.js
+++ b/plugins/opencost/src/components/AllocationChart/SummaryChart.js
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import React from 'react';
import { ResponsiveContainer, PieChart, Pie, Cell } from 'recharts';
import { primary, greyscale, browns } from '../../constants/colors';
diff --git a/plugins/opencost/src/components/AllocationChart/index.js b/plugins/opencost/src/components/AllocationChart/index.js
index c08c5513a8..9fec3e296f 100644
--- a/plugins/opencost/src/components/AllocationChart/index.js
+++ b/plugins/opencost/src/components/AllocationChart/index.js
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import React from 'react';
import { isArray, filter, map, reduce, reverse, sortBy } from 'lodash';
diff --git a/plugins/opencost/src/components/Controls/Download.js b/plugins/opencost/src/components/Controls/Download.js
index 527940924a..727188e5c1 100644
--- a/plugins/opencost/src/components/Controls/Download.js
+++ b/plugins/opencost/src/components/Controls/Download.js
@@ -13,84 +13,89 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-import React from 'react'
-import { get, forEach, reverse, round, sortBy } from 'lodash'
-import ExportIcon from '@material-ui/icons/GetApp'
-import IconButton from '@material-ui/core/IconButton'
-import Tooltip from '@material-ui/core/Tooltip'
+import React from 'react';
+import { get, forEach, reverse, round, sortBy } from 'lodash';
+import ExportIcon from '@material-ui/icons/GetApp';
+import IconButton from '@material-ui/core/IconButton';
+import Tooltip from '@material-ui/core/Tooltip';
const columns = [
{
- head: "Name",
- prop: "name",
+ head: 'Name',
+ prop: 'name',
currency: false,
- }, {
- head: "CPU",
- prop: "cpuCost",
+ },
+ {
+ head: 'CPU',
+ prop: 'cpuCost',
currency: true,
- }, {
- head: "GPU",
- prop: "gpuCost",
+ },
+ {
+ head: 'GPU',
+ prop: 'gpuCost',
currency: true,
- }, {
- head: "RAM",
- prop: "ramCost",
+ },
+ {
+ head: 'RAM',
+ prop: 'ramCost',
currency: true,
- }, {
- head: "PV",
- prop: "pvCost",
+ },
+ {
+ head: 'PV',
+ prop: 'pvCost',
currency: true,
- }, {
- head: "Network",
- prop: "networkCost",
+ },
+ {
+ head: 'Network',
+ prop: 'networkCost',
currency: true,
- }, {
- head: "Shared",
- prop: "sharedCost",
+ },
+ {
+ head: 'Shared',
+ prop: 'sharedCost',
currency: true,
- }, {
- head: "Total",
- prop: "totalCost",
+ },
+ {
+ head: 'Total',
+ prop: 'totalCost',
currency: true,
- }
-]
+ },
+];
-const toCSVLine = (datum) => {
- const cols = []
+const toCSVLine = datum => {
+ const cols = [];
forEach(columns, c => {
if (c.currency) {
- cols.push(round(get(datum, c.prop, 0.0), 2))
+ cols.push(round(get(datum, c.prop, 0.0), 2));
} else {
- cols.push(`"${get(datum, c.prop, "")}"`)
+ cols.push(`"${get(datum, c.prop, '')}"`);
}
- })
+ });
- return cols.join(',')
-}
+ return cols.join(',');
+};
-const DownloadControl = ({
- cumulativeData,
- title,
-}) => {
+const DownloadControl = ({ cumulativeData, title }) => {
// downloadReport downloads a CSV of the cumulative allocation data
function downloadReport() {
// Build CSV
- const head = columns.map(c => c.head).join(',')
- const body = reverse(sortBy(cumulativeData, 'totalCost')).map(toCSVLine).join('\r\n')
- const csv = `${head}\r\n${body}`
+ const head = columns.map(c => c.head).join(',');
+ const body = reverse(sortBy(cumulativeData, 'totalCost'))
+ .map(toCSVLine)
+ .join('\r\n');
+ const csv = `${head}\r\n${body}`;
// Create download link
- const a = document.createElement("a")
- a.href = URL.createObjectURL(new Blob([csv], { type: "text/csv" }))
- const filename = title.toLocaleLowerCase('en-US').replace(/\s/gi, '-')
- a.setAttribute("download", `${filename}-${Date.now()}.csv`)
+ const a = document.createElement('a');
+ a.href = URL.createObjectURL(new Blob([csv], { type: 'text/csv' }));
+ const filename = title.toLocaleLowerCase('en-US').replace(/\s/gi, '-');
+ a.setAttribute('download', `${filename}-${Date.now()}.csv`);
// Click the link
- document.body.appendChild(a)
- a.click()
- document.body.removeChild(a)
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
}
return (
@@ -99,7 +104,7 @@ const DownloadControl = ({
- )
-}
+ );
+};
-export default React.memo(DownloadControl)
+export default React.memo(DownloadControl);
diff --git a/plugins/opencost/src/components/Controls/Edit.js b/plugins/opencost/src/components/Controls/Edit.js
index a1b3fe1fc7..f02f8cc111 100644
--- a/plugins/opencost/src/components/Controls/Edit.js
+++ b/plugins/opencost/src/components/Controls/Edit.js
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import { makeStyles } from '@material-ui/styles';
import FormControl from '@material-ui/core/FormControl';
import InputLabel from '@material-ui/core/InputLabel';
diff --git a/plugins/opencost/src/components/Controls/index.js b/plugins/opencost/src/components/Controls/index.js
index f5ea994e33..c63833a6ab 100644
--- a/plugins/opencost/src/components/Controls/index.js
+++ b/plugins/opencost/src/components/Controls/index.js
@@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-import React from 'react'
-import DownloadControl from './Download'
-import EditControl from './Edit'
+import React from 'react';
+import DownloadControl from './Download';
+import EditControl from './Edit';
const Controls = ({
windowOptions,
@@ -34,7 +33,6 @@ const Controls = ({
currencyOptions,
setCurrency,
}) => {
-
return (
-
+
- )
-}
+ );
+};
-export default React.memo(Controls)
+export default React.memo(Controls);
diff --git a/plugins/opencost/src/components/OpenCostPage/OpenCostPage.test.tsx b/plugins/opencost/src/components/OpenCostPage/OpenCostPage.test.tsx
index de6565246c..ea10906f85 100644
--- a/plugins/opencost/src/components/OpenCostPage/OpenCostPage.test.tsx
+++ b/plugins/opencost/src/components/OpenCostPage/OpenCostPage.test.tsx
@@ -37,6 +37,8 @@ describe('OpenCostPage', () => {
it('should render', async () => {
await renderInTestApp();
- expect(screen.getByText('Open source Kubernetes cloud cost monitoring')).toBeInTheDocument();
+ expect(
+ screen.getByText('Open source Kubernetes cloud cost monitoring'),
+ ).toBeInTheDocument();
});
});
diff --git a/plugins/opencost/src/components/OpenCostPage/OpenCostPage.tsx b/plugins/opencost/src/components/OpenCostPage/OpenCostPage.tsx
index 88ef390c49..19a383e7b6 100644
--- a/plugins/opencost/src/components/OpenCostPage/OpenCostPage.tsx
+++ b/plugins/opencost/src/components/OpenCostPage/OpenCostPage.tsx
@@ -38,10 +38,10 @@ export const OpenCostPage = () => (
/>
-
+
-
+
diff --git a/plugins/opencost/src/components/OpenCostReport/OpenCostReport.tsx b/plugins/opencost/src/components/OpenCostReport/OpenCostReport.tsx
index 1fb57d78db..8a4cad49c8 100644
--- a/plugins/opencost/src/components/OpenCostReport/OpenCostReport.tsx
+++ b/plugins/opencost/src/components/OpenCostReport/OpenCostReport.tsx
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
// code ported from https://github.com/opencost/opencost/blob/develop/ui/src/Reports.js
import React, { useEffect, useState } from 'react';
diff --git a/plugins/opencost/src/components/Page.js b/plugins/opencost/src/components/Page.js
index 9d5af515d0..6346b6287b 100644
--- a/plugins/opencost/src/components/Page.js
+++ b/plugins/opencost/src/components/Page.js
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-import { makeStyles } from '@material-ui/styles'
-import React from 'react'
+import { makeStyles } from '@material-ui/styles';
+import React from 'react';
const useStyles = makeStyles({
wrapper: {
@@ -29,21 +29,19 @@ const useStyles = makeStyles({
display: 'flex',
flexFlow: 'column',
flexGrow: 1,
- }
-})
+ },
+});
const Page = props => {
- const classes = useStyles()
+ const classes = useStyles();
return (
-
- {props.children}
-
+
{props.children}
- )
-}
+ );
+};
-export default Page
+export default Page;
diff --git a/plugins/opencost/src/components/SelectWindow.js b/plugins/opencost/src/components/SelectWindow.js
index a8eb00f03c..87ecfe093e 100644
--- a/plugins/opencost/src/components/SelectWindow.js
+++ b/plugins/opencost/src/components/SelectWindow.js
@@ -14,19 +14,22 @@
* limitations under the License.
*/
-import React, { useEffect, useState } from 'react'
-import { makeStyles } from '@material-ui/styles'
-import { endOfDay, startOfDay } from 'date-fns'
-import { MuiPickersUtilsProvider, KeyboardDatePicker } from '@material-ui/pickers'
-import Button from '@material-ui/core/Button'
-import DateFnsUtils from '@date-io/date-fns'
-import FormControl from '@material-ui/core/FormControl'
-import Link from '@material-ui/core/Link'
-import Popover from '@material-ui/core/Popover'
-import TextField from '@material-ui/core/TextField'
-import Typography from '@material-ui/core/Typography'
-import { isValid } from 'date-fns'
-import { find, get } from 'lodash'
+import React, { useEffect, useState } from 'react';
+import { makeStyles } from '@material-ui/styles';
+import { endOfDay, startOfDay } from 'date-fns';
+import {
+ MuiPickersUtilsProvider,
+ KeyboardDatePicker,
+} from '@material-ui/pickers';
+import Button from '@material-ui/core/Button';
+import DateFnsUtils from '@date-io/date-fns';
+import FormControl from '@material-ui/core/FormControl';
+import Link from '@material-ui/core/Link';
+import Popover from '@material-ui/core/Popover';
+import TextField from '@material-ui/core/TextField';
+import Typography from '@material-ui/core/Typography';
+import { isValid } from 'date-fns';
+import { find, get } from 'lodash';
const useStyles = makeStyles({
dateContainer: {
@@ -45,96 +48,99 @@ const useStyles = makeStyles({
margin: 8,
width: 120,
},
-})
+});
const SelectWindow = ({ windowOptions, window, setWindow }) => {
- const classes = useStyles()
- const [anchorEl, setAnchorEl] = useState(null)
+ const classes = useStyles();
+ const [anchorEl, setAnchorEl] = useState(null);
- const [startDate, setStartDate] = useState(null)
- const [endDate, setEndDate] = useState(null)
- const [intervalString, setIntervalString] = useState(null)
+ const [startDate, setStartDate] = useState(null);
+ const [endDate, setEndDate] = useState(null);
+ const [intervalString, setIntervalString] = useState(null);
- const handleClick = (event) => {
- setAnchorEl(event.currentTarget)
+ const handleClick = event => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ const handleStartDateChange = date => {
+ if (isValid(date)) {
+ setStartDate(startOfDay(date));
}
+ };
- const handleClose = () => {
- setAnchorEl(null)
+ const handleEndDateChange = date => {
+ if (isValid(date)) {
+ setEndDate(endOfDay(date));
}
+ };
- const handleStartDateChange = (date) => {
- if (isValid(date)) {
- setStartDate(startOfDay(date))
- }
+ const handleSubmitPresetDates = dateString => {
+ setWindow(dateString);
+ setStartDate(null);
+ setEndDate(null);
+ handleClose();
+ };
+
+ const handleSubmitCustomDates = () => {
+ if (intervalString !== null) {
+ setWindow(intervalString);
+ handleClose();
}
+ };
- const handleEndDateChange = (date) => {
- if (isValid(date)) {
- setEndDate(endOfDay(date))
- }
+ useEffect(() => {
+ if (startDate !== null && endDate !== null) {
+ // Note: getTimezoneOffset() is calculated based on current system locale, NOT date object
+ const adjustedStartDate = new Date(
+ startDate - startDate.getTimezoneOffset() * 60000,
+ );
+ const adjustedEndDate = new Date(
+ endDate - endDate.getTimezoneOffset() * 60000,
+ );
+ setIntervalString(
+ `${adjustedStartDate.toISOString().split('.')[0]}Z` +
+ `,${adjustedEndDate.toISOString().split('.')[0]}Z`,
+ );
}
+ }, [startDate, endDate]);
- const handleSubmitPresetDates = (dateString) => {
- setWindow(dateString)
- setStartDate(null)
- setEndDate(null)
- handleClose()
- }
+ const open = Boolean(anchorEl);
+ const id = open ? 'date-range-popover' : undefined;
- const handleSubmitCustomDates = () => {
- if (intervalString !== null) {
- setWindow(intervalString)
- handleClose()
- }
- }
-
- useEffect(() => {
- if (startDate !== null && endDate !== null) {
- // Note: getTimezoneOffset() is calculated based on current system locale, NOT date object
- const adjustedStartDate = new Date(startDate - startDate.getTimezoneOffset() * 60000)
- const adjustedEndDate = new Date(endDate - endDate.getTimezoneOffset() * 60000)
- setIntervalString(
- `${adjustedStartDate.toISOString().split('.')[0] }Z`
- + `,${
- adjustedEndDate.toISOString().split('.')[0] }Z`
- )
- }
- }, [startDate, endDate])
-
- const open = Boolean(anchorEl)
- const id = open ? 'date-range-popover' : undefined
-
- return (
- <>
-
-
+
+ handleClick(e)}
inputProps={{
readOnly: true,
style: { cursor: 'pointer' },
}}
- />
-
-
-
-
+ />
+
+
+
+
{
}}
/>
-
-
-
-
-
- {windowOptions.map(opt =>
- (
+
+
+
+
+ {windowOptions.map(opt => (
+
handleSubmitPresetDates(opt.value)}
>
{opt.name}
- )
- )}
-
+
+ ))}
-
- >
- )
- }
+
+
+ >
+ );
+};
- export default React.memo(SelectWindow)
+export default React.memo(SelectWindow);
diff --git a/plugins/opencost/src/components/Subtitle.js b/plugins/opencost/src/components/Subtitle.js
index 1c7affb8b7..63b3df61ff 100644
--- a/plugins/opencost/src/components/Subtitle.js
+++ b/plugins/opencost/src/components/Subtitle.js
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-import React from 'react'
-import { makeStyles } from '@material-ui/styles'
-import { upperFirst } from 'lodash'
-import Breadcrumbs from '@material-ui/core/Breadcrumbs'
-import NavigateNextIcon from '@material-ui/icons/NavigateNext'
-import Typography from '@material-ui/core/Typography'
+import React from 'react';
+import { makeStyles } from '@material-ui/styles';
+import { upperFirst } from 'lodash';
+import Breadcrumbs from '@material-ui/core/Breadcrumbs';
+import NavigateNextIcon from '@material-ui/icons/NavigateNext';
+import Typography from '@material-ui/core/Typography';
import { toVerboseTimeRange } from '../util';
const useStyles = makeStyles({
@@ -29,14 +29,14 @@ const useStyles = makeStyles({
},
},
link: {
- cursor: "pointer",
+ cursor: 'pointer',
},
-})
+});
const Subtitle = ({ report }) => {
- const classes = useStyles()
+ const classes = useStyles();
- const { aggregateBy, window } = report
+ const { aggregateBy, window } = report;
return (
@@ -45,13 +45,15 @@ const Subtitle = ({ report }) => {
aria-label="breadcrumb"
>
{aggregateBy && aggregateBy.length > 0 ? (
- {toVerboseTimeRange(window)} by {upperFirst(aggregateBy)}
+
+ {toVerboseTimeRange(window)} by {upperFirst(aggregateBy)}
+
) : (
{toVerboseTimeRange(window)}
)}
- )
-}
+ );
+};
-export default React.memo(Subtitle)
+export default React.memo(Subtitle);
diff --git a/plugins/opencost/src/components/Warnings.js b/plugins/opencost/src/components/Warnings.js
index 5cb3ccfdd6..ae1047ebc2 100644
--- a/plugins/opencost/src/components/Warnings.js
+++ b/plugins/opencost/src/components/Warnings.js
@@ -14,24 +14,24 @@
* limitations under the License.
*/
-import React from 'react'
-import { makeStyles } from '@material-ui/styles'
-import List from '@material-ui/core/List'
-import ListItem from '@material-ui/core/ListItem'
-import ListItemIcon from '@material-ui/core/ListItemIcon'
-import ListItemText from '@material-ui/core/ListItemText'
-import Paper from '@material-ui/core/Paper'
-import WarningIcon from '@material-ui/icons/Warning'
+import React from 'react';
+import { makeStyles } from '@material-ui/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import Paper from '@material-ui/core/Paper';
+import WarningIcon from '@material-ui/icons/Warning';
const useStyles = makeStyles({
root: {},
-})
+});
-const Warnings = ({warnings}) => {
- const classes = useStyles()
+const Warnings = ({ warnings }) => {
+ const classes = useStyles();
if (!warnings || warnings.length === 0) {
- return null
+ return null;
}
return (
@@ -47,7 +47,7 @@ const Warnings = ({warnings}) => {
))}
- )
-}
+ );
+};
-export default Warnings
+export default Warnings;
diff --git a/plugins/opencost/src/constants/colors.js b/plugins/opencost/src/constants/colors.js
index 4c66549ad0..8e0289541b 100644
--- a/plugins/opencost/src/constants/colors.js
+++ b/plugins/opencost/src/constants/colors.js
@@ -1,15 +1,31 @@
-import blue from '@material-ui/core/colors/blue'
-import brown from '@material-ui/core/colors/brown'
-import cyan from '@material-ui/core/colors/cyan'
-import deepOrange from '@material-ui/core/colors/deepOrange'
-import deepPurple from '@material-ui/core/colors/deepPurple'
-import green from '@material-ui/core/colors/green'
-import grey from '@material-ui/core/colors/grey'
-import indigo from '@material-ui/core/colors/indigo'
-import orange from '@material-ui/core/colors/orange'
-import red from '@material-ui/core/colors/red'
-import teal from '@material-ui/core/colors/teal'
-import yellow from '@material-ui/core/colors/yellow'
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import blue from '@material-ui/core/colors/blue';
+import brown from '@material-ui/core/colors/brown';
+import cyan from '@material-ui/core/colors/cyan';
+import deepOrange from '@material-ui/core/colors/deepOrange';
+import deepPurple from '@material-ui/core/colors/deepPurple';
+import green from '@material-ui/core/colors/green';
+import grey from '@material-ui/core/colors/grey';
+import indigo from '@material-ui/core/colors/indigo';
+import orange from '@material-ui/core/colors/orange';
+import red from '@material-ui/core/colors/red';
+import teal from '@material-ui/core/colors/teal';
+import yellow from '@material-ui/core/colors/yellow';
export const primary = [
blue[500],
@@ -22,7 +38,7 @@ export const primary = [
indigo[500],
deepOrange[500],
deepPurple[500],
-]
+];
export const greyscale = [
grey[300],
@@ -31,8 +47,6 @@ export const greyscale = [
grey[500],
grey[100],
grey[600],
-]
+];
-export const browns = [
- brown[500],
-]
+export const browns = [brown[500]];
diff --git a/plugins/opencost/src/constants/currencyCodes.js b/plugins/opencost/src/constants/currencyCodes.js
index 219384c24b..a325df54d0 100644
--- a/plugins/opencost/src/constants/currencyCodes.js
+++ b/plugins/opencost/src/constants/currencyCodes.js
@@ -1 +1,196 @@
-export const currencyCodes = ["AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BOV", "BRL", "BSD", "BTN", "BWP", "BYR", "BZD", "CAD", "CDF", "CHE", "CHF", "CHW", "CLF", "CLP", "CNY", "COP", "COU", "CRC", "CUC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "INR", "IQD", "IRR", "ISK", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LTL", "LVL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRO", "MUR", "MVR", "MWK", "MXN", "MXV", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLL", "SOS", "SRD", "SSP", "STD", "SYP", "SZL", "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "USN", "USS", "UYI", "UYU", "UZS", "VEF", "VND", "VUV", "WST", "XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XFU", "XOF", "XPD", "XPF", "XPT", "XTS", "XXX", "YER", "ZAR", "ZMW"];
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const currencyCodes = [
+ 'AED',
+ 'AFN',
+ 'ALL',
+ 'AMD',
+ 'ANG',
+ 'AOA',
+ 'ARS',
+ 'AUD',
+ 'AWG',
+ 'AZN',
+ 'BAM',
+ 'BBD',
+ 'BDT',
+ 'BGN',
+ 'BHD',
+ 'BIF',
+ 'BMD',
+ 'BND',
+ 'BOB',
+ 'BOV',
+ 'BRL',
+ 'BSD',
+ 'BTN',
+ 'BWP',
+ 'BYR',
+ 'BZD',
+ 'CAD',
+ 'CDF',
+ 'CHE',
+ 'CHF',
+ 'CHW',
+ 'CLF',
+ 'CLP',
+ 'CNY',
+ 'COP',
+ 'COU',
+ 'CRC',
+ 'CUC',
+ 'CUP',
+ 'CVE',
+ 'CZK',
+ 'DJF',
+ 'DKK',
+ 'DOP',
+ 'DZD',
+ 'EGP',
+ 'ERN',
+ 'ETB',
+ 'EUR',
+ 'FJD',
+ 'FKP',
+ 'GBP',
+ 'GEL',
+ 'GHS',
+ 'GIP',
+ 'GMD',
+ 'GNF',
+ 'GTQ',
+ 'GYD',
+ 'HKD',
+ 'HNL',
+ 'HRK',
+ 'HTG',
+ 'HUF',
+ 'IDR',
+ 'ILS',
+ 'INR',
+ 'IQD',
+ 'IRR',
+ 'ISK',
+ 'JMD',
+ 'JOD',
+ 'JPY',
+ 'KES',
+ 'KGS',
+ 'KHR',
+ 'KMF',
+ 'KPW',
+ 'KRW',
+ 'KWD',
+ 'KYD',
+ 'KZT',
+ 'LAK',
+ 'LBP',
+ 'LKR',
+ 'LRD',
+ 'LSL',
+ 'LTL',
+ 'LVL',
+ 'LYD',
+ 'MAD',
+ 'MDL',
+ 'MGA',
+ 'MKD',
+ 'MMK',
+ 'MNT',
+ 'MOP',
+ 'MRO',
+ 'MUR',
+ 'MVR',
+ 'MWK',
+ 'MXN',
+ 'MXV',
+ 'MYR',
+ 'MZN',
+ 'NAD',
+ 'NGN',
+ 'NIO',
+ 'NOK',
+ 'NPR',
+ 'NZD',
+ 'OMR',
+ 'PAB',
+ 'PEN',
+ 'PGK',
+ 'PHP',
+ 'PKR',
+ 'PLN',
+ 'PYG',
+ 'QAR',
+ 'RON',
+ 'RSD',
+ 'RUB',
+ 'RWF',
+ 'SAR',
+ 'SBD',
+ 'SCR',
+ 'SDG',
+ 'SEK',
+ 'SGD',
+ 'SHP',
+ 'SLL',
+ 'SOS',
+ 'SRD',
+ 'SSP',
+ 'STD',
+ 'SYP',
+ 'SZL',
+ 'THB',
+ 'TJS',
+ 'TMT',
+ 'TND',
+ 'TOP',
+ 'TRY',
+ 'TTD',
+ 'TWD',
+ 'TZS',
+ 'UAH',
+ 'UGX',
+ 'USD',
+ 'USN',
+ 'USS',
+ 'UYI',
+ 'UYU',
+ 'UZS',
+ 'VEF',
+ 'VND',
+ 'VUV',
+ 'WST',
+ 'XAF',
+ 'XAG',
+ 'XAU',
+ 'XBA',
+ 'XBB',
+ 'XBC',
+ 'XBD',
+ 'XCD',
+ 'XDR',
+ 'XFU',
+ 'XOF',
+ 'XPD',
+ 'XPF',
+ 'XPT',
+ 'XTS',
+ 'XXX',
+ 'YER',
+ 'ZAR',
+ 'ZMW',
+];
diff --git a/plugins/opencost/src/index.ts b/plugins/opencost/src/index.ts
index 0391378aef..32ec0d0091 100644
--- a/plugins/opencost/src/index.ts
+++ b/plugins/opencost/src/index.ts
@@ -13,4 +13,5 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
export { openCostPlugin, OpenCostPage } from './plugin';
diff --git a/plugins/opencost/src/plugin.test.ts b/plugins/opencost/src/plugin.test.ts
index a505cbe130..6d6d20c603 100644
--- a/plugins/opencost/src/plugin.test.ts
+++ b/plugins/opencost/src/plugin.test.ts
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
import { openCostPlugin } from './plugin';
describe('opencost', () => {
diff --git a/plugins/opencost/src/plugin.ts b/plugins/opencost/src/plugin.ts
index edaa04d595..9eaf8f63f5 100644
--- a/plugins/opencost/src/plugin.ts
+++ b/plugins/opencost/src/plugin.ts
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
import {
createPlugin,
createRoutableExtension,
diff --git a/plugins/opencost/src/routes.ts b/plugins/opencost/src/routes.ts
index b7ace600e2..5f1f9e4527 100644
--- a/plugins/opencost/src/routes.ts
+++ b/plugins/opencost/src/routes.ts
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
import { createRouteRef } from '@backstage/core-plugin-api';
export const rootRouteRef = createRouteRef({
diff --git a/plugins/opencost/src/services/allocation.js b/plugins/opencost/src/services/allocation.js
index 8b94c4945e..e7fba8feae 100644
--- a/plugins/opencost/src/services/allocation.js
+++ b/plugins/opencost/src/services/allocation.js
@@ -1,8 +1,23 @@
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
import axios from 'axios';
class AllocationService {
async fetchAllocation(baseUrl, win, aggregate, options) {
- const { accumulate, } = options;
+ const { accumulate } = options;
const params = {
window: win,
aggregate: aggregate,
@@ -12,10 +27,8 @@ class AllocationService {
params.accumulate = accumulate;
}
- console.log(`${baseUrl}/allocation/compute`, { params });
const result = await axios.get(`${baseUrl}/allocation/compute`, { params });
- console.log(result.data);
return result.data;
}
}
diff --git a/plugins/opencost/src/setupTests.ts b/plugins/opencost/src/setupTests.ts
deleted file mode 100644
index 73dd8dce47..0000000000
--- a/plugins/opencost/src/setupTests.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright 2023 The Backstage Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import '@testing-library/jest-dom';
-import 'cross-fetch/polyfill';
diff --git a/plugins/opencost/src/util.js b/plugins/opencost/src/util.js
index 8e4bfcb54d..d2c8fa7562 100644
--- a/plugins/opencost/src/util.js
+++ b/plugins/opencost/src/util.js
@@ -1,18 +1,34 @@
-import { forEach, get, round } from 'lodash'
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { forEach, get, round } from 'lodash';
// rangeToCumulative takes an AllocationSetRange (type: array[AllocationSet])
// and accumulates the values into a single AllocationSet (type: object)
export function rangeToCumulative(allocationSetRange, aggregateBy) {
if (allocationSetRange.length === 0) {
- return null
+ return null;
}
- const result = {}
+ const result = {};
- forEach(allocationSetRange, (allocSet) => {
- forEach(allocSet, (alloc) => {
+ forEach(allocationSetRange, allocSet => {
+ forEach(allocSet, alloc => {
if (result[alloc.name] === undefined) {
- const hrs = get(alloc, 'minutes', 0) / 60.0
+ const hrs = get(alloc, 'minutes', 0) / 60.0;
result[alloc.name] = {
name: alloc.name,
@@ -32,70 +48,76 @@ export function rangeToCumulative(allocationSetRange, aggregateBy) {
cpuEfficiency: get(alloc, 'cpuEfficiency', 0),
ramEfficiency: get(alloc, 'ramEfficiency', 0),
totalEfficiency: get(alloc, 'totalEfficiency', 0),
- }
+ };
} else {
- const hrs = get(alloc, 'minutes', 0) / 60.0
+ const hrs = get(alloc, 'minutes', 0) / 60.0;
- result[alloc.name].cpuCost += get(alloc, 'cpuCost', 0)
- result[alloc.name].gpuCost += get(alloc, 'gpuCost', 0)
- result[alloc.name].ramCost += get(alloc, 'ramCost', 0)
- result[alloc.name].pvCost += get(alloc, 'pvCost', 0)
- result[alloc.name].networkCost += get(alloc, 'networkCost', 0)
- result[alloc.name].sharedCost += get(alloc, 'sharedCost', 0)
- result[alloc.name].externalCost += get(alloc, 'externalCost', 0)
- result[alloc.name].totalCost += get(alloc, 'totalCost', 0)
- result[alloc.name].cpuUseCoreHrs += get(alloc, 'cpuCoreUsageAverage', 0) * hrs
- result[alloc.name].cpuReqCoreHrs += get(alloc, 'cpuCoreRequestAverage', 0) * hrs
- result[alloc.name].ramUseByteHrs += get(alloc, 'ramByteUsageAverage', 0) * hrs
- result[alloc.name].ramReqByteHrs += get(alloc, 'ramByteRequestAverage', 0) * hrs
+ result[alloc.name].cpuCost += get(alloc, 'cpuCost', 0);
+ result[alloc.name].gpuCost += get(alloc, 'gpuCost', 0);
+ result[alloc.name].ramCost += get(alloc, 'ramCost', 0);
+ result[alloc.name].pvCost += get(alloc, 'pvCost', 0);
+ result[alloc.name].networkCost += get(alloc, 'networkCost', 0);
+ result[alloc.name].sharedCost += get(alloc, 'sharedCost', 0);
+ result[alloc.name].externalCost += get(alloc, 'externalCost', 0);
+ result[alloc.name].totalCost += get(alloc, 'totalCost', 0);
+ result[alloc.name].cpuUseCoreHrs +=
+ get(alloc, 'cpuCoreUsageAverage', 0) * hrs;
+ result[alloc.name].cpuReqCoreHrs +=
+ get(alloc, 'cpuCoreRequestAverage', 0) * hrs;
+ result[alloc.name].ramUseByteHrs +=
+ get(alloc, 'ramByteUsageAverage', 0) * hrs;
+ result[alloc.name].ramReqByteHrs +=
+ get(alloc, 'ramByteRequestAverage', 0) * hrs;
}
- })
- })
+ });
+ });
// If the range is of length > 1 (i.e. it is not just a single set) then
// compute efficiency for each result after accumulating.
if (allocationSetRange.length > 1) {
forEach(result, (alloc, name) => {
// If we can't compute total efficiency, it defaults to 0.0
- let totalEfficiency = 0.0
+ let totalEfficiency = 0.0;
// CPU efficiency is defined as (usage/request). If request == 0.0 but
// usage > 0, then efficiency gets set to 1.0.
- let cpuEfficiency = 0.0
+ let cpuEfficiency = 0.0;
if (alloc.cpuReqCoreHrs > 0) {
- cpuEfficiency = alloc.cpuUseCoreHrs / alloc.cpuReqCoreHrs
+ cpuEfficiency = alloc.cpuUseCoreHrs / alloc.cpuReqCoreHrs;
} else if (alloc.cpuUseCoreHrs > 0) {
- cpuEfficiency = 1.0
+ cpuEfficiency = 1.0;
}
// RAM efficiency is defined as (usage/request). If request == 0.0 but
// usage > 0, then efficiency gets set to 1.0.
- let ramEfficiency = 0.0
+ let ramEfficiency = 0.0;
if (alloc.ramReqByteHrs > 0) {
- ramEfficiency = alloc.ramUseByteHrs / alloc.ramReqByteHrs
+ ramEfficiency = alloc.ramUseByteHrs / alloc.ramReqByteHrs;
} else if (alloc.ramUseByteHrs > 0) {
- ramEfficiency = 1.0
+ ramEfficiency = 1.0;
}
// Compute efficiency as the cost-weighted average of CPU and RAM
// efficiency
- if ((alloc.cpuCost + alloc.ramCost) > 0.0) {
- totalEfficiency = ((alloc.cpuCost*cpuEfficiency)+(alloc.ramCost*ramEfficiency)) / (alloc.cpuCost + alloc.ramCost)
+ if (alloc.cpuCost + alloc.ramCost > 0.0) {
+ totalEfficiency =
+ (alloc.cpuCost * cpuEfficiency + alloc.ramCost * ramEfficiency) /
+ (alloc.cpuCost + alloc.ramCost);
}
- result[name].cpuEfficiency = cpuEfficiency
- result[name].ramEfficiency = ramEfficiency
- result[name].totalEfficiency = totalEfficiency
- })
+ result[name].cpuEfficiency = cpuEfficiency;
+ result[name].ramEfficiency = ramEfficiency;
+ result[name].totalEfficiency = totalEfficiency;
+ });
}
- return result
+ return result;
}
// cumulativeToTotals adds each entry in the given AllocationSet (type: object)
// and returns a single Allocation (type: object) representing the totals
export function cumulativeToTotals(allocationSet) {
- let totals = {
+ const totals = {
name: 'Totals',
cpuCost: 0,
gpuCost: 0,
@@ -108,177 +130,225 @@ export function cumulativeToTotals(allocationSet) {
cpuEfficiency: 0,
ramEfficiency: 0,
totalEfficiency: 0,
- }
+ };
// Use these for computing efficiency. As such, idle will not factor into
// these numbers, including CPU and RAM cost.
- let cpuReqCoreHrs = 0
- let cpuUseCoreHrs = 0
- let ramReqByteHrs = 0
- let ramUseByteHrs = 0
- let cpuCost = 0
- let ramCost = 0
+ let cpuReqCoreHrs = 0;
+ let cpuUseCoreHrs = 0;
+ let ramReqByteHrs = 0;
+ let ramUseByteHrs = 0;
+ let cpuCost = 0;
+ let ramCost = 0;
forEach(allocationSet, (alloc, name) => {
// Accumulate efficiency-related fields
- if (name !== "__idle__") {
- cpuReqCoreHrs += get(alloc, 'cpuReqCoreHrs', 0.0)
- cpuUseCoreHrs += get(alloc, 'cpuUseCoreHrs', 0.0)
- ramReqByteHrs += get(alloc, 'ramReqByteHrs', 0.0)
- ramUseByteHrs += get(alloc, 'ramUseByteHrs', 0.0)
- cpuCost += get(alloc, 'cpuCost', 0.0)
- ramCost += get(alloc, 'ramCost', 0.0)
+ if (name !== '__idle__') {
+ cpuReqCoreHrs += get(alloc, 'cpuReqCoreHrs', 0.0);
+ cpuUseCoreHrs += get(alloc, 'cpuUseCoreHrs', 0.0);
+ ramReqByteHrs += get(alloc, 'ramReqByteHrs', 0.0);
+ ramUseByteHrs += get(alloc, 'ramUseByteHrs', 0.0);
+ cpuCost += get(alloc, 'cpuCost', 0.0);
+ ramCost += get(alloc, 'ramCost', 0.0);
}
// Sum cumulative fields
- totals.cpuCost += get(alloc, 'cpuCost', 0)
- totals.gpuCost += get(alloc, 'gpuCost', 0)
- totals.ramCost += get(alloc, 'ramCost', 0)
- totals.pvCost += get(alloc, 'pvCost', 0)
- totals.networkCost += get(alloc, 'networkCost', 0)
- totals.sharedCost += get(alloc, 'sharedCost', 0)
- totals.externalCost += get(alloc, 'externalCost', 0)
- totals.totalCost += get(alloc, 'totalCost', 0)
- })
+ totals.cpuCost += get(alloc, 'cpuCost', 0);
+ totals.gpuCost += get(alloc, 'gpuCost', 0);
+ totals.ramCost += get(alloc, 'ramCost', 0);
+ totals.pvCost += get(alloc, 'pvCost', 0);
+ totals.networkCost += get(alloc, 'networkCost', 0);
+ totals.sharedCost += get(alloc, 'sharedCost', 0);
+ totals.externalCost += get(alloc, 'externalCost', 0);
+ totals.totalCost += get(alloc, 'totalCost', 0);
+ });
// Compute efficiency
if (cpuReqCoreHrs > 0) {
- totals.cpuEfficiency = cpuUseCoreHrs / cpuReqCoreHrs
+ totals.cpuEfficiency = cpuUseCoreHrs / cpuReqCoreHrs;
} else if (cpuUseCoreHrs > 0) {
- totals.cpuEfficiency = 1.0
+ totals.cpuEfficiency = 1.0;
}
if (ramReqByteHrs > 0) {
- totals.ramEfficiency = ramUseByteHrs / ramReqByteHrs
+ totals.ramEfficiency = ramUseByteHrs / ramReqByteHrs;
} else if (ramUseByteHrs > 0) {
- totals.ramEfficiency = 1.0
+ totals.ramEfficiency = 1.0;
}
- if ((cpuCost + ramCost) > 0) {
- totals.totalEfficiency = ((cpuCost*totals.cpuEfficiency) + (ramCost*totals.ramEfficiency)) / (cpuCost + ramCost)
+ if (cpuCost + ramCost > 0) {
+ totals.totalEfficiency =
+ (cpuCost * totals.cpuEfficiency + ramCost * totals.ramEfficiency) /
+ (cpuCost + ramCost);
}
- totals.cpuReqCoreHrs = cpuReqCoreHrs
- totals.cpuUseCoreHrs = cpuUseCoreHrs
- totals.ramReqByteHrs = ramReqByteHrs
- totals.ramUseByteHrs = ramUseByteHrs
+ totals.cpuReqCoreHrs = cpuReqCoreHrs;
+ totals.cpuUseCoreHrs = cpuUseCoreHrs;
+ totals.ramReqByteHrs = ramReqByteHrs;
+ totals.ramUseByteHrs = ramUseByteHrs;
- return totals
+ return totals;
}
export function toVerboseTimeRange(window) {
- const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
+ const months = [
+ 'January',
+ 'February',
+ 'March',
+ 'April',
+ 'May',
+ 'June',
+ 'July',
+ 'August',
+ 'September',
+ 'October',
+ 'November',
+ 'December',
+ ];
- const start = new Date()
- start.setUTCHours(0, 0, 0, 0)
+ const start = new Date();
+ start.setUTCHours(0, 0, 0, 0);
- const end = new Date()
- end.setUTCHours(0, 0, 0, 0)
+ const end = new Date();
+ end.setUTCHours(0, 0, 0, 0);
switch (window) {
case 'today':
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()}`
+ return `${start.getUTCDate()} ${
+ months[start.getUTCMonth()]
+ } ${start.getUTCFullYear()}`;
case 'yesterday':
- start.setUTCDate(start.getUTCDate()-1)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()}`
+ start.setUTCDate(start.getUTCDate() - 1);
+ return `${start.getUTCDate()} ${
+ months[start.getUTCMonth()]
+ } ${start.getUTCFullYear()}`;
case 'week':
- start.setUTCDate(start.getUTCDate()-start.getUTCDay())
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} until now`
+ start.setUTCDate(start.getUTCDate() - start.getUTCDay());
+ return `${start.getUTCDate()} ${
+ months[start.getUTCMonth()]
+ } ${start.getUTCFullYear()} until now`;
case 'month':
- start.setUTCDate(1)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} until now`
+ start.setUTCDate(1);
+ return `${start.getUTCDate()} ${
+ months[start.getUTCMonth()]
+ } ${start.getUTCFullYear()} until now`;
case 'lastweek':
- start.setUTCDate(start.getUTCDate()-(start.getUTCDay()+7))
- end.setUTCDate(end.getUTCDate()-(end.getUTCDay()+1))
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through ${end.getUTCDate()} ${months[end.getUTCMonth()]} ${end.getUTCFullYear()}`
+ start.setUTCDate(start.getUTCDate() - (start.getUTCDay() + 7));
+ end.setUTCDate(end.getUTCDate() - (end.getUTCDay() + 1));
+ return `${start.getUTCDate()} ${
+ months[start.getUTCMonth()]
+ } ${start.getUTCFullYear()} through ${end.getUTCDate()} ${
+ months[end.getUTCMonth()]
+ } ${end.getUTCFullYear()}`;
case 'lastmonth':
- end.setUTCDate(1)
- end.setUTCDate(end.getUTCDate()-1)
- start.setUTCDate(1)
- start.setUTCDate(start.getUTCDate()-1)
- start.setUTCDate(1)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through ${end.getUTCDate()} ${months[end.getUTCMonth()]} ${end.getUTCFullYear()}`
+ end.setUTCDate(1);
+ end.setUTCDate(end.getUTCDate() - 1);
+ start.setUTCDate(1);
+ start.setUTCDate(start.getUTCDate() - 1);
+ start.setUTCDate(1);
+ return `${start.getUTCDate()} ${
+ months[start.getUTCMonth()]
+ } ${start.getUTCFullYear()} through ${end.getUTCDate()} ${
+ months[end.getUTCMonth()]
+ } ${end.getUTCFullYear()}`;
case '6d':
- start.setUTCDate(start.getUTCDate()-6)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through now`
+ start.setUTCDate(start.getUTCDate() - 6);
+ return `${start.getUTCDate()} ${
+ months[start.getUTCMonth()]
+ } ${start.getUTCFullYear()} through now`;
case '29d':
- start.setUTCDate(start.getUTCDate()-29)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through now`
+ start.setUTCDate(start.getUTCDate() - 29);
+ return `${start.getUTCDate()} ${
+ months[start.getUTCMonth()]
+ } ${start.getUTCFullYear()} through now`;
case '59d':
- start.setUTCDate(start.getUTCDate()-59)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through now`
+ start.setUTCDate(start.getUTCDate() - 59);
+ return `${start.getUTCDate()} ${
+ months[start.getUTCMonth()]
+ } ${start.getUTCFullYear()} through now`;
case '89d':
- start.setUTCDate(start.getUTCDate()-89)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through now`
+ start.setUTCDate(start.getUTCDate() - 89);
+ return `${start.getUTCDate()} ${
+ months[start.getUTCMonth()]
+ } ${start.getUTCFullYear()} through now`;
+ // no default
}
- const splitDates = window.split(",")
+ const splitDates = window.split(',');
if (checkCustomWindow(window) && splitDates.length > 1) {
- let s = splitDates[0].split(/\D+/).slice(0, 3)
- let e = splitDates[1].split(/\D+/).slice(0, 3)
+ const s = splitDates[0].split(/\D+/).slice(0, 3);
+ const e = splitDates[1].split(/\D+/).slice(0, 3);
if (s.length === 3 && e.length === 3) {
- start.setUTCFullYear(s[0], s[1]-1, s[2])
- end.setUTCFullYear(e[0], e[1]-1, e[2])
+ start.setUTCFullYear(s[0], s[1] - 1, s[2]);
+ end.setUTCFullYear(e[0], e[1] - 1, e[2]);
if (start === end) {
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()}`
- } else {
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through ${end.getUTCDate()} ${months[end.getUTCMonth()]} ${end.getUTCFullYear()}`
+ return `${start.getUTCDate()} ${
+ months[start.getUTCMonth()]
+ } ${start.getUTCFullYear()}`;
}
+ return `${start.getUTCDate()} ${
+ months[start.getUTCMonth()]
+ } ${start.getUTCFullYear()} through ${end.getUTCDate()} ${
+ months[end.getUTCMonth()]
+ } ${end.getUTCFullYear()}`;
}
}
- return null
+ return null;
}
export function bytesToString(bytes) {
- const ei = Math.pow(1024, 6)
+ const ei = Math.pow(1024, 6);
if (bytes >= ei) {
- return `${round(bytes/ei, 1)} EiB`
+ return `${round(bytes / ei, 1)} EiB`;
}
- const pi = Math.pow(1024, 5)
+ const pi = Math.pow(1024, 5);
if (bytes >= pi) {
- return `${round(bytes/pi, 1)} PiB`
+ return `${round(bytes / pi, 1)} PiB`;
}
- const ti = Math.pow(1024, 4)
+ const ti = Math.pow(1024, 4);
if (bytes >= ti) {
- return `${round(bytes/ti, 1)} TiB`
+ return `${round(bytes / ti, 1)} TiB`;
}
- const gi = Math.pow(1024, 3)
+ const gi = Math.pow(1024, 3);
if (bytes >= gi) {
- return `${round(bytes/gi, 1)} GiB`
+ return `${round(bytes / gi, 1)} GiB`;
}
- const mi = Math.pow(1024, 2)
+ const mi = Math.pow(1024, 2);
if (bytes >= mi) {
- return `${round(bytes/mi, 1)} MiB`
+ return `${round(bytes / mi, 1)} MiB`;
}
- const ki = Math.pow(1024, 1)
+ const ki = Math.pow(1024, 1);
if (bytes >= ki) {
- return `${round(bytes/ki, 1)} KiB`
+ return `${round(bytes / ki, 1)} KiB`;
}
- return `${round(bytes, 1)} B`
+ return `${round(bytes, 1)} B`;
}
-const currencyLocale = "en-US"
+const currencyLocale = 'en-US';
export function toCurrency(amount, currency, precision) {
- if (typeof amount !== "number") {
- console.warn(`Tried to convert "${amount}" to currency, but it is not a number`)
- return ""
+ if (typeof amount !== 'number') {
+ Console.warn(
+ `Tried to convert "${amount}" to currency, but it is not a number`,
+ );
+ return '';
}
- if (currency === undefined || currency === "") {
- currency = "USD"
+ let ctype = currency;
+
+ if (currency === undefined || currency === '') {
+ ctype = 'USD';
}
const opts = {
- style: "currency",
- currency: currency,
+ style: 'currency',
+ currency: ctype,
+ };
- }
-
- if (typeof precision === "number") {
- opts.minimumFractionDigits = precision
- opts.maximumFractionDigits = precision
+ if (typeof precision === 'number') {
+ opts.minimumFractionDigits = precision;
+ opts.maximumFractionDigits = precision;
}
return amount.toLocaleString(currencyLocale, opts);
@@ -286,12 +356,11 @@ export function toCurrency(amount, currency, precision) {
export function checkCustomWindow(window) {
// Example ISO interval string: 2020-12-02T00:00:00Z,2020-12-03T23:59:59Z
- const customDateRegex = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z,\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/
- return customDateRegex.test(window)
+ const customDateRegex =
+ /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z,\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/;
+ return customDateRegex.test(window);
}
-
-
export default {
rangeToCumulative,
cumulativeToTotals,
@@ -299,4 +368,4 @@ export default {
bytesToString,
toCurrency,
checkCustomWindow,
-}
+};
diff --git a/yarn.lock b/yarn.lock
index 3bb3052421..4e837003a2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7482,6 +7482,39 @@ __metadata:
languageName: unknown
linkType: soft
+"@backstage/plugin-opencost@workspace:plugins/opencost":
+ version: 0.0.0-use.local
+ resolution: "@backstage/plugin-opencost@workspace:plugins/opencost"
+ dependencies:
+ "@backstage/cli": "workspace:^"
+ "@backstage/core-app-api": "workspace:^"
+ "@backstage/core-components": "workspace:^"
+ "@backstage/core-plugin-api": "workspace:^"
+ "@backstage/dev-utils": "workspace:^"
+ "@backstage/test-utils": "workspace:^"
+ "@backstage/theme": "workspace:^"
+ "@date-io/date-fns": ^2.16.0
+ "@material-ui/core": ^4.9.13
+ "@material-ui/icons": ^4.9.1
+ "@material-ui/lab": ^4.0.0-alpha.60
+ "@material-ui/pickers": ^3.3.10
+ "@material-ui/styles": ^4.11.5
+ "@testing-library/jest-dom": ^5.10.1
+ "@testing-library/react": ^12.1.3
+ "@testing-library/user-event": ^14.0.0
+ axios: ^1.4.0
+ cross-fetch: ^3.1.5
+ date-fns: ^2.30.0
+ lodash: ^4.17.21
+ msw: ^1.0.0
+ react-use: ^17.2.4
+ recharts: ^2.5.0
+ peerDependencies:
+ react: ^16.13.1 || ^17.0.0
+ react-router-dom: "*"
+ languageName: unknown
+ linkType: soft
+
"@backstage/plugin-org-react@workspace:plugins/org-react":
version: 0.0.0-use.local
resolution: "@backstage/plugin-org-react@workspace:plugins/org-react"
@@ -9948,6 +9981,13 @@ __metadata:
languageName: node
linkType: hard
+"@date-io/core@npm:^2.17.0":
+ version: 2.17.0
+ resolution: "@date-io/core@npm:2.17.0"
+ checksum: 008dfc79eb54256805113d76feca82fe0b08a245ecbfb2d53809e6a129dc201f9dbd053c8ad63512203ab1a13ff7f76de0edc31829588ef507d53307974c29a8
+ languageName: node
+ linkType: hard
+
"@date-io/date-fns@npm:^1.3.13":
version: 1.3.13
resolution: "@date-io/date-fns@npm:1.3.13"
@@ -9959,6 +9999,20 @@ __metadata:
languageName: node
linkType: hard
+"@date-io/date-fns@npm:^2.16.0":
+ version: 2.17.0
+ resolution: "@date-io/date-fns@npm:2.17.0"
+ dependencies:
+ "@date-io/core": ^2.17.0
+ peerDependencies:
+ date-fns: ^2.0.0
+ peerDependenciesMeta:
+ date-fns:
+ optional: true
+ checksum: bfab634c985a98dd44fdfc5f982b0348da2886c9ad79a8d71fd7bfa05b740af7f5cf340508cd7ce51d67c141fb8766998c8efdf50653252c68ec078471cd76e6
+ languageName: node
+ linkType: hard
+
"@date-io/luxon@npm:1.x, @date-io/luxon@npm:^1.3.13":
version: 1.3.13
resolution: "@date-io/luxon@npm:1.3.13"