diff --git a/app-config.yaml b/app-config.yaml index ef133491af..f890b4228a 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -373,6 +373,11 @@ auth: development: {} costInsights: engineerCost: 200000 + baseCurrency: + locale: en-US + options: + currency: EUR + minimumFractionDigits: 3 products: computeEngine: name: Compute Engine diff --git a/plugins/cost-insights/README.md b/plugins/cost-insights/README.md index eeafe9e029..945274202a 100644 --- a/plugins/cost-insights/README.md +++ b/plugins/cost-insights/README.md @@ -186,7 +186,11 @@ In the case you would like to show your baseline costs on the graph on other cur ## ./app-config.yaml costInsights: engineerCost: 200000 - baseCurrency: EUR + baseCurrency: + locale: en-US + options: + currency: EUR + minimumFractionDigits: 3 ``` ### Currencies (Optional) diff --git a/plugins/cost-insights/config.d.ts b/plugins/cost-insights/config.d.ts index 7c8b9d265d..5317485555 100644 --- a/plugins/cost-insights/config.d.ts +++ b/plugins/cost-insights/config.d.ts @@ -24,7 +24,54 @@ export interface Config { /** * @visibility frontend */ - baseCurrency?: Intl.NumberFormat; + baseCurrency?: { + /** + * @visibility frontend + */ + locale?: string; + options?: { + /** + * @visibility frontend + */ + localeMatcher?: string | undefined; + /** + * @visibility frontend + */ + style?: string | undefined; + /** + * @visibility frontend + */ + currency?: string | undefined; + /** + * @visibility frontend + */ + currencySign?: string | undefined; + /** + * @visibility frontend + */ + useGrouping?: boolean | undefined; + /** + * @visibility frontend + */ + minimumIntegerDigits?: number | undefined; + /** + * @visibility frontend + */ + minimumFractionDigits?: number | undefined; + /** + * @visibility frontend + */ + maximumFractionDigits?: number | undefined; + /** + * @visibility frontend + */ + minimumSignificantDigits?: number | undefined; + /** + * @visibility frontend + */ + maximumSignificantDigits?: number | undefined; + }; + }; products?: { [kind: string]: { diff --git a/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewBreakdownChart.tsx b/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewBreakdownChart.tsx index 838da0d1f4..80a8d5f9ac 100644 --- a/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewBreakdownChart.tsx +++ b/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewBreakdownChart.tsx @@ -186,9 +186,10 @@ export const CostOverviewBreakdownChart = ({ ? DateTime.fromMillis(label) : DateTime.fromISO(label!); const dateTitle = date.toUTC().toFormat(DEFAULT_DATE_FORMAT); + const formatGraphValueWith = formatGraphValue(baseCurrency); const items = payload.map((p, i) => ({ label: p.dataKey as string, - value: formatGraphValue(baseCurrency)(Number(p.value), i), + value: formatGraphValueWith(Number(p.value), i), fill: p.color!, })); const expandText = ( diff --git a/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewChart.tsx b/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewChart.tsx index 4232c56ffc..0a87474476 100644 --- a/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewChart.tsx +++ b/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewChart.tsx @@ -108,6 +108,7 @@ export const CostOverviewChart = ({ ? DateTime.fromMillis(label) : DateTime.fromISO(label!); const title = date.toUTC().toFormat(DEFAULT_DATE_FORMAT); + const formatGraphValueWith = formatGraphValue(baseCurrency); const items = payload .filter(p => dataKeys.includes(p.dataKey as string)) .map((p, i) => ({ @@ -117,16 +118,8 @@ export const CostOverviewChart = ({ : data.metric.name, value: p.dataKey === data.dailyCost.dataKey - ? formatGraphValue(baseCurrency)( - Number(p.value), - i, - data.dailyCost.format, - ) - : formatGraphValue(baseCurrency)( - Number(p.value), - i, - data.metric.format, - ), + ? formatGraphValueWith(Number(p.value), i, data.dailyCost.format) + : formatGraphValueWith(Number(p.value), i, data.metric.format), fill: p.dataKey === data.dailyCost.dataKey ? theme.palette.blue diff --git a/plugins/cost-insights/src/hooks/useConfig.tsx b/plugins/cost-insights/src/hooks/useConfig.tsx index 34ecfd463d..679031b131 100644 --- a/plugins/cost-insights/src/hooks/useConfig.tsx +++ b/plugins/cost-insights/src/hooks/useConfig.tsx @@ -25,7 +25,7 @@ import { Config as BackstageConfig } from '@backstage/config'; import { Currency, Icon, Metric, Product } from '../types'; import { getIcon } from '../utils/navigation'; import { validateCurrencies, validateMetrics } from '../utils/config'; -import { createCurrency, defaultCurrencies } from '../utils/currency'; +import { createCurrencyFormat, defaultCurrencies } from '../utils/currency'; import { configApiRef, useApi } from '@backstage/core-plugin-api'; /* @@ -80,7 +80,7 @@ export const ConfigContext = createContext( ); const defaultState: ConfigContextProps = { - baseCurrency: createCurrency(), + baseCurrency: createCurrencyFormat(), metrics: [], products: [], icons: [], @@ -124,11 +124,11 @@ export const ConfigProvider = ({ children }: PropsWithChildren<{}>) => { if (baseCurrency) { const options = baseCurrency.getOptionalConfig('options'); return new Intl.NumberFormat( - baseCurrency.getOptionalString('locales'), + baseCurrency.getOptionalString('locale'), options ? { localeMatcher: options.getOptionalString('localeMatcher'), - style: options.getOptionalString('style'), + style: 'currency', currency: options.getOptionalString('currency'), currencySign: options.getOptionalString('currencySign'), useGrouping: options.getOptionalBoolean('useGrouping'), diff --git a/plugins/cost-insights/src/testUtils/providers.tsx b/plugins/cost-insights/src/testUtils/providers.tsx index 761a908ca4..bdba7c26fb 100644 --- a/plugins/cost-insights/src/testUtils/providers.tsx +++ b/plugins/cost-insights/src/testUtils/providers.tsx @@ -23,7 +23,7 @@ import { CurrencyContext, CurrencyContextProps } from '../hooks'; import { BillingDateContext, BillingDateContextProps } from '../hooks'; import { ScrollContext, ScrollContextProps } from '../hooks'; import { Duration } from '../types'; -import { createCurrency } from '../utils/currency'; +import { createCurrencyFormat } from '../utils/currency'; export type MockFilterProviderProps = PropsWithChildren< Partial @@ -81,7 +81,7 @@ export const MockConfigProvider = (props: MockConfigProviderProps) => { const { children, ...context } = props; const defaultContext: ConfigContextProps = { - baseCurrency: createCurrency(), + baseCurrency: createCurrencyFormat(), metrics: [], products: [], icons: [], diff --git a/plugins/cost-insights/src/utils/currency.ts b/plugins/cost-insights/src/utils/currency.ts index 400d3bcb72..98c968fc53 100644 --- a/plugins/cost-insights/src/utils/currency.ts +++ b/plugins/cost-insights/src/utils/currency.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { Currency, CurrencyType, Duration } from '../types'; -import { assertNever } from '../utils/assert'; +import { assertNever } from './assert'; export const rateOf = (cost: number, duration: Duration) => { switch (duration) { @@ -62,7 +62,7 @@ export const defaultCurrencies: Currency[] = [ }, ]; -export const createCurrency = ( +export const createCurrencyFormat = ( currency: string = 'USD', locale: string = 'en-US', ) => diff --git a/plugins/cost-insights/src/utils/formatters.test.ts b/plugins/cost-insights/src/utils/formatters.test.ts index f1cf778b6c..1190ac17ae 100644 --- a/plugins/cost-insights/src/utils/formatters.test.ts +++ b/plugins/cost-insights/src/utils/formatters.test.ts @@ -21,7 +21,7 @@ import { quarterOf, } from './formatters'; import { Duration } from '../types'; -import { createCurrency } from './currency'; +import { createCurrencyFormat } from './currency'; Date.now = jest.fn(() => new Date(Date.parse('2019-12-07')).valueOf()); @@ -40,7 +40,7 @@ describe('date formatters', () => { 0.00000040925, 0.21, 0.0000004, 0.4139877878, 0.00000234566, ]; const formattedValues = values.map(val => - lengthyCurrencyFormatter(createCurrency()).format(val), + lengthyCurrencyFormatter(createCurrencyFormat()).format(val), ); expect(formattedValues).toEqual([ '$0.00000041', @@ -56,7 +56,7 @@ describe('date formatters', () => { 0.00000040925, 0.21, 0.0000004, 0.4139877878, 0.00000234566, ]; const formattedValues = values.map(val => - lengthyCurrencyFormatter(createCurrency('EUR')).format(val), + lengthyCurrencyFormatter(createCurrencyFormat('EUR')).format(val), ); expect(formattedValues).toEqual([ '€0.00000041', diff --git a/plugins/cost-insights/src/utils/graphs.test.ts b/plugins/cost-insights/src/utils/graphs.test.ts index 5b425edb44..72749d7682 100644 --- a/plugins/cost-insights/src/utils/graphs.test.ts +++ b/plugins/cost-insights/src/utils/graphs.test.ts @@ -16,19 +16,23 @@ import { formatGraphValue, tooltipItemOf } from './graphs'; import { DataKey } from '../types'; -import { createCurrency } from './currency'; +import { createCurrencyFormat } from './currency'; describe('graphs', () => { it('formatGraphValue', () => { - expect(formatGraphValue(createCurrency('SEK'))(1000, 0)).toEqual( + expect(formatGraphValue(createCurrencyFormat('SEK'))(1000, 0)).toEqual( 'SEK 1,000', ); - expect(formatGraphValue(createCurrency('EUR'))(1000, 0)).toEqual('€1,000'); - expect(formatGraphValue(createCurrency('USD'))(1000, 0)).toEqual('$1,000'); + expect(formatGraphValue(createCurrencyFormat('EUR'))(1000, 0)).toEqual( + '€1,000', + ); + expect(formatGraphValue(createCurrencyFormat('USD'))(1000, 0)).toEqual( + '$1,000', + ); }); it('tooltipItemOf', () => { expect( - tooltipItemOf(createCurrency('EUR'))({ + tooltipItemOf(createCurrencyFormat('EUR'))({ value: '1000', color: 'red', dataKey: DataKey.Current, @@ -37,7 +41,7 @@ describe('graphs', () => { ).toEqual({ fill: 'red', label: 'Kubernetes', - value: '€1,000', + value: '€1,000.00', }); }); });