Make products optional

Signed-off-by: kielosz <kielosz@gmail.com>
This commit is contained in:
kielosz
2022-08-03 16:22:51 +02:00
parent 84ad48160a
commit b746eca638
6 changed files with 60 additions and 37 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-cost-insights': patch
---
Make `products` field optional in the config
+13 -3
View File
@@ -120,14 +120,24 @@ To expose the plugin to your users, you can integrate the `cost-insights` route
## Configuration
Cost Insights has only two required configuration fields: a map of cloud `products` for showing cost breakdowns and `engineerCost` - the average yearly cost of an engineer including benefits. Products must be defined as keys on the `products` field.
Cost Insights has only one required configuration field: `engineerCost` - the average yearly cost of an engineer including benefits.
### Basic
```yaml
## ./app-config.yaml
costInsights:
engineerCost: 200000
```
### Products (Optional)
For showing cost breakdowns you can define a map of cloud products. They must be defined as keys on the `products` field. A user-friendly name is **required**.
You can optionally supply a product `icon` to display in Cost Insights navigation. See the [type file](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/types/Icon.ts) for supported types and Material UI icon [mappings](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/utils/navigation.tsx).
**Note:** Product keys should be unique and camelCased. Backstage does not support underscores in configuration keys.
### Basic
```yaml
## ./app-config.yaml
costInsights:
+1 -1
View File
@@ -21,7 +21,7 @@ export interface Config {
*/
engineerCost: number;
products: {
products?: {
[kind: string]: {
/**
* @visibility frontend
@@ -84,6 +84,7 @@ export const CostInsightsPage = () => {
const accepted = useMemo(() => alerts.filter(isAlertAccepted), [alerts]);
const dismissed = useMemo(() => alerts.filter(isAlertDismissed), [alerts]);
const isProductsDisplayed = !!config.products?.length;
const isActionItemsDisplayed = !!active.length;
const isAlertInsightsDisplayed = !!alerts.length;
@@ -247,14 +248,16 @@ export const CostInsightsPage = () => {
return (
<CostInsightsLayout groups={groups}>
<Grid container wrap="nowrap">
<Grid item>
<Box position="sticky" top={20}>
<CostInsightsNavigation
products={products}
alerts={active.length}
/>
</Box>
</Grid>
{(isProductsDisplayed || isActionItemsDisplayed) && (
<Grid item>
<Box position="sticky" top={20}>
<CostInsightsNavigation
products={products}
alerts={active.length}
/>
</Box>
</Grid>
)}
<Grid item xs>
<Box
display="flex"
@@ -316,17 +319,19 @@ export const CostInsightsPage = () => {
</Box>
</Grid>
</Collapse>
{!isAlertInsightsDisplayed && <Divider />}
<Grid item xs>
<Box px={3} py={6}>
<ProductInsights
group={pageFilters.group}
project={pageFilters.project}
products={config.products}
onLoaded={setProducts}
/>
</Box>
</Grid>
{!isAlertInsightsDisplayed && isProductsDisplayed && <Divider />}
{isProductsDisplayed && (
<Grid item xs>
<Box px={3} py={6}>
<ProductInsights
group={pageFilters.group}
project={pageFilters.project}
products={config.products}
onLoaded={setProducts}
/>
</Box>
</Grid>
)}
</Grid>
</Container>
</Grid>
+17 -13
View File
@@ -85,12 +85,15 @@ export const ConfigProvider = ({ children }: PropsWithChildren<{}>) => {
useEffect(() => {
function getProducts(): Product[] {
const products = c.getConfig('costInsights.products');
return products.keys().map(key => ({
kind: key,
name: products.getString(`${key}.name`),
aggregation: [0, 0],
}));
const products = c.getOptionalConfig('costInsights.products');
if (products) {
return products.keys().map(key => ({
kind: key,
name: products.getString(`${key}.name`),
aggregation: [0, 0],
}));
}
return [];
}
function getMetrics(): Metric[] {
@@ -122,13 +125,14 @@ export const ConfigProvider = ({ children }: PropsWithChildren<{}>) => {
}
function getIcons(): Icon[] {
const products = c.getConfig('costInsights.products');
const keys = products.keys();
return keys.map(k => ({
kind: k,
component: getIcon(products.getOptionalString(`${k}.icon`)),
}));
const products = c.getOptionalConfig('costInsights.products');
if (products) {
return products.keys().map(k => ({
kind: k,
component: getIcon(products.getOptionalString(`${k}.icon`)),
}));
}
return [];
}
function getEngineerCost(): number {
@@ -35,7 +35,6 @@ export enum DefaultLoadingAction {
export const INITIAL_LOADING_ACTIONS = [
DefaultLoadingAction.UserGroups,
DefaultLoadingAction.CostInsightsInitial,
DefaultLoadingAction.CostInsightsProducts,
];
export const getDefaultState = (loadingActions: string[]): Loading => {