Skip to content

Commit 9dfbcac

Browse files
authored
Merge pull request #3945 from dlabrecq/ec2
Wire up AWS EC2 API
2 parents 1ab1e6c + 63ab020 commit 9dfbcac

29 files changed

+127
-482
lines changed

src/api/reports/awsReports.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { axiosInstance } from 'api';
2-
import { default as devAxiosInstance } from 'api/apiDev';
32

43
import type { Report, ReportData, ReportItem, ReportItemValue, ReportMeta, ReportValue } from './report';
54
import { ReportType } from './report';
@@ -63,9 +62,9 @@ export const ReportTypePaths: Partial<Record<ReportType, string>> = {
6362
export function runReport(reportType: ReportType, query: string) {
6463
const path = ReportTypePaths[reportType];
6564

66-
// For use with API development
67-
if (reportType === ReportType.ec2Compute) {
68-
return devAxiosInstance.get<AwsReport>(`${path}?${query}`);
69-
}
65+
// For use with API development -- see 'api/apiDev'
66+
// if (reportType === ReportType.ec2Compute) {
67+
// return devAxiosInstance.get<AwsReport>(`${path}?${query}`);
68+
// }
7069
return axiosInstance.get<AwsReport>(`${path}?${query}`);
7170
}

src/api/resources/awsResource.ts

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { ResourceType } from './resource';
66
export const ResourceTypePaths: Partial<Record<ResourceType, string>> = {
77
[ResourceType.account]: 'resource-types/aws-accounts/',
88
[ResourceType.aws_category]: 'resource-types/aws-categories/',
9+
[ResourceType.aws_ec2_instance]: 'resource-types/aws-ec2-compute-instances/',
10+
[ResourceType.aws_ec2_os]: 'resource-types/aws-ec2-compute-os/',
911
[ResourceType.region]: 'resource-types/aws-regions/',
1012
[ResourceType.service]: 'resource-types/aws-services/',
1113
};

src/api/resources/resource.ts

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { PagedMetaData, PagedResponse } from 'api/api';
33
export interface ResourceData {
44
account_alias?: string;
55
cluster_alias?: string;
6+
instance_name?: string;
67
key?: string;
78
value?: string | string[];
89
}
@@ -13,6 +14,8 @@ export interface Resource extends PagedResponse<ResourceData, PagedMetaData> {}
1314
export const enum ResourceType {
1415
account = 'account',
1516
aws_category = 'aws_category',
17+
aws_ec2_instance = 'instance',
18+
aws_ec2_os = 'operating_system',
1619
cluster = 'cluster',
1720
gcpProject = 'gcp_project',
1821
node = 'node',

src/api/resources/resourceUtils.ts

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export function isResourceTypeValid(resourcePathsType: ResourcePathsType, resour
3232
switch (resourceType) {
3333
case ResourceType.account:
3434
case ResourceType.aws_category:
35+
case ResourceType.aws_ec2_instance:
36+
case ResourceType.aws_ec2_os:
3537
case ResourceType.cluster:
3638
case ResourceType.gcpProject:
3739
case ResourceType.node:

src/routes/components/dataToolbar/dataToolbar.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,9 @@ export class DataToolbarBase extends React.Component<DataToolbarProps, DataToolb
273273
key,
274274
});
275275

276+
if (!(filter && filters)) {
277+
return;
278+
}
276279
this.setState(
277280
{
278281
filters,

src/routes/components/dataToolbar/utils/category.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export const getCategoryInput = ({
5858
return (
5959
<ToolbarFilter
6060
categoryName={categoryOption}
61-
chips={getChips(filters[categoryOption.key] as Filter[])}
61+
chips={getChips(filters?.[categoryOption.key] as Filter[])}
6262
deleteChip={onDelete}
6363
key={categoryOption.key}
6464
showToolbarItem={currentCategory === categoryOption.key}
@@ -71,6 +71,7 @@ export const getCategoryInput = ({
7171
isDisabled={isDisabled && !_hasFilters}
7272
onSelect={value => onCategoryInputSelect(value, categoryOption.key)}
7373
placeholder={intl.formatMessage(messages.filterByPlaceholder, { value: placeholderKey })}
74+
resourceKey={categoryOption.resourceKey}
7475
resourcePathsType={resourcePathsType}
7576
resourceType={categoryOption.key as ResourceType}
7677
/>
@@ -124,12 +125,12 @@ export const onCategoryInput = ({
124125
key?: string;
125126
}) => {
126127
if (event && event.key && event.key !== 'Enter') {
127-
return {};
128+
return {}; // For destructure
128129
}
129130

130131
const val = cleanInput(categoryInput);
131132
if (val.trim() === '') {
132-
return {};
133+
return {}; // For destructure
133134
}
134135

135136
const isExcludes = currentExclude === ExcludeType.exclude;

src/routes/components/dataToolbar/utils/common.ts

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface Filters {
1313
export interface ToolbarChipGroupExt extends ToolbarChipGroup {
1414
ariaLabelKey?: string;
1515
placeholderKey?: string;
16+
resourceKey?: string;
1617
selectClassName?: string; // A selector from routes/components/dataToolbar/dataToolbar.scss
1718
selectOptions?: ToolbarChipGroup[];
1819
}

src/routes/components/dataToolbar/utils/orgUntits.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ export const getOrgUnitSelect = ({
3232
const selectOptions: SelectWrapperOption[] = getOrgUnitOptions(orgReport).map(option => ({
3333
description: option.key,
3434
compareTo: item =>
35-
filters[orgUnitIdKey] ? (filters[orgUnitIdKey] as any).find(filter => filter.value === item.value) : false,
35+
filters?.[orgUnitIdKey] ? (filters[orgUnitIdKey] as any).find(filter => filter.value === item.value) : false,
3636
toString: () => option.name,
3737
value: option.key,
3838
}));
3939

4040
const chips = []; // Get selected items as PatternFly's ToolbarChip type
4141
const selections = []; // Select options and selections must be same type
42-
if (filters[orgUnitIdKey] && Array.isArray(filters[orgUnitIdKey])) {
42+
if (filters?.[orgUnitIdKey] && Array.isArray(filters[orgUnitIdKey])) {
4343
(filters[orgUnitIdKey] as any).map(filter => {
4444
const selection = selectOptions.find(option => option.value === filter.value);
4545
if (selection) {

src/routes/components/dataToolbar/utils/tags.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ export const getTagValueSelect = ({
137137
return (
138138
<ToolbarFilter
139139
categoryName={categoryName}
140-
chips={getChips(filters.tag[tagKeyOption.key])}
140+
chips={getChips(filters?.tag?.[tagKeyOption.key])}
141141
deleteChip={onDelete}
142142
key={tagKeyOption.key}
143143
showToolbarItem={currentCategory === tagKey && currentTagKey === tagKeyOption.key}
@@ -147,7 +147,7 @@ export const getTagValueSelect = ({
147147
onTagValueSelect={onTagValueSelect}
148148
onTagValueInput={onTagValueInput}
149149
onTagValueInputChange={onTagValueInputChange}
150-
selections={filters.tag[tagKeyOption.key] ? filters.tag[tagKeyOption.key].map(filter => filter.value) : []}
150+
selections={filters?.tag?.[tagKeyOption.key] ? filters.tag[tagKeyOption.key].map(filter => filter.value) : []}
151151
tagKey={currentTagKey}
152152
tagKeyValue={tagKeyValueInput}
153153
tagPathsType={tagPathsType}

src/routes/components/export/exportModal.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
Radio,
1414
TextInput,
1515
} from '@patternfly/react-core';
16-
import type { ReportPathsType } from 'api/reports/report';
16+
import type { ReportPathsType, ReportType } from 'api/reports/report';
1717
import type { AxiosError } from 'axios';
1818
import { format } from 'date-fns';
1919
import messages from 'locales/messages';
@@ -35,10 +35,12 @@ export interface ExportModalOwnProps {
3535
groupBy?: string;
3636
isAllItems?: boolean;
3737
isOpen: boolean;
38+
isTimeScoped?: boolean;
3839
items?: ComputedReportItem[];
3940
onClose(isOpen: boolean);
4041
reportPathsType: ReportPathsType;
4142
reportQueryString: string;
43+
reportType: ReportType;
4244
resolution?: 'daily' | 'monthly'; // Default resolution
4345
showAggregateType?: boolean; // Monthly resolution filters are not valid with date range
4446
showFormatType?: boolean; // Format type; CVS / JSON
@@ -144,9 +146,11 @@ export class ExportModalBase extends React.Component<ExportModalProps, ExportMod
144146
intl,
145147
isAllItems,
146148
isExportsToggleEnabled,
149+
isTimeScoped,
147150
items,
148151
reportPathsType,
149152
reportQueryString,
153+
reportType,
150154
showAggregateType = true,
151155
showFormatType = true,
152156
showTimeScope = true,
@@ -200,6 +204,7 @@ export class ExportModalBase extends React.Component<ExportModalProps, ExportMod
200204
formatType={formatType}
201205
groupBy={groupBy}
202206
isAllItems={isAllItems}
207+
isTimeScoped={isTimeScoped}
203208
items={items}
204209
key="confirm"
205210
timeScope={showTimeScope ? timeScope : undefined}
@@ -208,6 +213,7 @@ export class ExportModalBase extends React.Component<ExportModalProps, ExportMod
208213
name={defaultName}
209214
reportPathsType={reportPathsType}
210215
reportQueryString={reportQueryString}
216+
reportType={reportType}
211217
resolution={resolution}
212218
/>,
213219
<Button ouiaId="cancel-btn" key="cancel" onClick={this.handleOnClose} variant={ButtonVariant.link}>

src/routes/components/export/exportSubmit.tsx

+22-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { Query } from 'api/queries/query';
44
import { parseQuery } from 'api/queries/query';
55
import { getQuery } from 'api/queries/query';
66
import type { ReportPathsType } from 'api/reports/report';
7-
import { ReportType } from 'api/reports/report';
7+
import type { ReportType } from 'api/reports/report';
88
import type { AxiosError } from 'axios';
99
import { endOfMonth, format, startOfMonth } from 'date-fns';
1010
import fileDownload from 'js-file-download';
@@ -29,11 +29,13 @@ export interface ExportSubmitOwnProps extends RouterComponentProps, WrappedCompo
2929
groupBy?: string;
3030
isAllItems?: boolean;
3131
items?: ComputedReportItem[];
32+
isTimeScoped?: boolean;
3233
name?: string;
3334
onClose(isOpen: boolean);
3435
onError(error: AxiosError);
3536
reportPathsType: ReportPathsType;
3637
reportQueryString: string;
38+
reportType: ReportType;
3739
resolution: string;
3840
timeScope: 'current' | 'previous';
3941
}
@@ -58,8 +60,6 @@ interface ExportSubmitState {
5860

5961
type ExportSubmitProps = ExportSubmitOwnProps & ExportSubmitDispatchProps & ExportSubmitStateProps;
6062

61-
const reportType = ReportType.cost;
62-
6363
export class ExportSubmitBase extends React.Component<ExportSubmitProps, ExportSubmitState> {
6464
protected defaultState: ExportSubmitState = {
6565
fetchExportClicked: false,
@@ -83,7 +83,7 @@ export class ExportSubmitBase extends React.Component<ExportSubmitProps, ExportS
8383
}
8484

8585
private fetchExport = () => {
86-
const { exportQueryString, fetchExport, isExportsToggleEnabled, reportPathsType } = this.props;
86+
const { exportQueryString, fetchExport, isExportsToggleEnabled, reportPathsType, reportType } = this.props;
8787

8888
fetchExport(reportPathsType, reportType, exportQueryString, isExportsToggleEnabled);
8989

@@ -149,14 +149,28 @@ export class ExportSubmitBase extends React.Component<ExportSubmitProps, ExportS
149149
}
150150

151151
const mapStateToProps = createMapStateToProps<ExportSubmitOwnProps, ExportSubmitStateProps>((state, props) => {
152-
const { groupBy, isAllItems, items, reportPathsType, reportQueryString, resolution, router, timeScope } = props;
152+
const {
153+
groupBy,
154+
isAllItems,
155+
isTimeScoped,
156+
items,
157+
reportPathsType,
158+
reportQueryString,
159+
reportType,
160+
resolution,
161+
router,
162+
timeScope,
163+
} = props;
153164

165+
const isPrevious = timeScope === 'previous';
154166
const queryFromRoute = parseQuery<Query>(router.location.search);
155167
const getDateRange = () => {
168+
if (isTimeScoped) {
169+
return {};
170+
}
156171
if (queryFromRoute.dateRangeType) {
157172
return getDateRangeFromQuery(queryFromRoute);
158173
} else {
159-
const isPrevious = timeScope === 'previous';
160174
const today = getToday();
161175

162176
if (isPrevious) {
@@ -180,9 +194,11 @@ const mapStateToProps = createMapStateToProps<ExportSubmitOwnProps, ExportSubmit
180194
limit: undefined, // Don't want paginated data
181195
offset: undefined, // Don't want a page
182196
resolution: resolution ? resolution : undefined, // Resolution is defined by export modal
197+
...(isTimeScoped && { time_scope_value: isPrevious ? -2 : -1 }),
183198
},
184199
filter_by: {}, // Don't want page filter, selected items will be filtered below
185200
limit: 0, // No limit to number of items returned
201+
offset: undefined,
186202
order_by: undefined, // Don't want items sorted by cost
187203
start_date,
188204
end_date,

src/routes/components/resourceTypeahead/resourceFetch.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface ResourceFetchOwnProps {
2323
onClear?: () => void;
2424
onSelect?: (value: string) => void;
2525
placeholder?: string;
26+
resourceKey?: string;
2627
resourcePathsType: ResourcePathsType;
2728
resourceType: ResourceType;
2829
search?: string;
@@ -50,6 +51,7 @@ const ResourceFetch: React.FC<ResourceFetchProps> = ({
5051
onClear,
5152
onSelect,
5253
placeholder,
54+
resourceKey,
5355
resourcePathsType,
5456
resourceType,
5557
search,
@@ -60,7 +62,8 @@ const ResourceFetch: React.FC<ResourceFetchProps> = ({
6062
let options = [];
6163
if (resource && resource.data && resource.data.length > 0 && resourceFetchStatus !== FetchStatus.inProgress) {
6264
options = resource.data.map(item => {
63-
const value = !isNaN(search as any) ? item.value : item.account_alias || item.cluster_alias || item.value;
65+
// The resource API typically returns just a value, but account_alias, cluster_alias, and instance_name may be preferred keys.
66+
const value = !isNaN(search as any) ? item.value : item[resourceKey] || item.value;
6467
return {
6568
key: value,
6669
name: value,

src/routes/components/resourceTypeahead/resourceTypeahead.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface ResourceTypeaheadOwnProps {
99
isDisabled?: boolean;
1010
onSelect?: (value: string) => void;
1111
placeholder?: string;
12+
resourceKey?: string;
1213
resourcePathsType: ResourcePathsType;
1314
resourceType: ResourceType;
1415
}
@@ -22,6 +23,7 @@ const ResourceTypeahead: React.FC<ResourceTypeaheadProps> = ({
2223
isDisabled,
2324
onSelect,
2425
placeholder,
26+
resourceKey,
2527
resourcePathsType,
2628
resourceType,
2729
}) => {
@@ -51,6 +53,7 @@ const ResourceTypeahead: React.FC<ResourceTypeaheadProps> = ({
5153
onChange={handleOnChange}
5254
onSelect={handleOnSelect}
5355
placeholder={placeholder}
56+
resourceKey={resourceKey}
5457
resourcePathsType={resourcePathsType}
5558
resourceType={resourceType}
5659
search={search}

0 commit comments

Comments
 (0)