Skip to content

Commit b8642ab

Browse files
authored
Merge pull request #4202 from dlabrecq/cost-5891
Show total cost in Cost Explorer header
2 parents 8841997 + 18b8afe commit b8642ab

File tree

5 files changed

+105
-42
lines changed

5 files changed

+105
-42
lines changed

src/api/resources/awsOcpResource.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ export const ResourceTypePaths: Partial<Record<ResourceType, string>> = {
1515

1616
export function runResource(resourceType: ResourceType, query: string) {
1717
const path = ResourceTypePaths[resourceType];
18-
const queryString = query ? `?openshift=true&${query}` : '?openshift=true';
18+
const openshiftParam = resourceType === ResourceType.aws_category ? '' : 'openshift=true';
19+
let queryString;
20+
21+
if (openshiftParam && query) {
22+
queryString = `?${openshiftParam}&${query}`;
23+
} else if (openshiftParam) {
24+
queryString = `?${openshiftParam}`;
25+
} else if (query) {
26+
queryString = `?${query}`;
27+
}
1928
return axiosInstance.get<Resource>(`${path}${queryString}`);
2029
}

src/routes/details/ocpDetails/detailsHeader.tsx

+2-24
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,17 @@ import { CostDistribution } from 'routes/components/costDistribution';
1717
import { Currency } from 'routes/components/currency';
1818
import { DateRange } from 'routes/components/dateRange';
1919
import { GroupBy } from 'routes/components/groupBy';
20-
import { EmptyValueState } from 'routes/components/state/emptyValueState';
2120
import { ProviderDetailsModal } from 'routes/details/components/providerStatus';
2221
import type { ComputedOcpReportItemsParams } from 'routes/utils/computedReport/getComputedOcpReportItems';
2322
import { getIdKeyForGroupBy } from 'routes/utils/computedReport/getComputedOcpReportItems';
23+
import { getTotalCost } from 'routes/utils/cost';
2424
import { DateRangeType, getCurrentDateRangeType } from 'routes/utils/dateRange';
2525
import { filterProviders } from 'routes/utils/providers';
2626
import type { FetchStatus } from 'store/common';
2727
import { createMapStateToProps } from 'store/common';
2828
import { FeatureToggleSelectors } from 'store/featureToggle';
2929
import { providersQuery, providersSelectors } from 'store/providers';
3030
import { getSinceDateRangeString } from 'utils/dates';
31-
import { formatCurrency } from 'utils/format';
3231
import type { RouterComponentProps } from 'utils/router';
3332
import { withRouter } from 'utils/router';
3433

@@ -133,28 +132,7 @@ class DetailsHeaderBase extends React.Component<DetailsHeaderProps, DetailsHeade
133132
const showContent = report && !providersError && providers?.meta?.count > 0;
134133
const showCostDistribution = costDistribution === ComputedReportItemValueType.distributed; // Always show -- see https://issues.redhat.com/browse/COST-5870
135134

136-
let cost: string | React.ReactNode = <EmptyValueState />;
137-
let supplementaryCost: string | React.ReactNode = <EmptyValueState />;
138-
let infrastructureCost: string | React.ReactNode = <EmptyValueState />;
139-
140-
const reportItemValue = costDistribution ? costDistribution : ComputedReportItemValueType.total;
141-
if (report?.meta?.total) {
142-
const hasCost = report.meta.total.cost && report.meta.total.cost[reportItemValue];
143-
const hasSupplementaryCost = report.meta.total.supplementary && report.meta.total.supplementary.total;
144-
const hasInfrastructureCost = report.meta.total.infrastructure && report.meta.total.infrastructure.total;
145-
cost = formatCurrency(
146-
hasCost ? report.meta.total.cost[reportItemValue].value : 0,
147-
hasCost ? report.meta.total.cost[reportItemValue].units : 'USD'
148-
);
149-
supplementaryCost = formatCurrency(
150-
hasSupplementaryCost ? report.meta.total.supplementary.total.value : 0,
151-
hasSupplementaryCost ? report.meta.total.supplementary.total.units : 'USD'
152-
);
153-
infrastructureCost = formatCurrency(
154-
hasInfrastructureCost ? report.meta.total.infrastructure.total.value : 0,
155-
hasInfrastructureCost ? report.meta.total.infrastructure.total.units : 'USD'
156-
);
157-
}
135+
const { cost, infrastructureCost, supplementaryCost } = getTotalCost(report, costDistribution);
158136

159137
return (
160138
<header style={styles.header}>

src/routes/explorer/explorerHeader.styles.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const styles = {
1515
costValue: {
1616
marginTop: 0,
1717
marginBottom: 0,
18-
marginRight: global_spacer_md.var,
18+
textAlign: 'right',
1919
},
2020
costLabelUnit: {
2121
fontSize: global_FontSize_sm.value,
@@ -25,6 +25,12 @@ export const styles = {
2525
fontSize: global_FontSize_sm.value,
2626
color: global_Color_200.var,
2727
},
28+
dateTitle: {
29+
textAlign: 'end',
30+
},
31+
filterContainer: {
32+
alignItems: 'unset',
33+
},
2834
header: {
2935
backgroundColor: global_BackgroundColor_light_100.var,
3036
paddingBottom: global_spacer_md.var,

src/routes/explorer/explorerHeader.tsx

+55-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Flex, FlexItem, Title, TitleSizes } from '@patternfly/react-core';
1+
import { Flex, FlexItem, Title, TitleSizes, Tooltip } from '@patternfly/react-core';
22
import type { Providers } from 'api/providers';
33
import { ProviderType } from 'api/providers';
44
import { getProvidersQuery } from 'api/queries/providersQuery';
@@ -23,6 +23,7 @@ import { Currency } from 'routes/components/currency';
2323
import { GroupBy } from 'routes/components/groupBy';
2424
import { Perspective } from 'routes/components/perspective';
2525
import { getIdKeyForGroupBy } from 'routes/utils/computedReport/getComputedExplorerReportItems';
26+
import { getTotalCost } from 'routes/utils/cost';
2627
import type { DateRangeType } from 'routes/utils/dateRange';
2728
import type { Filter } from 'routes/utils/filter';
2829
import { filterProviders, hasCloudProvider } from 'routes/utils/providers';
@@ -279,7 +280,10 @@ class ExplorerHeaderBase extends React.Component<ExplorerHeaderProps, ExplorerHe
279280
onFilterRemoved,
280281
onGroupBySelect,
281282
perspective,
283+
providers,
284+
providersError,
282285
providersFetchStatus,
286+
report,
283287
query,
284288
startDate,
285289
} = this.props;
@@ -299,8 +303,15 @@ class ExplorerHeaderBase extends React.Component<ExplorerHeaderProps, ExplorerHe
299303
const resourcePathsType = getResourcePathsType(perspective);
300304
const tagPathsType = getTagReportPathsType(perspective);
301305

306+
const showContent = report && !providersError && providers?.meta?.count > 0;
302307
const showCostDistribution = costDistribution === ComputedReportItemValueType.distributed; // Always show -- see https://issues.redhat.com/browse/COST-5870
303308

309+
const { cost, infrastructureCost, supplementaryCost } = getTotalCost(report, costDistribution);
310+
const dateRange = intl.formatDateTimeRange(new Date(startDate + 'T00:00:00'), new Date(endDate + 'T00:00:00'), {
311+
day: 'numeric',
312+
month: 'long',
313+
});
314+
304315
return (
305316
<header style={styles.header}>
306317
<Flex justifyContent={{ default: 'justifyContentSpaceBetween' }} style={styles.headerContent}>
@@ -351,21 +362,49 @@ class ExplorerHeaderBase extends React.Component<ExplorerHeaderProps, ExplorerHe
351362
</Flex>
352363
</FlexItem>
353364
</Flex>
354-
<ExplorerFilter
355-
dateRangeType={dateRangeType}
356-
endDate={endDate}
357-
groupBy={groupBy}
358-
isCurrentMonthData={isCurrentMonthData}
359-
isDataAvailable={isDataAvailable}
360-
isDisabled={noProviders}
361-
isPreviousMonthData={isPreviousMonthData}
362-
onFilterAdded={onFilterAdded}
363-
onFilterRemoved={onFilterRemoved}
364-
onDateRangeSelect={onDateRangeSelect}
365-
perspective={perspective}
366-
query={query}
367-
startDate={startDate}
368-
/>
365+
<Flex justifyContent={{ default: 'justifyContentSpaceBetween' }} style={styles.filterContainer}>
366+
<FlexItem>
367+
<ExplorerFilter
368+
dateRangeType={dateRangeType}
369+
endDate={endDate}
370+
groupBy={groupBy}
371+
isCurrentMonthData={isCurrentMonthData}
372+
isDataAvailable={isDataAvailable}
373+
isDisabled={noProviders}
374+
isPreviousMonthData={isPreviousMonthData}
375+
onFilterAdded={onFilterAdded}
376+
onFilterRemoved={onFilterRemoved}
377+
onDateRangeSelect={onDateRangeSelect}
378+
perspective={perspective}
379+
query={query}
380+
startDate={startDate}
381+
/>
382+
</FlexItem>
383+
<FlexItem>
384+
{showContent && (
385+
<>
386+
{perspective === PerspectiveType.ocp ? (
387+
<Tooltip
388+
content={intl.formatMessage(messages.dashboardTotalCostTooltip, {
389+
infrastructureCost,
390+
supplementaryCost,
391+
})}
392+
enableFlip
393+
>
394+
<Title headingLevel="h2" style={styles.costValue} size={TitleSizes['4xl']}>
395+
{cost}
396+
</Title>
397+
</Tooltip>
398+
) : (
399+
<Title headingLevel="h2" style={styles.costValue} size={TitleSizes['4xl']}>
400+
{cost}
401+
</Title>
402+
)}
403+
<div style={styles.dateTitle}>{intl.formatMessage(messages.sinceDate, { dateRange })}</div>
404+
</>
405+
)}
406+
</FlexItem>
407+
</Flex>
369408
</header>
370409
);
371410
}

src/routes/utils/cost.tsx

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { Report } from 'api/reports/report';
2+
import React from 'react';
3+
import { ComputedReportItemValueType } from 'routes/components/charts/common';
4+
import { EmptyValueState } from 'routes/components/state/emptyValueState';
5+
import { formatCurrency } from 'utils/format';
6+
7+
export const getTotalCost = (report: Report, costDistribution: string) => {
8+
let cost: string | React.ReactNode = <EmptyValueState />;
9+
let supplementaryCost: string | React.ReactNode = <EmptyValueState />;
10+
let infrastructureCost: string | React.ReactNode = <EmptyValueState />;
11+
12+
const reportItemValue = costDistribution ? costDistribution : ComputedReportItemValueType.total;
13+
if (report?.meta?.total) {
14+
const hasCost = report.meta.total.cost && report.meta.total.cost[reportItemValue];
15+
const hasSupplementaryCost = report.meta.total.supplementary && report.meta.total.supplementary.total;
16+
const hasInfrastructureCost = report.meta.total.infrastructure && report.meta.total.infrastructure.total;
17+
cost = formatCurrency(
18+
hasCost ? report.meta.total.cost[reportItemValue].value : 0,
19+
hasCost ? report.meta.total.cost[reportItemValue].units : 'USD'
20+
);
21+
supplementaryCost = formatCurrency(
22+
hasSupplementaryCost ? report.meta.total.supplementary.total.value : 0,
23+
hasSupplementaryCost ? report.meta.total.supplementary.total.units : 'USD'
24+
);
25+
infrastructureCost = formatCurrency(
26+
hasInfrastructureCost ? report.meta.total.infrastructure.total.value : 0,
27+
hasInfrastructureCost ? report.meta.total.infrastructure.total.units : 'USD'
28+
);
29+
}
30+
return { cost, infrastructureCost, supplementaryCost };
31+
};

0 commit comments

Comments
 (0)