@electrolux-oss/plugin-infrawallet 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -25
- package/dist/api/InfraWalletApi.esm.js.map +1 -1
- package/dist/api/InfraWalletApiClient.esm.js +12 -2
- package/dist/api/InfraWalletApiClient.esm.js.map +1 -1
- package/dist/api/functions.esm.js +33 -4
- package/dist/api/functions.esm.js.map +1 -1
- package/dist/components/ColumnsChartComponent/ColumnsChartComponent.esm.js +45 -28
- package/dist/components/ColumnsChartComponent/ColumnsChartComponent.esm.js.map +1 -1
- package/dist/components/CostReportsTableComponent/CostReportsTableComponent.esm.js +42 -37
- package/dist/components/CostReportsTableComponent/CostReportsTableComponent.esm.js.map +1 -1
- package/dist/components/ErrorsAlertComponent/ErrorsAlertComponent.esm.js +3 -2
- package/dist/components/ErrorsAlertComponent/ErrorsAlertComponent.esm.js.map +1 -1
- package/dist/components/FiltersComponent/FiltersComponent.esm.js +216 -10
- package/dist/components/FiltersComponent/FiltersComponent.esm.js.map +1 -1
- package/dist/components/MetricConfigurationComponent/MetricConfigurationComponent.esm.js +7 -0
- package/dist/components/MetricConfigurationComponent/MetricConfigurationComponent.esm.js.map +1 -1
- package/dist/components/ProviderIcons/ProviderIcons.esm.js +322 -0
- package/dist/components/ProviderIcons/ProviderIcons.esm.js.map +1 -0
- package/dist/components/ReportsComponent/ReportsComponent.esm.js +30 -15
- package/dist/components/ReportsComponent/ReportsComponent.esm.js.map +1 -1
- package/dist/components/TopbarComponent/TopbarComponent.esm.js +1 -1
- package/dist/components/TopbarComponent/TopbarComponent.esm.js.map +1 -1
- package/package.json +4 -6
- package/dist/components/CostReportsTableComponent/TrendBarComponent.esm.js +0 -43
- package/dist/components/CostReportsTableComponent/TrendBarComponent.esm.js.map +0 -1
package/README.md
CHANGED
|
@@ -24,36 +24,49 @@ query period. Add the following configurations to your `app-config.yaml` file if
|
|
|
24
24
|
# note that infraWallet exists at the root level, it is not the same one for backend configurations
|
|
25
25
|
infraWallet:
|
|
26
26
|
settings:
|
|
27
|
-
defaultGroupBy: none # none by default, or provider, category, service, tag:<tag_key>
|
|
27
|
+
defaultGroupBy: none # none by default, or account, provider, category, service, tag:<tag_key>
|
|
28
28
|
defaultShowLastXMonths: 3 # 3 by default, or other numbers, we recommend it less than 12
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
#### Customizing the InfraWalletPage Title and Subtitle
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
query period. Add the following configurations to your `app-config.yaml` file if the default view needs to be changed.
|
|
33
|
+
By default, the `InfraWalletPage` component is configured in the `packages/app/src/App.tsx` file as follows:
|
|
35
34
|
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
```ts
|
|
36
|
+
<Route path="/infrawallet" element={<InfraWalletPage />} />
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
To customize the title and subtitle of the InfraWalletPage, you can modify the route in the same file as shown below:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
<Route path="/infrawallet" element={<InfraWalletPage title="Custom title" subTitle="Custom subTitle" />} />
|
|
42
43
|
```
|
|
43
44
|
|
|
44
|
-
###
|
|
45
|
+
### Defining Provider Integrations
|
|
46
|
+
|
|
47
|
+
InfraWallet's configuration schema is specified in in [plugins/infrawallet-backend/config.d.ts](../infrawallet-backend/config.d.ts). To set up provider integrations, users must configure them in the `app-config.yaml` file located in the root directory.
|
|
48
|
+
|
|
49
|
+
#### AWS Integration
|
|
50
|
+
|
|
51
|
+
InfraWallet uses an IAM role to retrieve cost and usage data via the AWS Cost Explorer APIs. Before configuring InfraWallet, you must set up the necessary AWS IAM role and policy.
|
|
52
|
+
|
|
53
|
+
##### For Management Accounts
|
|
45
54
|
|
|
46
|
-
|
|
55
|
+
If you have a [management account](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_getting-started_concepts.html#management-account), this setup only needs to be done once within the management account. InfraWallet will then be able to retrieve cost data across all [member accounts](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_getting-started_concepts.html#member-account).
|
|
47
56
|
|
|
48
|
-
|
|
57
|
+
##### For Non-Management Accounts
|
|
49
58
|
|
|
50
|
-
|
|
59
|
+
If you're not using a [management account](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_getting-started_concepts.html#management-account), you'll need to create a role in each AWS account and configure trust relationships individually.
|
|
60
|
+
|
|
61
|
+
##### Required IAM Role Permissions
|
|
62
|
+
|
|
63
|
+
The IAM role must have the following permissions to access cost and usage data:
|
|
51
64
|
|
|
52
65
|
```json
|
|
53
66
|
{
|
|
54
67
|
"Statement": [
|
|
55
68
|
{
|
|
56
|
-
"Action": "ce:GetCostAndUsage",
|
|
69
|
+
"Action": ["ce:GetCostAndUsage", "ce:GetTags"],
|
|
57
70
|
"Effect": "Allow",
|
|
58
71
|
"Resource": "*",
|
|
59
72
|
"Sid": ""
|
|
@@ -63,37 +76,49 @@ For AWS, InfraWallet relies on an IAM role to fetch cost and usage data using AW
|
|
|
63
76
|
}
|
|
64
77
|
```
|
|
65
78
|
|
|
66
|
-
|
|
79
|
+
##### Configuration
|
|
80
|
+
|
|
81
|
+
Once the IAM roles and policies are in place, add the following configuration to your `app-config.yaml` file:
|
|
67
82
|
|
|
68
83
|
```yaml
|
|
69
84
|
backend:
|
|
70
85
|
infraWallet:
|
|
71
86
|
integrations:
|
|
72
87
|
aws:
|
|
73
|
-
- name: <
|
|
88
|
+
- name: <unique_name_of_this_integration>
|
|
74
89
|
accountId: '<12-digit_account_ID>' # quoted as a string
|
|
75
90
|
assumedRoleName: <name_of_the_AWS_IAM_role_to_be_assumed>
|
|
76
|
-
accessKeyId: <access_key_ID_of_AWS_IAM_user_that_assumes_the_role>
|
|
77
|
-
accessKeySecret: <access_key_secret_of_AWS_IAM_user_that_assumes_the_role>
|
|
91
|
+
accessKeyId: <access_key_ID_of_AWS_IAM_user_that_assumes_the_role> # optional, only needed when an IAM user is used to assume the role
|
|
92
|
+
accessKeySecret: <access_key_secret_of_AWS_IAM_user_that_assumes_the_role> # optional, only needed when an IAM user is used to assume the role
|
|
78
93
|
```
|
|
79
94
|
|
|
80
|
-
|
|
95
|
+
InfraWallet's AWS client is built using the AWS SDK for JavaScript. If both `accessKeyId` and `accessKeySecret` are provided in the configuration, the client will use the specified IAM user to assume the role. Otherwise, it follows the [default credential provider chain](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html#credchain).
|
|
96
|
+
|
|
97
|
+
#### Azure Integration
|
|
81
98
|
|
|
82
|
-
|
|
99
|
+
To manage Azure costs with InfraWallet, you need to register an application in Azure. Note that InfraWallet has been tested with subscription-level cost data only.
|
|
100
|
+
|
|
101
|
+
##### Steps:
|
|
102
|
+
|
|
103
|
+
1. After registering the application, navigate to the `Subscriptions` page and select the target subscription.
|
|
104
|
+
2. Go to the `Access control (IAM)` section and assign the `Cost Management Reader` role to the newly created application.
|
|
105
|
+
3. Generate a client secret for the application.
|
|
106
|
+
|
|
107
|
+
Add the following configurations to your `app-config.yaml` file:
|
|
83
108
|
|
|
84
109
|
```yaml
|
|
85
110
|
backend:
|
|
86
111
|
infraWallet:
|
|
87
112
|
integrations:
|
|
88
113
|
azure:
|
|
89
|
-
- name: <
|
|
114
|
+
- name: <unique_name_of_this_integration>
|
|
90
115
|
subscriptionId: <Azure_subscription_ID>
|
|
91
116
|
tenantId: <Azure_tenant_ID>
|
|
92
117
|
clientId: <Client_ID_of_the_created_application>
|
|
93
118
|
clientSecret: <Client_secret_of_the_created_application>
|
|
94
119
|
```
|
|
95
120
|
|
|
96
|
-
#### GCP
|
|
121
|
+
#### GCP Integration
|
|
97
122
|
|
|
98
123
|
InfraWallet relies on GCP Big Query to fetch cost data. This means that the billing data needs to be exported to a big query dataset, and a service account needs to be created for InfraWallet. The steps of exporting billing data to Big Query can be found [here](https://cloud.google.com/billing/docs/how-to/export-data-bigquery). Then, visit Google Cloud Console and navigate to the `IAM & Admin` section in the billing account. Click `Service Accounts`, and create a new service account. The service account needs to have `BigQuery Data Viewer` and `BigQuery Job User` roles. On the `Service Accounts` page, click the three dots (menu) in the `Actions` column for the newly created service account and select `Manage keys`. There click `Add key` -> `Create new key`, and use `JSON` as the format. Download the JSON key file and keep it safe.
|
|
99
124
|
|
|
@@ -104,16 +129,45 @@ backend:
|
|
|
104
129
|
infraWallet:
|
|
105
130
|
integrations:
|
|
106
131
|
gcp:
|
|
107
|
-
- name: <
|
|
132
|
+
- name: <unique_name_of_this_integration>
|
|
108
133
|
keyFilePath: <path_to_your_json_key_file> # if you run it in a k8s pod, you may need to create a secret and mount it to the pod
|
|
109
134
|
projectId: <GCP_project_that_your_big_query_dataset_belongs_to>
|
|
110
135
|
datasetId: <big_query_dataset_id>
|
|
111
136
|
tableId: <big_query_table_id>
|
|
112
137
|
```
|
|
113
138
|
|
|
139
|
+
#### Confluent Cloud Integration
|
|
140
|
+
|
|
141
|
+
To manage Confluent Cloud costs, you need to create an API key (Service account) for your Organization with the 'Cloud resource management' resource scope, you can find the documentation [here](https://docs.confluent.io/cloud/current/security/authenticate/workload-identities/service-accounts/api-keys/manage-api-keys.html#add-an-api-key). Once you have your API key details, add the following settings to `app-config.yaml`:
|
|
142
|
+
|
|
143
|
+
```yaml
|
|
144
|
+
backend:
|
|
145
|
+
infraWallet:
|
|
146
|
+
integrations:
|
|
147
|
+
confluent:
|
|
148
|
+
- name: <unique_name_of_this_integration>
|
|
149
|
+
apiKey: <your_api_key>
|
|
150
|
+
apiSecret: <your_api_key_secret>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### MongoDB Atlas Integration
|
|
154
|
+
|
|
155
|
+
To manage Mongo Atlas costs, you need to create an API key for your Organization with `Organization Billing Viewer` permission, you can find the documentation [here](https://www.mongodb.com/docs/atlas/configure-api-access/#std-label-about-org-api-keys). Once you have your API key details, add the following settings to `app-config.yaml`:
|
|
156
|
+
|
|
157
|
+
```yaml
|
|
158
|
+
backend:
|
|
159
|
+
infraWallet:
|
|
160
|
+
integrations:
|
|
161
|
+
mongoatlas:
|
|
162
|
+
- name: <unique_name_of_this_integration>
|
|
163
|
+
orgId: <id_organization_mongo_atlas>
|
|
164
|
+
publicKey: <public_key_of_your_api_key>
|
|
165
|
+
privateKey: <private_key_of_your_api_key>
|
|
166
|
+
```
|
|
167
|
+
|
|
114
168
|
### Adjust Category Mappings if Needed
|
|
115
169
|
|
|
116
|
-
The category mappings are stored in the plugin's database. If there is no mapping found in the DB when initializing the plugin, the default mappings will be used. The default mappings can be found in the [plugins/infrawallet-backend/seeds/init.js](
|
|
170
|
+
The category mappings are stored in the plugin's database. If there is no mapping found in the DB when initializing the plugin, the default mappings will be used. The default mappings can be found in the [plugins/infrawallet-backend/seeds/init.js](../infrawallet-backend/seeds/init.js) file. You can adjust this seed file to fit your needs, or update the database directly later on.
|
|
117
171
|
|
|
118
172
|
### Install the Plugin
|
|
119
173
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfraWalletApi.esm.js","sources":["../../src/api/InfraWalletApi.ts"],"sourcesContent":["import { createApiRef } from '@backstage/core-plugin-api';\nimport {\n CostReportsResponse,\n GetWalletResponse,\n MetricConfigsResponse,\n MetricSetting,\n MetricsResponse,\n MetricsSettingResponse,\n} from './types';\n\n/** @public */\nexport const infraWalletApiRef = createApiRef<InfraWalletApi>({\n id: 'plugin.infrawallet',\n});\n\n/** @public */\nexport interface InfraWalletApi {\n getCostReports(\n filters: string,\n groups: string,\n granularity: string,\n startTime: Date,\n endTime: Date,\n ): Promise<CostReportsResponse>;\n getMetrics(walletName: string, granularity: string, startTime: Date, endTime: Date): Promise<MetricsResponse>;\n getMetricConfigs(): Promise<MetricConfigsResponse>;\n getWalletMetricsSetting(walletName: string): Promise<MetricsSettingResponse>;\n updateWalletMetricSetting(\n walletName: string,\n metricSetting: MetricSetting,\n ): Promise<{ updated: boolean; status: number }>;\n deleteWalletMetricSetting(\n walletName: string,\n metricSetting: MetricSetting,\n ): Promise<{ deleted: boolean; status: number }>;\n getWalletByName(walletName: string): Promise<GetWalletResponse>;\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"InfraWalletApi.esm.js","sources":["../../src/api/InfraWalletApi.ts"],"sourcesContent":["import { createApiRef } from '@backstage/core-plugin-api';\nimport {\n CostReportsResponse,\n GetWalletResponse,\n MetricConfigsResponse,\n MetricSetting,\n MetricsResponse,\n MetricsSettingResponse,\n Tag,\n TagResponse,\n} from './types';\n\n/** @public */\nexport const infraWalletApiRef = createApiRef<InfraWalletApi>({\n id: 'plugin.infrawallet',\n});\n\n/** @public */\nexport interface InfraWalletApi {\n getCostReports(\n filters: string,\n tags: Tag[],\n groups: string,\n granularity: string,\n startTime: Date,\n endTime: Date,\n ): Promise<CostReportsResponse>;\n getTagKeys(provider: string, startTime: Date, endTime: Date): Promise<TagResponse>;\n getTagValues(tag: Tag, startTime: Date, endTime: Date): Promise<TagResponse>;\n getMetrics(walletName: string, granularity: string, startTime: Date, endTime: Date): Promise<MetricsResponse>;\n getMetricConfigs(): Promise<MetricConfigsResponse>;\n getWalletMetricsSetting(walletName: string): Promise<MetricsSettingResponse>;\n updateWalletMetricSetting(\n walletName: string,\n metricSetting: MetricSetting,\n ): Promise<{ updated: boolean; status: number }>;\n deleteWalletMetricSetting(\n walletName: string,\n metricSetting: MetricSetting,\n ): Promise<{ deleted: boolean; status: number }>;\n getWalletByName(walletName: string): Promise<GetWalletResponse>;\n}\n"],"names":[],"mappings":";;AAaO,MAAM,oBAAoB,YAA6B,CAAA;AAAA,EAC5D,EAAI,EAAA,oBAAA;AACN,CAAC;;;;"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fetch from 'node-fetch';
|
|
2
|
+
import { tagsToString } from './functions.esm.js';
|
|
2
3
|
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -35,8 +36,17 @@ class InfraWalletApiClient {
|
|
|
35
36
|
}
|
|
36
37
|
return await response.json();
|
|
37
38
|
}
|
|
38
|
-
async getCostReports(filters, groups, granularity, startTime, endTime) {
|
|
39
|
-
const
|
|
39
|
+
async getCostReports(filters, tags, groups, granularity, startTime, endTime) {
|
|
40
|
+
const tagsString = tagsToString(tags);
|
|
41
|
+
const url = `api/infrawallet/reports?&filters=${filters}&tags=${tagsString}&groups=${groups}&granularity=${granularity}&startTime=${startTime.getTime()}&endTime=${endTime.getTime()}`;
|
|
42
|
+
return await this.request(url);
|
|
43
|
+
}
|
|
44
|
+
async getTagKeys(provider, startTime, endTime) {
|
|
45
|
+
const url = `api/infrawallet/tag-keys?provider=${provider}&startTime=${startTime.getTime()}&endTime=${endTime.getTime()}`;
|
|
46
|
+
return await this.request(url);
|
|
47
|
+
}
|
|
48
|
+
async getTagValues(tag, startTime, endTime) {
|
|
49
|
+
const url = `api/infrawallet/tag-values?provider=${tag.provider}&tag=${tag.key}&startTime=${startTime.getTime()}&endTime=${endTime.getTime()}`;
|
|
40
50
|
return await this.request(url);
|
|
41
51
|
}
|
|
42
52
|
async getWalletByName(walletName) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfraWalletApiClient.esm.js","sources":["../../src/api/InfraWalletApiClient.ts"],"sourcesContent":["import { ConfigApi, IdentityApi } from '@backstage/core-plugin-api';\nimport fetch from 'node-fetch';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport {\n CostReportsResponse,\n GetWalletResponse,\n MetricConfigsResponse,\n MetricSetting,\n MetricsResponse,\n MetricsSettingResponse,\n} from './types';\n\n/** @public */\nexport class InfraWalletApiClient implements InfraWalletApi {\n private readonly identityApi: IdentityApi;\n private readonly backendUrl: string;\n\n constructor(options: { identityApi: IdentityApi; configApi: ConfigApi }) {\n this.identityApi = options.identityApi;\n this.backendUrl = options.configApi.getString('backend.baseUrl');\n }\n\n async request(path: string, method?: string, payload?: Record<string, string | undefined>) {\n const url = `${this.backendUrl}/${path}`;\n const { token: idToken } = await this.identityApi.getCredentials();\n const headers: Record<string, string> = idToken ? { Authorization: `Bearer ${idToken}` } : {};\n\n if (method !== undefined && method !== 'GET') {\n headers['Content-Type'] = 'application/json';\n }\n\n const request: any = {\n headers: headers,\n method: method ?? 'GET',\n };\n\n if (payload) {\n request.body = JSON.stringify(payload);\n }\n\n const response = await fetch(url, request);\n\n if (!response.ok) {\n const res = await response.text();\n const message = `Request failed with ${response.status} ${response.statusText}, ${res}`;\n throw new Error(message);\n }\n\n return await response.json();\n }\n\n async getCostReports(\n filters: string,\n groups: string,\n granularity: string,\n startTime: Date,\n endTime: Date,\n ): Promise<CostReportsResponse> {\n const url = `api/infrawallet/reports?&filters=${filters}&groups=${groups}&granularity=${granularity}&startTime=${startTime.getTime()}&endTime=${endTime.getTime()}`;\n return await this.request(url);\n }\n\n async getWalletByName(walletName: string): Promise<GetWalletResponse> {\n const url = `api/infrawallet/${walletName}`;\n return await this.request(url);\n }\n\n async getMetrics(walletName: string, granularity: string, startTime: Date, endTime: Date): Promise<MetricsResponse> {\n const url = `api/infrawallet/${walletName}/metrics?&granularity=${granularity}&startTime=${startTime.getTime()}&endTime=${endTime.getTime()}`;\n return await this.request(url);\n }\n\n async getMetricConfigs(): Promise<MetricConfigsResponse> {\n const url = 'api/infrawallet/metric/metric_configs';\n return await this.request(url);\n }\n\n async getWalletMetricsSetting(walletName: string): Promise<MetricsSettingResponse> {\n const url = `api/infrawallet/${walletName}/metrics_setting`;\n return await this.request(url);\n }\n async updateWalletMetricSetting(\n walletName: string,\n metricSetting: MetricSetting,\n ): Promise<{ updated: boolean; status: number }> {\n const url = `api/infrawallet/${walletName}/metrics_setting`;\n return await this.request(url, 'PUT', metricSetting);\n }\n\n async deleteWalletMetricSetting(\n walletName: string,\n metricSetting: MetricSetting,\n ): Promise<{ deleted: boolean; status: number }> {\n const url = `api/infrawallet/${walletName}/metrics_setting`;\n return await this.request(url, 'DELETE', metricSetting);\n }\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"InfraWalletApiClient.esm.js","sources":["../../src/api/InfraWalletApiClient.ts"],"sourcesContent":["import { ConfigApi, IdentityApi } from '@backstage/core-plugin-api';\nimport fetch from 'node-fetch';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport {\n CostReportsResponse,\n GetWalletResponse,\n MetricConfigsResponse,\n MetricSetting,\n MetricsResponse,\n MetricsSettingResponse,\n Tag,\n TagResponse,\n} from './types';\nimport { tagsToString } from './functions';\n\n/** @public */\nexport class InfraWalletApiClient implements InfraWalletApi {\n private readonly identityApi: IdentityApi;\n private readonly backendUrl: string;\n\n constructor(options: { identityApi: IdentityApi; configApi: ConfigApi }) {\n this.identityApi = options.identityApi;\n this.backendUrl = options.configApi.getString('backend.baseUrl');\n }\n\n async request(path: string, method?: string, payload?: Record<string, string | undefined>) {\n const url = `${this.backendUrl}/${path}`;\n const { token: idToken } = await this.identityApi.getCredentials();\n const headers: Record<string, string> = idToken ? { Authorization: `Bearer ${idToken}` } : {};\n\n if (method !== undefined && method !== 'GET') {\n headers['Content-Type'] = 'application/json';\n }\n\n const request: any = {\n headers: headers,\n method: method ?? 'GET',\n };\n\n if (payload) {\n request.body = JSON.stringify(payload);\n }\n\n const response = await fetch(url, request);\n\n if (!response.ok) {\n const res = await response.text();\n const message = `Request failed with ${response.status} ${response.statusText}, ${res}`;\n throw new Error(message);\n }\n\n return await response.json();\n }\n\n async getCostReports(\n filters: string,\n tags: Tag[],\n groups: string,\n granularity: string,\n startTime: Date,\n endTime: Date,\n ): Promise<CostReportsResponse> {\n const tagsString = tagsToString(tags);\n const url = `api/infrawallet/reports?&filters=${filters}&tags=${tagsString}&groups=${groups}&granularity=${granularity}&startTime=${startTime.getTime()}&endTime=${endTime.getTime()}`;\n return await this.request(url);\n }\n\n async getTagKeys(provider: string, startTime: Date, endTime: Date): Promise<TagResponse> {\n const url = `api/infrawallet/tag-keys?provider=${provider}&startTime=${startTime.getTime()}&endTime=${endTime.getTime()}`;\n return await this.request(url);\n }\n\n async getTagValues(tag: Tag, startTime: Date, endTime: Date): Promise<TagResponse> {\n const url = `api/infrawallet/tag-values?provider=${tag.provider}&tag=${\n tag.key\n }&startTime=${startTime.getTime()}&endTime=${endTime.getTime()}`;\n return await this.request(url);\n }\n\n async getWalletByName(walletName: string): Promise<GetWalletResponse> {\n const url = `api/infrawallet/${walletName}`;\n return await this.request(url);\n }\n\n async getMetrics(walletName: string, granularity: string, startTime: Date, endTime: Date): Promise<MetricsResponse> {\n const url = `api/infrawallet/${walletName}/metrics?&granularity=${granularity}&startTime=${startTime.getTime()}&endTime=${endTime.getTime()}`;\n return await this.request(url);\n }\n\n async getMetricConfigs(): Promise<MetricConfigsResponse> {\n const url = 'api/infrawallet/metric/metric_configs';\n return await this.request(url);\n }\n\n async getWalletMetricsSetting(walletName: string): Promise<MetricsSettingResponse> {\n const url = `api/infrawallet/${walletName}/metrics_setting`;\n return await this.request(url);\n }\n async updateWalletMetricSetting(\n walletName: string,\n metricSetting: MetricSetting,\n ): Promise<{ updated: boolean; status: number }> {\n const url = `api/infrawallet/${walletName}/metrics_setting`;\n return await this.request(url, 'PUT', metricSetting);\n }\n\n async deleteWalletMetricSetting(\n walletName: string,\n metricSetting: MetricSetting,\n ): Promise<{ deleted: boolean; status: number }> {\n const url = `api/infrawallet/${walletName}/metrics_setting`;\n return await this.request(url, 'DELETE', metricSetting);\n }\n}\n"],"names":[],"mappings":";;;;;;;;;AAgBO,MAAM,oBAA+C,CAAA;AAAA,EAI1D,YAAY,OAA6D,EAAA;AAHzE,IAAiB,aAAA,CAAA,IAAA,EAAA,aAAA,CAAA,CAAA;AACjB,IAAiB,aAAA,CAAA,IAAA,EAAA,YAAA,CAAA,CAAA;AAGf,IAAA,IAAA,CAAK,cAAc,OAAQ,CAAA,WAAA,CAAA;AAC3B,IAAA,IAAA,CAAK,UAAa,GAAA,OAAA,CAAQ,SAAU,CAAA,SAAA,CAAU,iBAAiB,CAAA,CAAA;AAAA,GACjE;AAAA,EAEA,MAAM,OAAA,CAAQ,IAAc,EAAA,MAAA,EAAiB,OAA8C,EAAA;AACzF,IAAA,MAAM,GAAM,GAAA,CAAA,EAAG,IAAK,CAAA,UAAU,IAAI,IAAI,CAAA,CAAA,CAAA;AACtC,IAAA,MAAM,EAAE,KAAO,EAAA,OAAA,KAAY,MAAM,IAAA,CAAK,YAAY,cAAe,EAAA,CAAA;AACjE,IAAM,MAAA,OAAA,GAAkC,UAAU,EAAE,aAAA,EAAe,UAAU,OAAO,CAAA,CAAA,KAAO,EAAC,CAAA;AAE5F,IAAI,IAAA,MAAA,KAAW,KAAa,CAAA,IAAA,MAAA,KAAW,KAAO,EAAA;AAC5C,MAAA,OAAA,CAAQ,cAAc,CAAI,GAAA,kBAAA,CAAA;AAAA,KAC5B;AAEA,IAAA,MAAM,OAAe,GAAA;AAAA,MACnB,OAAA;AAAA,MACA,QAAQ,MAAU,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA;AAAA,KACpB,CAAA;AAEA,IAAA,IAAI,OAAS,EAAA;AACX,MAAQ,OAAA,CAAA,IAAA,GAAO,IAAK,CAAA,SAAA,CAAU,OAAO,CAAA,CAAA;AAAA,KACvC;AAEA,IAAA,MAAM,QAAW,GAAA,MAAM,KAAM,CAAA,GAAA,EAAK,OAAO,CAAA,CAAA;AAEzC,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,GAAA,GAAM,MAAM,QAAA,CAAS,IAAK,EAAA,CAAA;AAChC,MAAM,MAAA,OAAA,GAAU,uBAAuB,QAAS,CAAA,MAAM,IAAI,QAAS,CAAA,UAAU,KAAK,GAAG,CAAA,CAAA,CAAA;AACrF,MAAM,MAAA,IAAI,MAAM,OAAO,CAAA,CAAA;AAAA,KACzB;AAEA,IAAO,OAAA,MAAM,SAAS,IAAK,EAAA,CAAA;AAAA,GAC7B;AAAA,EAEA,MAAM,cACJ,CAAA,OAAA,EACA,MACA,MACA,EAAA,WAAA,EACA,WACA,OAC8B,EAAA;AAC9B,IAAM,MAAA,UAAA,GAAa,aAAa,IAAI,CAAA,CAAA;AACpC,IAAA,MAAM,MAAM,CAAoC,iCAAA,EAAA,OAAO,CAAS,MAAA,EAAA,UAAU,WAAW,MAAM,CAAA,aAAA,EAAgB,WAAW,CAAA,WAAA,EAAc,UAAU,OAAQ,EAAC,CAAY,SAAA,EAAA,OAAA,CAAQ,SAAS,CAAA,CAAA,CAAA;AACpL,IAAO,OAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,GAAG,CAAA,CAAA;AAAA,GAC/B;AAAA,EAEA,MAAM,UAAA,CAAW,QAAkB,EAAA,SAAA,EAAiB,OAAqC,EAAA;AACvF,IAAM,MAAA,GAAA,GAAM,CAAqC,kCAAA,EAAA,QAAQ,CAAc,WAAA,EAAA,SAAA,CAAU,SAAS,CAAA,SAAA,EAAY,OAAQ,CAAA,OAAA,EAAS,CAAA,CAAA,CAAA;AACvH,IAAO,OAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,GAAG,CAAA,CAAA;AAAA,GAC/B;AAAA,EAEA,MAAM,YAAA,CAAa,GAAU,EAAA,SAAA,EAAiB,OAAqC,EAAA;AACjF,IAAA,MAAM,GAAM,GAAA,CAAA,oCAAA,EAAuC,GAAI,CAAA,QAAQ,QAC7D,GAAI,CAAA,GACN,CAAc,WAAA,EAAA,SAAA,CAAU,OAAQ,EAAC,CAAY,SAAA,EAAA,OAAA,CAAQ,SAAS,CAAA,CAAA,CAAA;AAC9D,IAAO,OAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,GAAG,CAAA,CAAA;AAAA,GAC/B;AAAA,EAEA,MAAM,gBAAgB,UAAgD,EAAA;AACpE,IAAM,MAAA,GAAA,GAAM,mBAAmB,UAAU,CAAA,CAAA,CAAA;AACzC,IAAO,OAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,GAAG,CAAA,CAAA;AAAA,GAC/B;AAAA,EAEA,MAAM,UAAA,CAAW,UAAoB,EAAA,WAAA,EAAqB,WAAiB,OAAyC,EAAA;AAClH,IAAA,MAAM,GAAM,GAAA,CAAA,gBAAA,EAAmB,UAAU,CAAA,sBAAA,EAAyB,WAAW,CAAA,WAAA,EAAc,SAAU,CAAA,OAAA,EAAS,CAAA,SAAA,EAAY,OAAQ,CAAA,OAAA,EAAS,CAAA,CAAA,CAAA;AAC3I,IAAO,OAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,GAAG,CAAA,CAAA;AAAA,GAC/B;AAAA,EAEA,MAAM,gBAAmD,GAAA;AACvD,IAAA,MAAM,GAAM,GAAA,uCAAA,CAAA;AACZ,IAAO,OAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,GAAG,CAAA,CAAA;AAAA,GAC/B;AAAA,EAEA,MAAM,wBAAwB,UAAqD,EAAA;AACjF,IAAM,MAAA,GAAA,GAAM,mBAAmB,UAAU,CAAA,gBAAA,CAAA,CAAA;AACzC,IAAO,OAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,GAAG,CAAA,CAAA;AAAA,GAC/B;AAAA,EACA,MAAM,yBACJ,CAAA,UAAA,EACA,aAC+C,EAAA;AAC/C,IAAM,MAAA,GAAA,GAAM,mBAAmB,UAAU,CAAA,gBAAA,CAAA,CAAA;AACzC,IAAA,OAAO,MAAM,IAAA,CAAK,OAAQ,CAAA,GAAA,EAAK,OAAO,aAAa,CAAA,CAAA;AAAA,GACrD;AAAA,EAEA,MAAM,yBACJ,CAAA,UAAA,EACA,aAC+C,EAAA;AAC/C,IAAM,MAAA,GAAA,GAAM,mBAAmB,UAAU,CAAA,gBAAA,CAAA,CAAA;AACzC,IAAA,OAAO,MAAM,IAAA,CAAK,OAAQ,CAAA,GAAA,EAAK,UAAU,aAAa,CAAA,CAAA;AAAA,GACxD;AACF;;;;"}
|
|
@@ -64,6 +64,7 @@ const aggregateCostReports = (reports, aggregatedBy) => {
|
|
|
64
64
|
if (!accumulator[keyName]) {
|
|
65
65
|
accumulator[keyName] = {
|
|
66
66
|
id: keyName,
|
|
67
|
+
provider: report.provider,
|
|
67
68
|
reports: {}
|
|
68
69
|
};
|
|
69
70
|
if (aggregatedBy !== void 0) {
|
|
@@ -91,9 +92,8 @@ const getReportKeyAndValues = (reports) => {
|
|
|
91
92
|
if (!excludedKeys.includes(key)) {
|
|
92
93
|
if (keyValueSets[key] === void 0) {
|
|
93
94
|
keyValueSets[key] = /* @__PURE__ */ new Set();
|
|
94
|
-
} else {
|
|
95
|
-
keyValueSets[key].add(report[key]);
|
|
96
95
|
}
|
|
96
|
+
keyValueSets[key].add(report[key]);
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
99
|
});
|
|
@@ -103,9 +103,38 @@ const getReportKeyAndValues = (reports) => {
|
|
|
103
103
|
});
|
|
104
104
|
return keyValues;
|
|
105
105
|
};
|
|
106
|
+
const extractProvider = (input) => {
|
|
107
|
+
let provider = void 0;
|
|
108
|
+
if (input && input.indexOf("/") !== -1) {
|
|
109
|
+
provider = input.split("/")[0];
|
|
110
|
+
}
|
|
111
|
+
return provider;
|
|
112
|
+
};
|
|
113
|
+
const extractAccountInfo = (input) => {
|
|
114
|
+
const regex = /^(.*?)\s*\(([^)]+)\)$/;
|
|
115
|
+
const match = input.match(regex);
|
|
116
|
+
if (match) {
|
|
117
|
+
const accountName = match[1];
|
|
118
|
+
const accountId = match[2];
|
|
119
|
+
return { accountName, accountId };
|
|
120
|
+
}
|
|
121
|
+
return { accountName: input };
|
|
122
|
+
};
|
|
123
|
+
function tagExists(tags, targetTag) {
|
|
124
|
+
return tags.some(
|
|
125
|
+
(tag) => tag.provider === targetTag.provider && tag.key === targetTag.key && tag.value === targetTag.value
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const tagsToString = (tags) => {
|
|
129
|
+
if (tags.length === 0) {
|
|
130
|
+
return "()";
|
|
131
|
+
}
|
|
132
|
+
const keyValuePairs = tags.map((tag) => `${tag.provider}:${tag.key}=${tag.value}`);
|
|
133
|
+
return `(${keyValuePairs.join(" OR ")})`;
|
|
134
|
+
};
|
|
106
135
|
const getAllReportTags = (reports) => {
|
|
107
136
|
const tags = /* @__PURE__ */ new Set();
|
|
108
|
-
const reservedKeys = ["id", "
|
|
137
|
+
const reservedKeys = ["id", "account", "service", "category", "provider", "reports"];
|
|
109
138
|
reports.forEach((report) => {
|
|
110
139
|
Object.keys(report).forEach((key) => {
|
|
111
140
|
if (reservedKeys.indexOf(key) === -1) {
|
|
@@ -135,5 +164,5 @@ const getPeriodStrings = (granularity, startTime, endTime) => {
|
|
|
135
164
|
return result;
|
|
136
165
|
};
|
|
137
166
|
|
|
138
|
-
export { aggregateCostReports, filterCostReports, getAllReportTags, getPeriodStrings, getPreviousMonth, getReportKeyAndValues, mergeCostReports };
|
|
167
|
+
export { aggregateCostReports, extractAccountInfo, extractProvider, filterCostReports, getAllReportTags, getPeriodStrings, getPreviousMonth, getReportKeyAndValues, mergeCostReports, tagExists, tagsToString };
|
|
139
168
|
//# sourceMappingURL=functions.esm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"functions.esm.js","sources":["../../src/api/functions.ts"],"sourcesContent":["import { format, parse, subMonths } from 'date-fns';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { Report, Filters } from './types';\n\nexport const mergeCostReports = (reports: Report[], threshold: number): Report[] => {\n const totalCosts: { id: string; total: number }[] = [];\n reports.forEach(report => {\n let total = 0;\n Object.values(report.reports).forEach(v => {\n total += v as number;\n });\n totalCosts.push({ id: report.id, total: total });\n });\n const sortedTotalCosts = totalCosts.sort((a, b) => b.total - a.total);\n const idsToBeKept = sortedTotalCosts.slice(0, threshold).map(v => v.id);\n\n const mergedReports = reduce(\n reports,\n (accumulator: { [key: string]: Report }, report) => {\n let keyName = 'others';\n if (idsToBeKept.includes(report.id)) {\n keyName = report.id;\n }\n if (!accumulator[keyName]) {\n accumulator[keyName] = {\n id: keyName,\n reports: {},\n };\n }\n\n Object.keys(report.reports).forEach(key => {\n if (accumulator[keyName].reports[key]) {\n accumulator[keyName].reports[key] += report.reports[key];\n } else {\n accumulator[keyName].reports[key] = report.reports[key];\n }\n });\n return accumulator;\n },\n {},\n );\n\n return Object.values(mergedReports);\n};\n\nexport const filterCostReports = (reports: Report[], filters: Filters): Report[] => {\n const filteredReports = reports.filter(report => {\n let match = true;\n Object.keys(filters).forEach(key => {\n if (filters[key].length > 0 && !filters[key].includes(report[key] as string)) {\n match = false;\n }\n });\n return match;\n });\n\n return filteredReports;\n};\n\nexport const aggregateCostReports = (reports: Report[], aggregatedBy?: string): Report[] => {\n const aggregatedReports: { [key: string]: Report } = reduce(\n reports,\n (accumulator, report) => {\n let keyName: string = 'no value';\n if (aggregatedBy && aggregatedBy in report) {\n keyName = report[aggregatedBy] as string;\n } else if (aggregatedBy === 'none') {\n keyName = 'Total';\n }\n\n if (!accumulator[keyName]) {\n accumulator[keyName] = {\n id: keyName,\n reports: {},\n } as {\n id: string;\n reports: { [key: string]: number };\n [key: string]: any;\n };\n\n if (aggregatedBy !== undefined) {\n accumulator[keyName][aggregatedBy] = keyName;\n }\n }\n\n Object.keys(report.reports).forEach(key => {\n if (accumulator[keyName].reports[key]) {\n accumulator[keyName].reports[key] += report.reports[key];\n } else {\n accumulator[keyName].reports[key] = report.reports[key];\n }\n });\n return accumulator;\n },\n {} as { [key: string]: Report },\n );\n return Object.values(aggregatedReports);\n};\n\nexport const getReportKeyAndValues = (reports: Report[]): { [key: string]: string[] } => {\n const excludedKeys = ['id', 'reports'];\n const keyValueSets: { [key: string]: Set<string> } = {};\n reports.forEach(report => {\n Object.keys(report).forEach(key => {\n if (!excludedKeys.includes(key)) {\n if (keyValueSets[key] === undefined) {\n keyValueSets[key] = new Set<string>();\n } else {\n keyValueSets[key].add(report[key] as string);\n }\n }\n });\n });\n\n const keyValues: { [key: string]: string[] } = {};\n Object.keys(keyValueSets).forEach((key: string) => {\n keyValues[key] = Array.from(keyValueSets[key]);\n });\n return keyValues;\n};\n\nexport const getAllReportTags = (reports: Report[]): string[] => {\n const tags = new Set<string>();\n const reservedKeys = ['id', 'name', 'service', 'category', 'provider', 'reports'];\n reports.forEach(report => {\n Object.keys(report).forEach(key => {\n if (reservedKeys.indexOf(key) === -1) {\n tags.add(key);\n }\n });\n });\n return Array.from(tags);\n};\n\nexport const getPreviousMonth = (month: string): string => {\n const date = parse(month, 'yyyy-MM', new Date());\n const previousMonth = subMonths(date, 1);\n return format(previousMonth, 'yyyy-MM');\n};\n\nexport const getPeriodStrings = (granularity: string, startTime: Date, endTime: Date): string[] => {\n const result: string[] = [];\n const current = moment(startTime);\n\n while (current.isSameOrBefore(endTime) && current.isSameOrBefore(moment())) {\n if (granularity === 'monthly') {\n result.push(current.format('YYYY-MM'));\n current.add(1, 'months');\n } else {\n result.push(current.format('YYYY-MM-DD'));\n current.add(1, 'days');\n }\n }\n\n return result;\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"functions.esm.js","sources":["../../src/api/functions.ts"],"sourcesContent":["import { format, parse, subMonths } from 'date-fns';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { Report, Filters, Tag } from './types';\n\nexport const mergeCostReports = (reports: Report[], threshold: number): Report[] => {\n const totalCosts: { id: string; total: number }[] = [];\n reports.forEach(report => {\n let total = 0;\n Object.values(report.reports).forEach(v => {\n total += v as number;\n });\n totalCosts.push({ id: report.id, total: total });\n });\n const sortedTotalCosts = totalCosts.sort((a, b) => b.total - a.total);\n const idsToBeKept = sortedTotalCosts.slice(0, threshold).map(v => v.id);\n\n const mergedReports = reduce(\n reports,\n (accumulator: { [key: string]: Report }, report) => {\n let keyName = 'others';\n if (idsToBeKept.includes(report.id)) {\n keyName = report.id;\n }\n if (!accumulator[keyName]) {\n accumulator[keyName] = {\n id: keyName,\n reports: {},\n };\n }\n\n Object.keys(report.reports).forEach(key => {\n if (accumulator[keyName].reports[key]) {\n accumulator[keyName].reports[key] += report.reports[key];\n } else {\n accumulator[keyName].reports[key] = report.reports[key];\n }\n });\n return accumulator;\n },\n {},\n );\n\n return Object.values(mergedReports);\n};\n\nexport const filterCostReports = (reports: Report[], filters: Filters): Report[] => {\n const filteredReports = reports.filter(report => {\n let match = true;\n Object.keys(filters).forEach(key => {\n if (filters[key].length > 0 && !filters[key].includes(report[key] as string)) {\n match = false;\n }\n });\n return match;\n });\n\n return filteredReports;\n};\n\nexport const aggregateCostReports = (reports: Report[], aggregatedBy?: string): Report[] => {\n const aggregatedReports: { [key: string]: Report } = reduce(\n reports,\n (accumulator, report) => {\n let keyName: string = 'no value';\n if (aggregatedBy && aggregatedBy in report) {\n keyName = report[aggregatedBy] as string;\n } else if (aggregatedBy === 'none') {\n keyName = 'Total';\n }\n\n if (!accumulator[keyName]) {\n accumulator[keyName] = {\n id: keyName,\n provider: report.provider,\n reports: {},\n } as {\n id: string;\n reports: { [key: string]: number };\n [key: string]: any;\n };\n\n if (aggregatedBy !== undefined) {\n accumulator[keyName][aggregatedBy] = keyName;\n }\n }\n\n Object.keys(report.reports).forEach(key => {\n if (accumulator[keyName].reports[key]) {\n accumulator[keyName].reports[key] += report.reports[key];\n } else {\n accumulator[keyName].reports[key] = report.reports[key];\n }\n });\n return accumulator;\n },\n {} as { [key: string]: Report },\n );\n return Object.values(aggregatedReports);\n};\n\nexport const getReportKeyAndValues = (reports: Report[]): { [key: string]: string[] } => {\n const excludedKeys = ['id', 'reports'];\n const keyValueSets: { [key: string]: Set<string> } = {};\n reports.forEach(report => {\n Object.keys(report).forEach(key => {\n if (!excludedKeys.includes(key)) {\n if (keyValueSets[key] === undefined) {\n keyValueSets[key] = new Set<string>();\n }\n\n keyValueSets[key].add(report[key] as string);\n }\n });\n });\n\n const keyValues: { [key: string]: string[] } = {};\n Object.keys(keyValueSets).forEach((key: string) => {\n keyValues[key] = Array.from(keyValueSets[key]);\n });\n return keyValues;\n};\n\nexport const extractProvider = (input: string): string | undefined => {\n let provider = undefined;\n if (input && input.indexOf('/') !== -1) {\n provider = input.split('/')[0];\n }\n\n return provider;\n};\n\nexport const extractAccountInfo = (input: string): { accountName: string; accountId?: string } => {\n // try to match format: accountName (accountId), e.g. aws-dev (123456789012)\n const regex = /^(.*?)\\s*\\(([^)]+)\\)$/;\n const match = input.match(regex);\n\n if (match) {\n const accountName = match[1];\n const accountId = match[2];\n return { accountName: accountName, accountId: accountId };\n }\n\n return { accountName: input };\n};\n\n// check if targetTag exists in tags\nexport function tagExists(tags: Tag[], targetTag: Tag): boolean {\n return tags.some(\n tag => tag.provider === targetTag.provider && tag.key === targetTag.key && tag.value === targetTag.value,\n );\n}\n\n// convert Tag array to (provider1:key1=value1 OR provider2:key2=value2) format\nexport const tagsToString = (tags: Tag[]): string => {\n if (tags.length === 0) {\n return '()';\n }\n\n const keyValuePairs = tags.map(tag => `${tag.provider}:${tag.key}=${tag.value}`);\n return `(${keyValuePairs.join(' OR ')})`;\n};\n\nexport const getAllReportTags = (reports: Report[]): string[] => {\n const tags = new Set<string>();\n const reservedKeys = ['id', 'account', 'service', 'category', 'provider', 'reports'];\n reports.forEach(report => {\n Object.keys(report).forEach(key => {\n if (reservedKeys.indexOf(key) === -1) {\n tags.add(key);\n }\n });\n });\n return Array.from(tags);\n};\n\nexport const getPreviousMonth = (month: string): string => {\n const date = parse(month, 'yyyy-MM', new Date());\n const previousMonth = subMonths(date, 1);\n return format(previousMonth, 'yyyy-MM');\n};\n\nexport const getPeriodStrings = (granularity: string, startTime: Date, endTime: Date): string[] => {\n const result: string[] = [];\n const current = moment(startTime);\n\n while (current.isSameOrBefore(endTime) && current.isSameOrBefore(moment())) {\n if (granularity === 'monthly') {\n result.push(current.format('YYYY-MM'));\n current.add(1, 'months');\n } else {\n result.push(current.format('YYYY-MM-DD'));\n current.add(1, 'days');\n }\n }\n\n return result;\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -30,7 +30,7 @@ const ColumnsChartComponent = ({
|
|
|
30
30
|
}
|
|
31
31
|
});
|
|
32
32
|
const classes = useStyles();
|
|
33
|
-
const [showMetrics, setShowMetrics] = useState(
|
|
33
|
+
const [showMetrics, setShowMetrics] = useState(false);
|
|
34
34
|
const [seriesArray, setSeriesArray] = useState([]);
|
|
35
35
|
const [yaxisArray, setYaxisArray] = useState([]);
|
|
36
36
|
const [strokeWidthArray, setStrokeWidthArray] = useState([]);
|
|
@@ -117,9 +117,18 @@ const ColumnsChartComponent = ({
|
|
|
117
117
|
series: seriesArray
|
|
118
118
|
};
|
|
119
119
|
const initChartCallback = useCallback(async () => {
|
|
120
|
+
const labelFormatter = (value) => {
|
|
121
|
+
const scale = humanFormat.Scale.create(["", "K", "M", "B"], 1e3);
|
|
122
|
+
if (typeof value !== "number" || isNaN(value)) {
|
|
123
|
+
return "";
|
|
124
|
+
}
|
|
125
|
+
return `$${humanFormat(value, {
|
|
126
|
+
scale,
|
|
127
|
+
separator: ""
|
|
128
|
+
})}`;
|
|
129
|
+
};
|
|
120
130
|
const strokeWidth = Array(series.length).fill(0);
|
|
121
131
|
const seriesResult = series.map((s) => s);
|
|
122
|
-
const scale = humanFormat.Scale.create(["", "K", "M", "B"], 1e3);
|
|
123
132
|
const yaxisResult = [
|
|
124
133
|
{
|
|
125
134
|
seriesName: series.map((s) => s.name),
|
|
@@ -128,41 +137,49 @@ const ColumnsChartComponent = ({
|
|
|
128
137
|
text: "Costs in USD"
|
|
129
138
|
},
|
|
130
139
|
labels: {
|
|
131
|
-
formatter:
|
|
132
|
-
if (typeof value !== "number" || isNaN(value)) {
|
|
133
|
-
return "";
|
|
134
|
-
}
|
|
135
|
-
return `$${humanFormat(value, {
|
|
136
|
-
scale,
|
|
137
|
-
separator: ""
|
|
138
|
-
})}`;
|
|
139
|
-
}
|
|
140
|
+
formatter: labelFormatter
|
|
140
141
|
}
|
|
141
142
|
}
|
|
142
143
|
];
|
|
143
144
|
if (metrics && showMetrics) {
|
|
145
|
+
const metricGroups = {};
|
|
144
146
|
metrics.forEach((metric) => {
|
|
145
147
|
strokeWidth.push(3);
|
|
146
148
|
seriesResult.push(metric);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
149
|
+
if (metric.group) {
|
|
150
|
+
if (!metricGroups[metric.group]) {
|
|
151
|
+
metricGroups[metric.group] = {
|
|
152
|
+
seriesName: [metric.name],
|
|
153
|
+
decimalsInFloat: 2,
|
|
154
|
+
opposite: true,
|
|
155
|
+
forceNiceScale: true,
|
|
156
|
+
title: {
|
|
157
|
+
text: metric.group
|
|
158
|
+
},
|
|
159
|
+
labels: {
|
|
160
|
+
formatter: labelFormatter
|
|
158
161
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
});
|
|
163
|
-
}
|
|
162
|
+
};
|
|
163
|
+
} else {
|
|
164
|
+
metricGroups[metric.group].seriesName.push(metric.name);
|
|
164
165
|
}
|
|
165
|
-
}
|
|
166
|
+
} else {
|
|
167
|
+
yaxisResult.push({
|
|
168
|
+
seriesName: [metric.name],
|
|
169
|
+
decimalsInFloat: 2,
|
|
170
|
+
opposite: true,
|
|
171
|
+
forceNiceScale: true,
|
|
172
|
+
title: {
|
|
173
|
+
text: metric.name
|
|
174
|
+
},
|
|
175
|
+
labels: {
|
|
176
|
+
formatter: labelFormatter
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
Object.values(metricGroups).forEach((group) => {
|
|
182
|
+
yaxisResult.push(group);
|
|
166
183
|
});
|
|
167
184
|
}
|
|
168
185
|
setSeriesArray(seriesResult);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColumnsChartComponent.esm.js","sources":["../../../src/components/ColumnsChartComponent/ColumnsChartComponent.tsx"],"sourcesContent":["import { Grid, Paper, Switch } from '@material-ui/core';\nimport { makeStyles, useTheme } from '@material-ui/core/styles';\nimport humanFormat from 'human-format';\nimport React, { FC, useCallback, useEffect, useState } from 'react';\nimport Chart from 'react-apexcharts';\nimport { colorList } from '../constants';\nimport { ColumnsChartComponentProps } from '../types';\n\ntype CurveType =\n | 'smooth'\n | 'straight'\n | 'stepline'\n | 'linestep'\n | 'monotoneCubic'\n | ('smooth' | 'straight' | 'stepline' | 'linestep' | 'monotoneCubic')[]\n | undefined;\n\nexport const ColumnsChartComponent: FC<ColumnsChartComponentProps> = ({\n granularitySetter,\n categories,\n series,\n metrics,\n height,\n thumbnail,\n dataPointSelectionHandler,\n}) => {\n const defaultTheme = useTheme();\n const useStyles = makeStyles({\n fixedHeightPaper: {\n padding: '16px',\n display: 'flex',\n flexDirection: 'column',\n height: height ? height : 300,\n },\n thumbnailPaper: {\n display: 'flex',\n overflow: 'hidden',\n flexDirection: 'column',\n height: height ? height - 70 : 80,\n },\n });\n const classes = useStyles();\n const [showMetrics, setShowMetrics] = useState<boolean>(true);\n const [seriesArray, setSeriesArray] = useState<any[]>([]);\n const [yaxisArray, setYaxisArray] = useState<any[]>([]);\n const [strokeWidthArray, setStrokeWidthArray] = useState<number[]>([]);\n const [strokeDashArray, setStrokeDashArray] = useState<number[]>([]);\n const customScale = humanFormat.Scale.create(['', 'K', 'M', 'B'], 1000);\n\n const state = thumbnail\n ? {\n options: {\n chart: {\n animations: {\n enabled: false,\n },\n zoom: {\n enabled: false,\n },\n stacked: true,\n toolbar: {\n show: false,\n },\n sparkline: {\n enabled: true,\n },\n },\n xaxis: {\n categories: categories,\n },\n theme: {\n mode: defaultTheme.palette.type,\n },\n },\n series: series,\n }\n : {\n options: {\n chart: {\n animations: {\n enabled: false,\n },\n stacked: true,\n toolbar: {\n show: false,\n },\n events: {\n dataPointSelection: dataPointSelectionHandler,\n },\n },\n xaxis: {\n categories: categories,\n },\n stroke: {\n width: strokeWidthArray,\n dashArray: strokeDashArray,\n curve: 'smooth' as CurveType,\n },\n yaxis: yaxisArray,\n dataLabels: {\n enabled: false,\n },\n tooltip: {\n y: {\n formatter: (value: number, { seriesIndex }: { seriesIndex: number }) => {\n if (!value) {\n return '';\n }\n const prefix = seriesIndex <= series.length - 1 ? '$' : '';\n return `${prefix}${humanFormat(value, {\n scale: customScale,\n separator: '',\n })}`;\n },\n },\n fixed: {\n enabled: true,\n position: 'topRight',\n },\n },\n legend: {\n showForSingleSeries: true,\n },\n theme: {\n mode: defaultTheme.palette.type,\n },\n // there are only 5 colors by default, here we extend it to 50 different colors\n colors: colorList,\n },\n series: seriesArray,\n };\n\n const initChartCallback = useCallback(async () => {\n const strokeWidth = Array<number>(series.length).fill(0);\n const seriesResult = series.map(s => s);\n // init a scale here as well, it seems that adding the predefined customScale as a dependency is buggy\n const scale = humanFormat.Scale.create(['', 'K', 'M', 'B'], 1000);\n const yaxisResult: any[] = [\n {\n seriesName: series.map(s => s.name),\n decimalsInFloat: 2,\n title: {\n text: 'Costs in USD',\n },\n labels: {\n formatter: (value: number) => {\n if (typeof value !== 'number' || isNaN(value)) {\n return '';\n }\n return `$${humanFormat(value, {\n scale: scale,\n separator: '',\n })}`;\n },\n },\n },\n ];\n\n if (metrics && showMetrics) {\n metrics.forEach(metric => {\n strokeWidth.push(3);\n seriesResult.push(metric);\n yaxisResult.push({\n seriesName: [metric.name],\n decimalsInFloat: 2,\n opposite: true,\n title: {\n text: metric.name,\n },\n labels: {\n formatter: (value: number) => {\n if (typeof value !== 'number' || isNaN(value)) {\n return '';\n }\n return humanFormat(value, {\n scale: scale,\n separator: '',\n });\n },\n },\n });\n });\n }\n\n setSeriesArray(seriesResult);\n setYaxisArray(yaxisResult);\n setStrokeWidthArray(strokeWidth);\n setStrokeDashArray(Array<number>(seriesResult.length).fill(0));\n }, [metrics, series, showMetrics]);\n\n useEffect(() => {\n initChartCallback();\n }, [initChartCallback]);\n\n return (\n <Paper className={thumbnail ? classes.thumbnailPaper : classes.fixedHeightPaper}>\n <Grid container justifyContent=\"flex-end\" spacing={1}>\n <Grid item>Monthly</Grid>\n <Grid item>\n <Switch size=\"small\" onChange={event => granularitySetter(event.target.checked ? 'daily' : 'monthly')} />\n </Grid>\n <Grid item>Daily</Grid>\n <Grid item> | </Grid>\n <Grid item>\n <Switch size=\"small\" checked={showMetrics} onChange={_ => setShowMetrics((ori: boolean) => !ori)} />\n </Grid>\n <Grid item>Show Metrics</Grid>\n </Grid>\n {seriesArray && (\n <Chart options={state.options} series={state.series} type=\"line\" height={height ? height - 70 : 230} />\n )}\n </Paper>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ColumnsChartComponent.esm.js","sources":["../../../src/components/ColumnsChartComponent/ColumnsChartComponent.tsx"],"sourcesContent":["import { Grid, Paper, Switch } from '@material-ui/core';\nimport { makeStyles, useTheme } from '@material-ui/core/styles';\nimport humanFormat from 'human-format';\nimport React, { FC, useCallback, useEffect, useState } from 'react';\nimport Chart from 'react-apexcharts';\nimport { colorList } from '../constants';\nimport { ColumnsChartComponentProps } from '../types';\n\ntype CurveType =\n | 'smooth'\n | 'straight'\n | 'stepline'\n | 'linestep'\n | 'monotoneCubic'\n | ('smooth' | 'straight' | 'stepline' | 'linestep' | 'monotoneCubic')[]\n | undefined;\n\nexport const ColumnsChartComponent: FC<ColumnsChartComponentProps> = ({\n granularitySetter,\n categories,\n series,\n metrics,\n height,\n thumbnail,\n dataPointSelectionHandler,\n}) => {\n const defaultTheme = useTheme();\n const useStyles = makeStyles({\n fixedHeightPaper: {\n padding: '16px',\n display: 'flex',\n flexDirection: 'column',\n height: height ? height : 300,\n },\n thumbnailPaper: {\n display: 'flex',\n overflow: 'hidden',\n flexDirection: 'column',\n height: height ? height - 70 : 80,\n },\n });\n const classes = useStyles();\n const [showMetrics, setShowMetrics] = useState<boolean>(false);\n const [seriesArray, setSeriesArray] = useState<any[]>([]);\n const [yaxisArray, setYaxisArray] = useState<any[]>([]);\n const [strokeWidthArray, setStrokeWidthArray] = useState<number[]>([]);\n const [strokeDashArray, setStrokeDashArray] = useState<number[]>([]);\n const customScale = humanFormat.Scale.create(['', 'K', 'M', 'B'], 1000);\n\n const state = thumbnail\n ? {\n options: {\n chart: {\n animations: {\n enabled: false,\n },\n zoom: {\n enabled: false,\n },\n stacked: true,\n toolbar: {\n show: false,\n },\n sparkline: {\n enabled: true,\n },\n },\n xaxis: {\n categories: categories,\n },\n theme: {\n mode: defaultTheme.palette.type,\n },\n },\n series: series,\n }\n : {\n options: {\n chart: {\n animations: {\n enabled: false,\n },\n stacked: true,\n toolbar: {\n show: false,\n },\n events: {\n dataPointSelection: dataPointSelectionHandler,\n },\n },\n xaxis: {\n categories: categories,\n },\n stroke: {\n width: strokeWidthArray,\n dashArray: strokeDashArray,\n curve: 'smooth' as CurveType,\n },\n yaxis: yaxisArray,\n dataLabels: {\n enabled: false,\n },\n tooltip: {\n y: {\n formatter: (value: number, { seriesIndex }: { seriesIndex: number }) => {\n if (!value) {\n return '';\n }\n const prefix = seriesIndex <= series.length - 1 ? '$' : '';\n return `${prefix}${humanFormat(value, {\n scale: customScale,\n separator: '',\n })}`;\n },\n },\n fixed: {\n enabled: true,\n position: 'topRight',\n },\n },\n legend: {\n showForSingleSeries: true,\n },\n theme: {\n mode: defaultTheme.palette.type,\n },\n // there are only 5 colors by default, here we extend it to 50 different colors\n colors: colorList,\n },\n series: seriesArray,\n };\n\n const initChartCallback = useCallback(async () => {\n const labelFormatter = (value: number): string => {\n const scale = humanFormat.Scale.create(['', 'K', 'M', 'B'], 1000);\n if (typeof value !== 'number' || isNaN(value)) {\n return '';\n }\n return `$${humanFormat(value, {\n scale: scale,\n separator: '',\n })}`;\n };\n\n const strokeWidth = Array<number>(series.length).fill(0);\n const seriesResult = series.map(s => s);\n const yaxisResult: any[] = [\n {\n seriesName: series.map(s => s.name),\n decimalsInFloat: 2,\n title: {\n text: 'Costs in USD',\n },\n labels: {\n formatter: labelFormatter,\n },\n },\n ];\n\n if (metrics && showMetrics) {\n const metricGroups: any = {};\n metrics.forEach(metric => {\n strokeWidth.push(3);\n seriesResult.push(metric);\n\n if (metric.group) {\n if (!metricGroups[metric.group]) {\n metricGroups[metric.group] = {\n seriesName: [metric.name],\n decimalsInFloat: 2,\n opposite: true,\n forceNiceScale: true,\n title: {\n text: metric.group,\n },\n labels: {\n formatter: labelFormatter,\n },\n };\n } else {\n // yaxis already exists, add the series to the existing one\n metricGroups[metric.group].seriesName.push(metric.name);\n }\n } else {\n // the metric does not have a group, create a separate yaxis for it\n yaxisResult.push({\n seriesName: [metric.name],\n decimalsInFloat: 2,\n opposite: true,\n forceNiceScale: true,\n title: {\n text: metric.name,\n },\n labels: {\n formatter: labelFormatter,\n },\n });\n }\n });\n Object.values(metricGroups).forEach((group: any) => {\n yaxisResult.push(group);\n });\n }\n\n setSeriesArray(seriesResult);\n setYaxisArray(yaxisResult);\n setStrokeWidthArray(strokeWidth);\n setStrokeDashArray(Array<number>(seriesResult.length).fill(0));\n }, [metrics, series, showMetrics]);\n\n useEffect(() => {\n initChartCallback();\n }, [initChartCallback]);\n\n return (\n <Paper className={thumbnail ? classes.thumbnailPaper : classes.fixedHeightPaper}>\n <Grid container justifyContent=\"flex-end\" spacing={1}>\n <Grid item>Monthly</Grid>\n <Grid item>\n <Switch size=\"small\" onChange={event => granularitySetter(event.target.checked ? 'daily' : 'monthly')} />\n </Grid>\n <Grid item>Daily</Grid>\n <Grid item> | </Grid>\n <Grid item>\n <Switch size=\"small\" checked={showMetrics} onChange={_ => setShowMetrics((ori: boolean) => !ori)} />\n </Grid>\n <Grid item>Show Metrics</Grid>\n </Grid>\n {seriesArray && (\n <Chart options={state.options} series={state.series} type=\"line\" height={height ? height - 70 : 230} />\n )}\n </Paper>\n );\n};\n"],"names":[],"mappings":"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"}
|