added optional currencies config
Signed-off-by: Vannarath Poeu <vannarath.poeu@gmail.com>
This commit is contained in:
@@ -369,6 +369,31 @@ costInsights:
|
||||
default: true
|
||||
MSC:
|
||||
name: Monthly Subscribers
|
||||
currencies:
|
||||
engineers:
|
||||
label: 'Engineers 🛠'
|
||||
unit: 'engineer'
|
||||
usd:
|
||||
label: 'US Dollars 💵'
|
||||
kind: 'USD'
|
||||
unit: 'dollar'
|
||||
prefix: '$'
|
||||
rate: 1
|
||||
carbonOffsetTons:
|
||||
label: 'Carbon Offset Tons ♻️⚖️s'
|
||||
kind: 'CARBON_OFFSET_TONS'
|
||||
unit: 'carbon offset ton'
|
||||
rate: 3.5
|
||||
beers:
|
||||
label: 'Beers 🍺'
|
||||
kind: 'BEERS'
|
||||
unit: 'beer'
|
||||
rate: 4.5
|
||||
pintsIceCream:
|
||||
label: 'Pints of Ice Cream 🍦'
|
||||
kind: 'PINTS_OF_ICE_CREAM'
|
||||
unit: 'ice cream pint'
|
||||
rate: 5.5
|
||||
homepage:
|
||||
clocks:
|
||||
- label: UTC
|
||||
|
||||
@@ -148,6 +148,36 @@ costInsights:
|
||||
name: Metric C
|
||||
```
|
||||
|
||||
### Currencies (Optional)
|
||||
|
||||
In the `Cost Overview` panel, users can choose from a dropdown of currencies to see costs in, such as Engineers or USD. Currencies must be defined as keys on the `currencies` field. A user-friendly label and unit are **required**. If not set, the `defaultCurrencies` in `currenc.ts` will be used.
|
||||
|
||||
A currency without `kind` is reserved to calculate cost for `engineers`. There should only be one currency without `kind`.
|
||||
|
||||
```yaml
|
||||
## ./app-config.yaml
|
||||
costInsights:
|
||||
engineerCost: 200000
|
||||
products:
|
||||
productA:
|
||||
name: Some Cloud Product
|
||||
icon: storage
|
||||
productB:
|
||||
name: Some Other Cloud Product
|
||||
icon: data
|
||||
currencies:
|
||||
metricA:
|
||||
currencyA:
|
||||
label: Currency A
|
||||
unit: Unit A
|
||||
currencyB:
|
||||
label: Currency B
|
||||
kind: CURRENCY_B
|
||||
unit: Unit B
|
||||
prefix: B
|
||||
rate: 3.5
|
||||
```
|
||||
|
||||
## Alerts
|
||||
|
||||
The CostInsightsApi `getAlerts` method may return any type of alert or recommendation (called collectively "Action Items" in Cost Insights) that implements the [Alert type](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/types/Alert.ts). This allows you to deliver any alerts or recommendations specific to your infrastructure or company migrations.
|
||||
|
||||
Vendored
+34
@@ -48,5 +48,39 @@ interface Config {
|
||||
default?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
currencies?: {
|
||||
[id: string]: {
|
||||
/**
|
||||
* @visibility frontend
|
||||
*/
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* @visibility frontend
|
||||
*/
|
||||
unit: string;
|
||||
|
||||
/**
|
||||
* @visibility frontend
|
||||
*/
|
||||
kind?: string;
|
||||
|
||||
/**
|
||||
* @visibility frontend
|
||||
*/
|
||||
prefix?: string;
|
||||
|
||||
/**
|
||||
* @visibility frontend
|
||||
*/
|
||||
rate?: number;
|
||||
|
||||
/**
|
||||
* @visibility frontend
|
||||
*/
|
||||
default?: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@ import React, {
|
||||
import { Config as BackstageConfig } from '@backstage/config';
|
||||
import { Currency, Icon, Metric, Product } from '../types';
|
||||
import { getIcon } from '../utils/navigation';
|
||||
import { validateMetrics } from '../utils/config';
|
||||
import { validateCurrencies, validateMetrics } from '../utils/config';
|
||||
import { defaultCurrencies } from '../utils/currency';
|
||||
import { configApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
|
||||
/*
|
||||
* Config schema 2020-10-15
|
||||
* Config schema 2021-08-05
|
||||
*
|
||||
* costInsights:
|
||||
* engineerCost: 200000
|
||||
@@ -46,6 +46,16 @@ import { configApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
* default: true
|
||||
* metricB:
|
||||
* name: Metric B
|
||||
* currencies:
|
||||
* currencyA:
|
||||
* label: Currency A
|
||||
* unit: Unit A
|
||||
* currencyB:
|
||||
* label: Currency B
|
||||
* kind: CURRENCY_B
|
||||
* unit: Unit B
|
||||
* prefix: B
|
||||
* rate: 3.5
|
||||
*/
|
||||
|
||||
export type ConfigContextProps = {
|
||||
@@ -96,6 +106,21 @@ export const ConfigProvider = ({ children }: PropsWithChildren<{}>) => {
|
||||
return [];
|
||||
}
|
||||
|
||||
function getCurrencies(): Currency[] {
|
||||
const currencies = c.getOptionalConfig('costInsights.currencies');
|
||||
if (currencies) {
|
||||
return currencies.keys().map(key => ({
|
||||
label: currencies.getString(`${key}.label`),
|
||||
unit: currencies.getString(`${key}.unit`),
|
||||
kind: currencies.getOptionalString(`${key}.kind`) || null,
|
||||
prefix: currencies.getOptionalString(`${key}.prefix`),
|
||||
rate: currencies.getOptionalNumber(`${key}.rate`),
|
||||
}));
|
||||
}
|
||||
|
||||
return defaultCurrencies;
|
||||
}
|
||||
|
||||
function getIcons(): Icon[] {
|
||||
const products = c.getConfig('costInsights.products');
|
||||
const keys = products.keys();
|
||||
@@ -115,8 +140,10 @@ export const ConfigProvider = ({ children }: PropsWithChildren<{}>) => {
|
||||
const metrics = getMetrics();
|
||||
const engineerCost = getEngineerCost();
|
||||
const icons = getIcons();
|
||||
const currencies = getCurrencies();
|
||||
|
||||
validateMetrics(metrics);
|
||||
validateCurrencies(currencies);
|
||||
|
||||
setConfig(prevState => ({
|
||||
...prevState,
|
||||
@@ -124,6 +151,7 @@ export const ConfigProvider = ({ children }: PropsWithChildren<{}>) => {
|
||||
products,
|
||||
engineerCost,
|
||||
icons,
|
||||
currencies,
|
||||
}));
|
||||
|
||||
setLoading(false);
|
||||
|
||||
@@ -21,8 +21,7 @@ import React, {
|
||||
PropsWithChildren,
|
||||
} from 'react';
|
||||
import { Currency } from '../types';
|
||||
import { findAlways } from '../utils/assert';
|
||||
import { defaultCurrencies } from '../utils/currency';
|
||||
import { useConfig } from './useConfig';
|
||||
|
||||
export type CurrencyContextProps = {
|
||||
currency: Currency;
|
||||
@@ -34,8 +33,12 @@ export const CurrencyContext = React.createContext<
|
||||
>(undefined);
|
||||
|
||||
export const CurrencyProvider = ({ children }: PropsWithChildren<{}>) => {
|
||||
const engineers = findAlways(defaultCurrencies, c => c.kind === null);
|
||||
const [currency, setCurrency] = useState<Currency>(engineers);
|
||||
const config = useConfig();
|
||||
const currencies = config.currencies;
|
||||
const engineers = currencies.find(currency => currency.kind === null);
|
||||
const [currency, setCurrency] = useState<Currency>(
|
||||
engineers || currencies[0],
|
||||
);
|
||||
return (
|
||||
<CurrencyContext.Provider value={{ currency, setCurrency }}>
|
||||
{children}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Metric } from '../types';
|
||||
import { Metric, Currency } from '../types';
|
||||
|
||||
export function validateMetrics(metrics: Metric[]) {
|
||||
const defaults = metrics.filter(metric => metric.default);
|
||||
@@ -24,3 +24,12 @@ export function validateMetrics(metrics: Metric[]) {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function validateCurrencies(currencies: Currency[]) {
|
||||
const withoutKinds = currencies.filter(currency => currency.kind === null);
|
||||
if (withoutKinds.length > 1) {
|
||||
throw new Error(
|
||||
`Only one currency can be without kind. Found ${withoutKinds.length}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user