Skip to content

Commit da41959

Browse files
committed
Add OpenShift VM Storage Support
https://issues.redhat.com/browse/COST-6024
1 parent 15a256b commit da41959

15 files changed

+331
-14
lines changed

locales/data.json

+40
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,12 @@
691691
"value": "Cancel"
692692
}
693693
],
694+
"capacity": [
695+
{
696+
"type": 0,
697+
"value": "Capacity"
698+
}
699+
],
694700
"chartCostForecastConeLabel": [
695701
{
696702
"type": 0,
@@ -3135,6 +3141,14 @@
31353141
}
31363142
]
31373143
},
3144+
"storage": {
3145+
"value": [
3146+
{
3147+
"type": 0,
3148+
"value": "Storage"
3149+
}
3150+
]
3151+
},
31383152
"subscription_guid": {
31393153
"value": [
31403154
{
@@ -12998,6 +13012,26 @@
1299813012
"value": "StorageClass"
1299913013
}
1300013014
],
13015+
"storageHeadingTitle": [
13016+
{
13017+
"type": 0,
13018+
"value": "Storage ("
13019+
},
13020+
{
13021+
"type": 1,
13022+
"value": "value"
13023+
},
13024+
{
13025+
"type": 0,
13026+
"value": ")"
13027+
}
13028+
],
13029+
"storageNames": [
13030+
{
13031+
"type": 0,
13032+
"value": "Storage names"
13033+
}
13034+
],
1300113035
"storageUnattributedDistributed": [
1300213036
{
1300313037
"type": 0,
@@ -13873,6 +13907,12 @@
1387313907
"value": "View release notes"
1387413908
}
1387513909
],
13910+
"virtualMachine": [
13911+
{
13912+
"type": 0,
13913+
"value": "Virtual machine"
13914+
}
13915+
],
1387613916
"virtualization": [
1387713917
{
1387813918
"type": 0,

locales/translations.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"breakdownTotalCostDate": "{value} total cost ({dateRange})",
3434
"calculationType": "Calculation type",
3535
"cancel": "Cancel",
36+
"capacity": "Capacity",
3637
"chartCostForecastConeLabel": "Cost confidence ({dateRange})",
3738
"chartCostForecastConeLabelNoData": "Cost confidence (no data)",
3839
"chartCostForecastConeRangeTooltip": "{value0} - {value1}",
@@ -235,7 +236,7 @@
235236
"detailsEmptyState": "Processing data to generate a list of all services that sums to a total cost...",
236237
"detailsMore": "{value} more...",
237238
"detailsMoreClusters": ", {value} more...",
238-
"detailsResourceNames": "{value, select, account {Account names} aws_category {Cost category names} cluster {Cluster names} cpu {CPU} gcp_project {GCP project names} group {Group} instance {Instance names} instance_type {Instance type} memory {Memory} name {Name} node {Node names} org_unit_id {Organizational unit names} os {OS} operating_system {Operating system} payer_tenant_id {Account names} product_service {Service names} project {Project names} region {Region names} resource_location {Region names} service {Service names} service_name {Service names} status {Status} subscription_guid {Account names} source_type {Integration} tag {Tag names} tags {Tags} tag_key {Tag keys} usage {Usage} vcpu {vCPU} vm_name {Virtual machine names} other {}}",
239+
"detailsResourceNames": "{value, select, account {Account names} aws_category {Cost category names} cluster {Cluster names} cpu {CPU} gcp_project {GCP project names} group {Group} instance {Instance names} instance_type {Instance type} memory {Memory} name {Name} node {Node names} org_unit_id {Organizational unit names} os {OS} operating_system {Operating system} payer_tenant_id {Account names} product_service {Service names} project {Project names} region {Region names} resource_location {Region names} service {Service names} service_name {Service names} status {Status} subscription_guid {Account names} source_type {Integration} storage {Storage} tag {Tag names} tags {Tags} tag_key {Tag keys} usage {Usage} vcpu {vCPU} vm_name {Virtual machine names} other {}}",
239240
"detailsSummaryModalTitle": "{groupBy, select, account {{name} accounts} aws_category {{name} cost categories} cluster {{name} clusters} gcp_project {{name} GCP projects} node {{name} nodes} org_unit_id {{name} organizational units} payer_tenant_id {{name} accounts} product_service {{name} services} project {{name} projects} region {{name} regions} resource_location {{name} regions} service {{name} services} service_name {{name} services} subscription_guid {{name} accounts} tag {{name} tags} other {}}",
240241
"detailsUnusedCapacityLabel": "Unused capacity",
241242
"detailsUnusedRequestsLabel": "Unused requests",
@@ -614,6 +615,8 @@
614615
"statusStates": "{value, select, pending {Pending} running {Running} failed {Failed} other {}}",
615616
"storage": "Storage",
616617
"storageClass": "StorageClass",
618+
"storageHeadingTitle": "Storage ({value})",
619+
"storageNames": "Storage names",
617620
"storageUnattributedDistributed": "Storage unattributed",
618621
"storageUnattributedDistributedDesc": "A type of project that gets created when cost management is unable to correlate a portion of the cloud cost to an OpenShift namespace",
619622
"suggestions": "Suggestions",
@@ -682,6 +685,7 @@
682685
"viewDocumentation": "View documentation",
683686
"viewLearningResources": "View all OpenShift learning resources",
684687
"viewReleaseNotes": "View release notes",
688+
"virtualMachine": "Virtual machine",
685689
"virtualization": "Virtualization",
686690
"volumeTitle": "Volume",
687691
"workerUnallocated": "Worker unallocated",

src/locales/messages.ts

+21
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ export default defineMessages({
215215
description: 'Cancel',
216216
id: 'cancel',
217217
},
218+
capacity: {
219+
defaultMessage: 'Capacity',
220+
description: 'Capacity',
221+
id: 'capacity',
222+
},
218223
chartCostForecastConeLabel: {
219224
defaultMessage: 'Cost confidence ({dateRange})',
220225
description: 'Cost confidence (Jan 1-31)',
@@ -1357,6 +1362,7 @@ export default defineMessages({
13571362
'status {Status} ' +
13581363
'subscription_guid {Account names} ' +
13591364
'source_type {Integration} ' +
1365+
'storage {Storage} ' +
13601366
'tag {Tag names} ' +
13611367
'tags {Tags} ' +
13621368
'tag_key {Tag keys} ' +
@@ -3738,6 +3744,16 @@ export default defineMessages({
37383744
description: 'StorageClass',
37393745
id: 'storageClass',
37403746
},
3747+
storageHeadingTitle: {
3748+
defaultMessage: 'Storage ({value})',
3749+
description: 'Storage ({value})',
3750+
id: 'storageHeadingTitle',
3751+
},
3752+
storageNames: {
3753+
defaultMessage: 'Storage names',
3754+
description: 'Storage names',
3755+
id: 'storageNames',
3756+
},
37413757
storageUnattributedDistributed: {
37423758
defaultMessage: 'Storage unattributed',
37433759
description: 'Storage unattributed',
@@ -4135,6 +4151,11 @@ export default defineMessages({
41354151
description: 'View release notes',
41364152
id: 'viewReleaseNotes',
41374153
},
4154+
virtualMachine: {
4155+
defaultMessage: 'Virtual machine',
4156+
description: 'Virtual machine',
4157+
id: 'virtualMachine',
4158+
},
41384159
virtualization: {
41394160
defaultMessage: 'Virtualization',
41404161
description: 'Virtualization',

src/routes/details/components/tag/modal/tagContent.styles.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export const styles = {
66
dataListHeading: {
77
fontWeight: global_FontWeight_bold.value as any,
88
},
9-
groupByHeading: {
9+
dataListSubHeading: {
1010
marginBottom: global_spacer_lg.value,
1111
},
1212
} as { [className: string]: React.CSSProperties };

src/routes/details/components/tag/modal/tagContent.tsx

+8-8
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ interface TagContentOwnProps {
1414
groupByValue: string | number;
1515
tagData?: TagData[];
1616
tagReport?: Tag;
17+
virtualMachine?: string;
1718
}
1819

1920
type TagContentProps = TagContentOwnProps & WrappedComponentProps;
@@ -49,19 +50,18 @@ class TagContentBase extends React.Component<TagContentProps, any> {
4950
};
5051

5152
public render() {
52-
const { groupBy, groupByValue, intl } = this.props;
53+
const { groupBy, groupByValue, intl, virtualMachine } = this.props;
5354
const dataListItems = this.getDataListItems();
5455

5556
return (
5657
<>
57-
<div>
58-
<span style={styles.dataListHeading}>
59-
{intl.formatMessage(messages.groupByValues, { value: groupBy, count: 1 })}
60-
</span>
61-
</div>
62-
<div style={styles.groupByHeading}>
63-
<span>{groupByValue}</span>
58+
<div style={styles.dataListHeading}>
59+
{intl.formatMessage(virtualMachine ? messages.virtualMachine : messages.groupByValuesTitleCase, {
60+
value: groupBy,
61+
count: 1,
62+
})}
6463
</div>
64+
<div style={styles.dataListSubHeading}>{virtualMachine ? virtualMachine : groupByValue}</div>
6565
<DataList aria-label={intl.formatMessage(messages.tagNames)} isCompact>
6666
<DataListItem aria-labelledby="heading1">
6767
<DataListItemRow>

src/routes/details/components/tag/modal/tagModal.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ interface TagModalOwnProps extends RouterComponentProps, WrappedComponentProps {
2525
onClose(isOpen: boolean);
2626
tagData?: TagData[];
2727
tagPathsType: TagPathsType;
28+
virtualMachine?: string;
2829
}
2930

3031
interface TagModalStateProps {
@@ -92,7 +93,7 @@ class TagModalBase extends React.Component<TagModalProps, any> {
9293
};
9394

9495
public render() {
95-
const { groupBy, intl, isOpen, query, tagData, tagReport } = this.props;
96+
const { groupBy, intl, isOpen, query, tagData, tagReport, virtualMachine } = this.props;
9697

9798
// Match page header description
9899
const groupByValue = query && query.filter && query.filter.account ? query.filter.account : this.props.groupByValue;
@@ -109,6 +110,7 @@ class TagModalBase extends React.Component<TagModalProps, any> {
109110
groupByValue={this.props.isPlatformCosts ? platformCategoryKey : groupByValue}
110111
tagData={tagData}
111112
tagReport={tagReport}
113+
virtualMachine={virtualMachine}
112114
/>
113115
</Modal>
114116
);

src/routes/details/components/tag/tagLink.tsx

+9-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ interface TagLinkOwnProps extends RouterComponentProps, WrappedComponentProps {
2424
id?: string;
2525
tagData?: TagData[];
2626
tagPathsType: TagPathsType;
27+
virtualMachine?: string;
2728
}
2829

2930
interface TagLinkState {
@@ -81,7 +82,7 @@ class TagLinkBase extends React.Component<TagLinkProps, TagLinkState> {
8182
};
8283

8384
public render() {
84-
const { id, tagData, tagReport, tagPathsType } = this.props;
85+
const { id, tagData, tagReport, tagPathsType, virtualMachine } = this.props;
8586
const { isOpen } = this.state;
8687

8788
let count = 0;
@@ -104,7 +105,13 @@ class TagLinkBase extends React.Component<TagLinkProps, TagLinkState> {
104105
<a data-testid="tag-lnk" href="#/" onClick={this.handleOpen} style={styles.tagLink}>
105106
{count}
106107
</a>
107-
<TagModal isOpen={isOpen} onClose={this.handleClose} tagData={tagData} tagPathsType={tagPathsType} />
108+
<TagModal
109+
isOpen={isOpen}
110+
onClose={this.handleClose}
111+
tagData={tagData}
112+
tagPathsType={tagPathsType}
113+
virtualMachine={virtualMachine}
114+
/>
108115
</div>
109116
);
110117
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as StorageLink } from './storageLink';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import global_FontWeight_bold from '@patternfly/react-tokens/dist/js/global_FontWeight_bold';
2+
import global_spacer_lg from '@patternfly/react-tokens/dist/js/global_spacer_lg';
3+
import type React from 'react';
4+
5+
export const styles = {
6+
dataListHeading: {
7+
fontWeight: global_FontWeight_bold.value as any,
8+
},
9+
dataListSubHeading: {
10+
marginBottom: global_spacer_lg.value,
11+
},
12+
} as { [className: string]: React.CSSProperties };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { DataList, DataListCell, DataListItem, DataListItemCells, DataListItemRow } from '@patternfly/react-core';
2+
import messages from 'locales/messages';
3+
import React from 'react';
4+
import type { WrappedComponentProps } from 'react-intl';
5+
import { injectIntl } from 'react-intl';
6+
import { connect } from 'react-redux';
7+
import type { StorageData } from 'routes/details/ocpBreakdown/virtualization/storage/storageLink';
8+
9+
import { styles } from './storageContent.styles';
10+
11+
interface StorageContentOwnProps {
12+
storageData?: StorageData[];
13+
virtualMachine?: string;
14+
}
15+
16+
type StorageContentProps = StorageContentOwnProps & WrappedComponentProps;
17+
18+
class StorageContentBase extends React.Component<StorageContentProps, any> {
19+
private getDataListItems = () => {
20+
const { storageData } = this.props;
21+
const result = [];
22+
23+
if (storageData) {
24+
Object.keys(storageData).map((key, i) => {
25+
const data = storageData[key];
26+
const id = `data-list-${i}`;
27+
result.push(
28+
<DataListItem aria-labelledby={id} key={`${id}-item`}>
29+
<DataListItemRow>
30+
<DataListItemCells
31+
dataListCells={[
32+
<DataListCell key={`${id}-cell1`}>
33+
<span id={id}>{data.pvc_name}</span>
34+
</DataListCell>,
35+
<DataListCell key={`${id}-cell2`}>{data.storage_class}</DataListCell>,
36+
<DataListCell key={`${id}-cell2`}>{data.usage}</DataListCell>,
37+
<DataListCell key={`${id}-cell2`}>{data.capacity}</DataListCell>,
38+
]}
39+
/>
40+
</DataListItemRow>
41+
</DataListItem>
42+
);
43+
});
44+
}
45+
return result;
46+
};
47+
48+
public render() {
49+
const { virtualMachine, intl } = this.props;
50+
const dataListItems = this.getDataListItems();
51+
52+
return (
53+
<>
54+
<div style={styles.dataListHeading}>{intl.formatMessage(messages.virtualMachine)}</div>
55+
<div style={styles.dataListSubHeading}>{virtualMachine}</div>
56+
<DataList aria-label={intl.formatMessage(messages.storage)} isCompact>
57+
<DataListItem aria-labelledby="heading1">
58+
<DataListItemRow>
59+
<DataListItemCells
60+
dataListCells={[
61+
<DataListCell key="primary content">
62+
<span id="heading1" style={styles.dataListHeading}>
63+
{intl.formatMessage(messages.storageNames)}
64+
</span>
65+
</DataListCell>,
66+
<DataListCell key="secondary content">
67+
<span id="heading2" style={styles.dataListHeading}>
68+
{intl.formatMessage(messages.storageClass)}
69+
</span>
70+
</DataListCell>,
71+
<DataListCell key="secondary content">
72+
<span id="heading2" style={styles.dataListHeading}>
73+
{intl.formatMessage(messages.usage)}
74+
</span>
75+
</DataListCell>,
76+
<DataListCell key="secondary content">
77+
<span id="heading2" style={styles.dataListHeading}>
78+
{intl.formatMessage(messages.capacity)}
79+
</span>
80+
</DataListCell>,
81+
]}
82+
/>
83+
</DataListItemRow>
84+
</DataListItem>
85+
{dataListItems.map(item => item)}
86+
</DataList>
87+
</>
88+
);
89+
}
90+
}
91+
92+
const StorageContent = injectIntl(connect()(StorageContentBase));
93+
94+
export { StorageContent };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import global_spacer_2xl from '@patternfly/react-tokens/dist/js/global_spacer_2xl';
2+
import type React from 'react';
3+
4+
export const styles = {
5+
subTitle: {
6+
marginTop: global_spacer_2xl.value,
7+
textAlign: 'right',
8+
},
9+
} as { [className: string]: React.CSSProperties };

0 commit comments

Comments
 (0)