diff --git a/plugins/cost-insights/src/client.ts b/plugins/cost-insights/src/client.ts
index 2180385424..db999584a0 100644
--- a/plugins/cost-insights/src/client.ts
+++ b/plugins/cost-insights/src/client.ts
@@ -332,14 +332,14 @@ export class ExampleCostInsightsClient implements CostInsightsApi {
project: 'example-project',
periodStart: '2020-Q2',
periodEnd: '2020-Q3',
- aggregation: [60_000, 120_000],
+ aggregation: [100, 120_000],
change: {
- ratio: 1,
+ ratio: 10.123123,
amount: 60000,
},
products: [
{ id: 'Compute Engine', aggregation: [58_000, 118_000] },
- { id: 'Cloud Dataflow', aggregation: [1200, 1500] },
+ { id: 'Cloud Dataflow', aggregation: [0, 15_000] },
{ id: 'Cloud Storage', aggregation: [800, 500] },
],
};
diff --git a/plugins/cost-insights/src/components/ProductInsights/ProductInsights.tsx b/plugins/cost-insights/src/components/ProductInsights/ProductInsights.tsx
index c5d39a5139..affef5d182 100644
--- a/plugins/cost-insights/src/components/ProductInsights/ProductInsights.tsx
+++ b/plugins/cost-insights/src/components/ProductInsights/ProductInsights.tsx
@@ -16,7 +16,7 @@
import React from 'react';
import { Box, Typography, Grid } from '@material-ui/core';
-import { ProductInsightsCard } from '../ProductInsightsCard';
+import { ProductInsightsCardList } from '../ProductInsightsCard';
import { useConfig } from '../../hooks';
export const ProductInsights = ({}) => {
@@ -30,11 +30,7 @@ export const ProductInsights = ({}) => {
- {config.products.map(product => (
-
-
-
- ))}
+
>
);
diff --git a/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCard.test.tsx b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCard.test.tsx
index cdbbb79806..385ff82f9b 100644
--- a/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCard.test.tsx
+++ b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCard.test.tsx
@@ -22,19 +22,19 @@ import {
createMockEntity,
mockDefaultLoadingState,
MockComputeEngine,
- MockProductFilters,
} from '../../utils/mockData';
import {
- MockCostInsightsApiProvider,
- MockBillingDateProvider,
MockConfigProvider,
+ MockCostInsightsApiProvider,
MockCurrencyProvider,
- MockFilterProvider,
- MockGroupsProvider,
+ MockBillingDateProvider,
MockScrollProvider,
MockLoadingProvider,
} from '../../utils/tests';
-import { Duration, Entity, Product, ProductPeriod } from '../../types';
+import { Duration, Entity, Product } from '../../types';
+
+// suppress recharts componentDidUpdate warnings
+jest.spyOn(console, 'warn').mockImplementation(() => {});
const costInsightsApi = (entity: Entity): Partial => ({
getProductInsights: () => Promise.resolve(entity),
@@ -53,29 +53,25 @@ const mockProductCost = createMockEntity(() => ({
const renderProductInsightsCardInTestApp = async (
entity: Entity,
product: Product,
- duration: Duration,
+ duration = Duration.P30D,
+ onSelectAsync = jest.fn(() => Promise.resolve(mockProductCost)),
) =>
await renderInTestApp(
-
-
+
+
- ({
- ...p,
- duration: duration,
- }))}
- >
-
-
-
-
-
-
+
+
+
-
-
+
+
,
);
@@ -100,7 +96,6 @@ describe('', () => {
const rendered = await renderProductInsightsCardInTestApp(
entity,
MockComputeEngine,
- Duration.P1M,
);
const subheader = 'entities, sorted by cost';
const subheaderRgx = new RegExp(`${entity.entities.length} ${subheader}`);
diff --git a/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCard.tsx b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCard.tsx
index 2a1f962000..6d6d8d5cd9 100644
--- a/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCard.tsx
+++ b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCard.tsx
@@ -14,46 +14,84 @@
* limitations under the License.
*/
-import React, { useCallback, useEffect, useState } from 'react';
-import { InfoCard, useApi } from '@backstage/core';
-import Alert from '@material-ui/lab/Alert';
+import React, {
+ PropsWithChildren,
+ useCallback,
+ useEffect,
+ useRef,
+ useState,
+} from 'react';
+import { InfoCard } from '@backstage/core';
import { Typography } from '@material-ui/core';
-import { costInsightsApiRef } from '../../api';
-import { ProductInsightsChart } from './ProductInsightsChart';
import { PeriodSelect } from '../PeriodSelect';
-import {
- useFilters,
- useLastCompleteBillingDate,
- useLoading,
- useScroll,
-} from '../../hooks';
+import { ProductInsightsChart } from './ProductInsightsChart';
+import { ProductInsightsErrorCard } from './ProductInsightsErrorCard';
import { useProductInsightsCardStyles as useStyles } from '../../utils/styles';
-import { mapFiltersToProps, mapLoadingToProps } from './selector';
-import { Duration, Maybe, Product, Entity } from '../../types';
+import { DefaultLoadingAction } from '../../utils/loading';
+import { Duration, Entity, Maybe, Product } from '../../types';
+import {
+ useLastCompleteBillingDate,
+ useScroll,
+ useLoading,
+ MapLoadingToProps,
+} from '../../hooks';
import { pluralOf } from '../../utils/grammar';
-type ProductInsightsCardProps = {
+type LoadingProps = (isLoading: boolean) => void;
+
+export type ProductInsightsCardProps = {
product: Product;
+ initialState: {
+ entity: Maybe;
+ duration: Duration;
+ };
+ onSelectAsync: (product: Product, duration: Duration) => Promise;
};
-export const ProductInsightsCard = ({ product }: ProductInsightsCardProps) => {
- const client = useApi(costInsightsApiRef);
+const mapLoadingToProps: MapLoadingToProps = ({ dispatch }) => (
+ isLoading: boolean,
+) => dispatch({ [DefaultLoadingAction.CostInsightsProducts]: isLoading });
+
+export const ProductInsightsCard = ({
+ initialState,
+ product,
+ onSelectAsync,
+}: PropsWithChildren) => {
const classes = useStyles();
+ const mountedRef = useRef(false);
const { ScrollAnchor } = useScroll(product.kind);
- const lastCompleteBillingDate = useLastCompleteBillingDate();
- const [entity, setEntity] = useState>(null);
const [error, setError] = useState>(null);
+ const dispatchLoading = useLoading(mapLoadingToProps);
+ const lastCompleteBillingDate = useLastCompleteBillingDate();
+ const [entity, setEntity] = useState>(initialState.entity);
+ const [duration, setDuration] = useState(initialState.duration);
- const { group, product: productFilter, setProduct, project } = useFilters(
- mapFiltersToProps(product.kind),
- );
- const { loadingProduct, dispatchLoading } = useLoading(
- mapLoadingToProps(product.kind),
- );
+ /* eslint-disable react-hooks/exhaustive-deps */
+ const dispatchLoadingProduct = useCallback(dispatchLoading, []);
+ /* eslint-enable react-hooks/exhaustive-deps */
- // @see CostInsightsPage
- // eslint-disable-next-line react-hooks/exhaustive-deps
- const dispatchLoadingProduct = useCallback(dispatchLoading, [product.kind]);
+ useEffect(() => {
+ async function handleOnSelectAsync() {
+ dispatchLoadingProduct(true);
+ try {
+ const e = await onSelectAsync(product, duration);
+ setEntity(e);
+ } catch (e) {
+ setEntity(null);
+ setError(e);
+ } finally {
+ dispatchLoadingProduct(false);
+ }
+ }
+
+ if (mountedRef.current) {
+ handleOnSelectAsync();
+ }
+ }, [product, duration, onSelectAsync, dispatchLoadingProduct]);
+
+ useEffect(function hasComponentMounted() {
+ mountedRef.current = true;
+ }, []);
const amount = entity?.entities?.length || 0;
const hasCostsWithinTimeframe = !!(entity?.change && amount);
@@ -62,77 +100,31 @@ export const ProductInsightsCard = ({ product }: ProductInsightsCardProps) => {
? `${amount} ${pluralOf(amount, 'entity', 'entities')}, sorted by cost`
: null;
- useEffect(() => {
- async function load() {
- if (loadingProduct) {
- try {
- const e: Entity = await client.getProductInsights({
- product: product.kind,
- group: group!,
- duration: productFilter!.duration,
- lastCompleteBillingDate,
- project,
- });
- setEntity(e);
- } catch (e) {
- setError(e);
- } finally {
- dispatchLoadingProduct(false);
- }
- }
- }
- load();
- }, [
- client,
- product,
- setEntity,
- loadingProduct,
- dispatchLoadingProduct,
- productFilter,
- group,
- product.kind,
- project,
- lastCompleteBillingDate,
- ]);
-
- const onPeriodSelect = (duration: Duration) => {
- dispatchLoadingProduct(true);
- setProduct(duration);
- };
-
const infoCardProps = {
headerProps: {
classes: classes,
- action: (
-
- ),
+ action: ,
},
};
- if (error) {
+ if (error || !entity) {
return (
-
-
- {`Error: Could not fetch product insights for ${product.name}`}
-
+
);
}
- if (!entity) {
- return null;
- }
-
return (
{hasCostsWithinTimeframe ? (
) : (
diff --git a/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCardList.test.tsx b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCardList.test.tsx
new file mode 100644
index 0000000000..256ee8ba96
--- /dev/null
+++ b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCardList.test.tsx
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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 React from 'react';
+import { renderInTestApp } from '@backstage/test-utils';
+import { ProductInsightsCardList } from './ProductInsightsCardList';
+import { ProductInsightsOptions } from '../../api';
+import { mockDefaultLoadingState, MockProducts } from '../../utils/mockData';
+import {
+ MockConfigProvider,
+ MockCostInsightsApiProvider,
+ MockCurrencyProvider,
+ MockFilterProvider,
+ MockBillingDateProvider,
+ MockScrollProvider,
+ MockLoadingProvider,
+} from '../../utils/tests';
+import { Entity } from '../../types';
+
+// suppress recharts componentDidUpdate warnings
+jest.spyOn(console, 'warn').mockImplementation(() => {});
+
+const MockComputeEngineInsights: Entity = {
+ id: 'compute-engine',
+ entities: [],
+ aggregation: [0, 0],
+ change: {
+ ratio: 0,
+ amount: 0,
+ },
+};
+
+const MockCloudDataflowInsights: Entity = {
+ id: 'cloud-dataflow',
+ entities: [],
+ aggregation: [1_000, 2_000],
+ change: {
+ ratio: 1,
+ amount: 1_000,
+ },
+};
+
+const MockCloudStorageInsights: Entity = {
+ id: 'cloud-storage',
+ entities: [],
+ aggregation: [2_000, 4_000],
+ change: {
+ ratio: 1,
+ amount: 2_000,
+ },
+};
+
+const MockBigQueryInsights: Entity = {
+ id: 'big-query',
+ entities: [],
+ aggregation: [8_000, 16_000],
+ change: {
+ ratio: 1,
+ amount: 8_000,
+ },
+};
+
+const MockBigTableInsights: Entity = {
+ id: 'big-table',
+ entities: [],
+ aggregation: [16_000, 32_000],
+ change: {
+ ratio: 1,
+ amount: 16_000,
+ },
+};
+
+const MockCloudPubSubInsights: Entity = {
+ id: 'cloud-pub-sub',
+ entities: [],
+ aggregation: [32_000, 64_000],
+ change: {
+ ratio: 1,
+ amount: 32_000,
+ },
+};
+
+const ProductEntityMap = {
+ [MockBigQueryInsights.id!]: MockBigQueryInsights,
+ [MockBigTableInsights.id!]: MockBigTableInsights,
+ [MockCloudPubSubInsights.id!]: MockCloudPubSubInsights,
+ [MockCloudStorageInsights.id!]: MockCloudStorageInsights,
+ [MockCloudDataflowInsights.id!]: MockCloudDataflowInsights,
+ [MockComputeEngineInsights.id!]: MockComputeEngineInsights,
+};
+
+const costInsightsApi = {
+ getProductInsights: ({ product }: ProductInsightsOptions): Promise =>
+ Promise.resolve(ProductEntityMap[product]),
+};
+
+function renderInContext(children: JSX.Element) {
+ return renderInTestApp(
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+ ,
+ );
+}
+
+describe('', () => {
+ it('should render each product panel', async () => {
+ const noComputeEngineCostsRgx = /There are no Compute Engine costs within this timeframe for your team's projects./;
+ const { getByText } = await renderInContext(
+ ,
+ );
+ expect(getByText(noComputeEngineCostsRgx)).toBeInTheDocument();
+ MockProducts.forEach(product =>
+ expect(getByText(product.name)).toBeInTheDocument(),
+ );
+ });
+
+ it('product panels should be sorted by total aggregated cost', async () => {
+ const { queryAllByTestId } = await renderInContext(
+ ,
+ );
+ const expectedOrder = MockProducts.map(
+ product => `product-list-item-${product.kind}`,
+ ).reverse();
+ const productPanels = queryAllByTestId(/^product-list-item/);
+
+ expect(productPanels.length).toBe(MockProducts.length);
+ Array.from(productPanels)
+ .map(el => el.getAttribute('data-testid'))
+ .forEach((id, i) => {
+ expect(id).toBe(expectedOrder[i]);
+ });
+ });
+});
diff --git a/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCardList.tsx b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCardList.tsx
new file mode 100644
index 0000000000..5c096553e1
--- /dev/null
+++ b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsCardList.tsx
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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 React, { useCallback, useEffect, useReducer, useRef } from 'react';
+import { Box, CircularProgress } from '@material-ui/core';
+import { useApi } from '@backstage/core';
+import { costInsightsApiRef } from '../../api';
+import { ProductInsightsCard } from './ProductInsightsCard';
+import { Duration, Entity, Maybe, Product } from '../../types';
+import { DefaultLoadingAction } from '../../utils/loading';
+import {
+ useFilters,
+ useLoading,
+ useLastCompleteBillingDate,
+ MapLoadingToProps,
+} from '../../hooks';
+
+type State = {
+ [kind: string]: ProductState;
+};
+
+type ProductState = {
+ product: Product;
+ entity: Maybe;
+ duration: Duration;
+};
+
+type LoadingProps = (isLoading: boolean) => void;
+
+type ProductInsightsCardListProps = {
+ products: Product[];
+};
+
+const DEFAULT_DURATION = Duration.P30D;
+
+function totalAggregationSort(a: ProductState, b: ProductState): number {
+ const [prevA, currA] = a.entity?.aggregation ?? [0, 0];
+ const [prevB, currB] = b.entity?.aggregation ?? [0, 0];
+ return prevB + currB - (prevA + currA);
+}
+
+const mapLoadingToProps: MapLoadingToProps = ({ dispatch }) => (
+ isLoading: boolean,
+) => dispatch({ [DefaultLoadingAction.CostInsightsProducts]: isLoading });
+
+function reducer(prevState: State, action: State): State {
+ return {
+ ...prevState,
+ ...action,
+ };
+}
+
+export const ProductInsightsCardList = ({
+ products,
+}: ProductInsightsCardListProps) => {
+ const onceRef = useRef(false);
+ const client = useApi(costInsightsApiRef);
+ const filters = useFilters(p => p.pageFilters);
+ const [state, dispatch] = useReducer(reducer, {});
+ const lastCompleteBillingDate = useLastCompleteBillingDate();
+ const dispatchLoading = useLoading(mapLoadingToProps);
+
+ /* eslint-disable react-hooks/exhaustive-deps */
+ // See @CostInsightsPage
+ const dispatchLoadingProducts = useCallback(dispatchLoading, []);
+ /* eslint-enable react-hooks/exhaustive-deps */
+
+ const initialProductStates = onceRef.current
+ ? Object.values(state).sort(totalAggregationSort)
+ : Object.values(state);
+
+ const onSelectAsyncMemo = useCallback(
+ async function onSelectAsync(
+ product: Product,
+ duration: Duration,
+ ): Promise {
+ if (filters.group) {
+ return client.getProductInsights({
+ group: filters.group,
+ project: filters.project,
+ product: product.kind,
+ duration: duration,
+ lastCompleteBillingDate: lastCompleteBillingDate,
+ });
+ }
+ return Promise.reject(
+ new Error(
+ `Cannot fetch insights for ${product.name}: Expected to have a group but found none.`,
+ ),
+ );
+ },
+ [client, filters.group, filters.project, lastCompleteBillingDate],
+ );
+
+ useEffect(() => {
+ async function getAllProductInsights(
+ products: Product[],
+ group: string,
+ project: Maybe,
+ lastCompleteBillingDate: string,
+ ) {
+ const requests = products.map(product =>
+ client.getProductInsights({
+ group: group,
+ project: project,
+ product: product.kind,
+ duration: DEFAULT_DURATION,
+ lastCompleteBillingDate: lastCompleteBillingDate,
+ }),
+ );
+
+ try {
+ dispatchLoadingProducts(true);
+ const responses = await Promise.allSettled(requests);
+ const results = responses.map(response =>
+ response.status === 'fulfilled' ? response.value : null,
+ );
+ const initialState = results.reduce((acc, entity, index) => {
+ const product = products[index];
+ return {
+ ...acc,
+ [product.kind]: {
+ product: product,
+ entity: entity,
+ duration: DEFAULT_DURATION,
+ },
+ };
+ }, {});
+ dispatch(initialState);
+ } finally {
+ dispatchLoadingProducts(false);
+ }
+ }
+
+ if (filters.group) {
+ onceRef.current = true;
+ getAllProductInsights(
+ products,
+ filters.group,
+ filters.project,
+ lastCompleteBillingDate,
+ );
+ }
+ }, [
+ client,
+ products,
+ filters.group,
+ filters.project,
+ lastCompleteBillingDate,
+ dispatchLoadingProducts,
+ ]);
+
+ if (!initialProductStates.length) {
+ return ;
+ }
+
+ return (
+ <>
+ {initialProductStates.map(({ product, entity, duration }) => (
+
+
+
+ ))}
+ >
+ );
+};
diff --git a/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsErrorCard.tsx b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsErrorCard.tsx
new file mode 100644
index 0000000000..6f6c5a21c8
--- /dev/null
+++ b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsErrorCard.tsx
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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 React from 'react';
+import { InfoCard } from '@backstage/core';
+import { default as Alert } from '@material-ui/lab/Alert';
+import { PeriodSelect } from '../PeriodSelect';
+import { useScroll } from '../../hooks';
+import { useProductInsightsCardStyles as useStyles } from '../../utils/styles';
+import { Duration, Product } from '../../types';
+
+export type ProductInsightsErrorCardProps = {
+ product: Product;
+ duration: Duration;
+ onSelect: (duration: Duration) => void;
+};
+
+export const ProductInsightsErrorCard = ({
+ product,
+ duration,
+ onSelect,
+}: ProductInsightsErrorCardProps) => {
+ const classes = useStyles();
+ const { ScrollAnchor } = useScroll(product.kind);
+
+ const headerProps = {
+ classes: classes,
+ action: ,
+ };
+
+ return (
+
+
+ {`Error: Could not fetch product insights for ${product.name}`}
+
+ );
+};
diff --git a/plugins/cost-insights/src/components/ProductInsightsCard/index.ts b/plugins/cost-insights/src/components/ProductInsightsCard/index.ts
index 33a402234c..0a67bf459e 100644
--- a/plugins/cost-insights/src/components/ProductInsightsCard/index.ts
+++ b/plugins/cost-insights/src/components/ProductInsightsCard/index.ts
@@ -14,5 +14,5 @@
* limitations under the License.
*/
-export { ProductInsightsCard } from './ProductInsightsCard';
+export { ProductInsightsCardList } from './ProductInsightsCardList';
export { ProductInsightsChart } from './ProductInsightsChart';
diff --git a/plugins/cost-insights/src/hooks/useLoading.tsx b/plugins/cost-insights/src/hooks/useLoading.tsx
index 420ac7ed56..07f8a0f4e7 100644
--- a/plugins/cost-insights/src/hooks/useLoading.tsx
+++ b/plugins/cost-insights/src/hooks/useLoading.tsx
@@ -21,7 +21,6 @@ import React, {
SetStateAction,
useContext,
useEffect,
- useMemo,
useReducer,
useState,
} from 'react';
@@ -30,10 +29,9 @@ import { Loading } from '../types';
import {
DefaultLoadingAction,
getDefaultState,
- getLoadingActions,
+ INITIAL_LOADING_ACTIONS,
} from '../utils/loading';
import { useBackdropStyles as useStyles } from '../utils/styles';
-import { useConfig } from './useConfig';
export type LoadingContextProps = {
state: Loading;
@@ -56,10 +54,7 @@ function reducer(prevState: Loading, action: Partial): Loading {
export const LoadingProvider = ({ children }: PropsWithChildren<{}>) => {
const classes = useStyles();
- const { products } = useConfig();
- const actions = useMemo(() => getLoadingActions(products.map(p => p.kind)), [
- products,
- ]);
+ const actions = INITIAL_LOADING_ACTIONS;
const [state, dispatch] = useReducer(reducer, getDefaultState(actions));
const [isBackdropVisible, setBackdropVisible] = useState(false);
diff --git a/plugins/cost-insights/src/utils/loading.ts b/plugins/cost-insights/src/utils/loading.ts
index 4652603926..40101051b8 100644
--- a/plugins/cost-insights/src/utils/loading.ts
+++ b/plugins/cost-insights/src/utils/loading.ts
@@ -21,11 +21,13 @@ export enum DefaultLoadingAction {
LastCompleteBillingDate = 'billing-date',
CostInsightsInitial = 'cost-insights-initial',
CostInsightsPage = 'cost-insights-page',
+ CostInsightsProducts = 'cost-insights-products',
}
export const INITIAL_LOADING_ACTIONS = [
DefaultLoadingAction.UserGroups,
DefaultLoadingAction.CostInsightsInitial,
+ DefaultLoadingAction.CostInsightsProducts,
];
export const getDefaultState = (loadingActions: string[]): Loading => {
@@ -54,11 +56,3 @@ export const getResetStateWithoutInitial = (
return { ...defaultState, [action]: loadingActionState };
}, {});
};
-
-export function getLoadingActions(products: string[]): string[] {
- return ([
- DefaultLoadingAction.UserGroups,
- DefaultLoadingAction.CostInsightsInitial,
- DefaultLoadingAction.CostInsightsPage,
- ] as string[]).concat(products);
-}
diff --git a/plugins/cost-insights/src/utils/mockData.ts b/plugins/cost-insights/src/utils/mockData.ts
index 708ce733dd..e40e5e1ddc 100644
--- a/plugins/cost-insights/src/utils/mockData.ts
+++ b/plugins/cost-insights/src/utils/mockData.ts
@@ -145,14 +145,14 @@ export const MockProducts: Product[] = Object.keys(MockProductTypes).map(
})),
);
-export const MockLoadingActions = ([
+export const MockDefaultLoadingActions = ([
DefaultLoadingAction.UserGroups,
DefaultLoadingAction.CostInsightsInitial,
DefaultLoadingAction.CostInsightsPage,
] as string[]).concat(MockProducts.map(product => product.kind));
export const mockDefaultLoadingState = getDefaultLoadingState(
- MockLoadingActions,
+ MockDefaultLoadingActions,
);
export const MockComputeEngine = findAlways(