@electrolux-oss/plugin-infrawallet 0.1.0 → 0.1.4

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.
Files changed (27) hide show
  1. package/README.md +26 -10
  2. package/dist/api/InfraWalletApi.esm.js.map +1 -1
  3. package/dist/api/InfraWalletApiClient.esm.js +12 -65
  4. package/dist/api/InfraWalletApiClient.esm.js.map +1 -1
  5. package/dist/api/functions.esm.js +35 -28
  6. package/dist/api/functions.esm.js.map +1 -1
  7. package/dist/components/ColumnsChartComponent/ColumnsChartComponent.esm.js +44 -22
  8. package/dist/components/ColumnsChartComponent/ColumnsChartComponent.esm.js.map +1 -1
  9. package/dist/components/CostReportsTableComponent/CostReportsTableComponent.esm.js +49 -19
  10. package/dist/components/CostReportsTableComponent/CostReportsTableComponent.esm.js.map +1 -1
  11. package/dist/components/CostReportsTableComponent/TrendBarComponent.esm.js +1 -6
  12. package/dist/components/CostReportsTableComponent/TrendBarComponent.esm.js.map +1 -1
  13. package/dist/components/ErrorsAlertComponent/ErrorsAlertComponent.esm.js +40 -0
  14. package/dist/components/ErrorsAlertComponent/ErrorsAlertComponent.esm.js.map +1 -0
  15. package/dist/components/InfraWalletIcon.esm.js +61 -0
  16. package/dist/components/InfraWalletIcon.esm.js.map +1 -0
  17. package/dist/components/PieChartComponent/PieChartComponent.esm.js +3 -15
  18. package/dist/components/PieChartComponent/PieChartComponent.esm.js.map +1 -1
  19. package/dist/components/ReportsComponent/ReportsComponent.esm.js +21 -39
  20. package/dist/components/ReportsComponent/ReportsComponent.esm.js.map +1 -1
  21. package/dist/components/TopbarComponent/TopbarComponent.esm.js +1 -25
  22. package/dist/components/TopbarComponent/TopbarComponent.esm.js.map +1 -1
  23. package/dist/index.d.ts +4 -1
  24. package/dist/index.esm.js +1 -0
  25. package/dist/index.esm.js.map +1 -1
  26. package/dist/plugin.esm.js.map +1 -1
  27. package/package.json +4 -3
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  - Swift response times with cached cost data, ensuring rapid access to financial insights fetched from cloud platforms
12
12
  - Easy configuration and deployment as a Backstage plugin, both frontend and backend plugins are production-ready
13
13
 
14
- \*_This version prioritizes AWS and Azure as the primary cloud vendors, but the framework is designed to be extensible to support others. Feel free to contribute to the project or wait for the next version with expanded cloud vendor support._
14
+ \*_The latest version supports AWS, Azure and GCP cost aggregation while the framework is designed to be extensible to support others. Feel free to contribute to the project._
15
15
 
16
16
  ## Getting started
17
17
 
@@ -67,6 +67,24 @@ backend:
67
67
  clientSecret: <Client_secret_of_the_created_application>
68
68
  ```
69
69
 
70
+ #### GCP
71
+
72
+ 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.
73
+
74
+ After setting up the resources above, add the following configurations in `app-config.yaml`:
75
+
76
+ ```yaml
77
+ backend:
78
+ infraWallet:
79
+ integrations:
80
+ gcp:
81
+ - name: <unique_name_of_this_account>
82
+ 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
83
+ projectId: <GCP_project_that_your_big_query_dataset_belongs_to>
84
+ datasetId: <big_query_dataset_id>
85
+ tableId: <big_query_table_id>
86
+ ```
87
+
70
88
  ### Adjust Category Mappings if Needed
71
89
 
72
90
  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](plugins/infrawallet-backend/seeds/init.js) file. You can adjust this seed file to fit your needs, or update the database directly later on.
@@ -145,17 +163,17 @@ backend:
145
163
 
146
164
  4. add InfraWallet to the sidebar (optional)
147
165
 
148
- modify `packages/app/src/App.tsx` and add the following code
166
+ modify `packages/app/src/components/Root/Root.tsx` and add the following code
149
167
 
150
168
  ```ts
151
169
  ...
152
- import AccountBalanceWalletIcon from '@material-ui/icons/AccountBalanceWallet';
170
+ import { InfraWalletIcon } from '@electrolux-oss/plugin-infrawallet';
153
171
  ...
154
172
  <Sidebar>
155
173
  ...
156
174
  <SidebarGroup label="Menu" icon={<MenuIcon />}>
157
175
  <SidebarItem
158
- icon={AccountBalanceWalletIcon}
176
+ icon={InfraWalletIcon}
159
177
  to="infrawallet"
160
178
  text="InfraWallet"
161
179
  />
@@ -180,13 +198,11 @@ import { createRouter } from '@electrolux-oss/plugin-infrawallet-backend';
180
198
  import { Router } from 'express';
181
199
  import { PluginEnvironment } from '../types';
182
200
 
183
- export default async function createPlugin(
184
- env: PluginEnvironment,
185
- ): Promise<Router> {
201
+ export default async function createPlugin(env: PluginEnvironment): Promise<Router> {
186
202
  return await createRouter({
187
203
  logger: env.logger,
188
204
  config: env.config,
189
- audit: env.audit,
205
+ cache: env.cache.getClient(),
190
206
  database: env.database,
191
207
  });
192
208
  }
@@ -209,9 +225,9 @@ async function main() {
209
225
 
210
226
  ## Local Development
211
227
 
212
- Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/infrawallet](http://localhost:3000/infrawallet).
228
+ First of all, make sure you are using either Node 18 or Node 20 for this project. Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn install && yarn dev` in the root directory, and then navigating to [/infrawallet](http://localhost:3000/infrawallet).
213
229
 
214
- You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
230
+ You can also serve the plugin in isolation by running `yarn install && yarn start` in the plugin directory.
215
231
  This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
216
232
  It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
217
233
 
@@ -1 +1 @@
1
- {"version":3,"file":"InfraWalletApi.esm.js","sources":["../../src/api/InfraWalletApi.ts"],"sourcesContent":["import { createApiRef } from '@backstage/core-plugin-api';\nimport { CostReportsResponse } from './types';\nimport { Response } from 'node-fetch';\n\n/** @public */\nexport const infraWalletApiRef = createApiRef<InfraWalletApi>({\n id: 'plugin.infrawallet',\n});\n\n/** @public */\nexport interface InfraWalletApi {\n get(path: string, headers?: Record<string, string>): Promise<Response>;\n post(\n path: string,\n headers?: Record<string, string>,\n data?: Record<string, any | undefined>,\n ): Promise<Response>;\n put(\n path: string,\n headers?: Record<string, string>,\n data?: Record<string, any | undefined>,\n ): Promise<Response>;\n delete(\n path: string,\n headers?: Record<string, string>,\n data?: Record<string, any | undefined>,\n ): Promise<Response>;\n getCostReports(\n filters: string,\n groups: string,\n granularity: string,\n startTime: Date,\n endTime: Date,\n ): Promise<CostReportsResponse>;\n}\n"],"names":[],"mappings":";;AAKO,MAAM,oBAAoB,YAA6B,CAAA;AAAA,EAC5D,EAAI,EAAA,oBAAA;AACN,CAAC;;;;"}
1
+ {"version":3,"file":"InfraWalletApi.esm.js","sources":["../../src/api/InfraWalletApi.ts"],"sourcesContent":["import { createApiRef } from '@backstage/core-plugin-api';\nimport { CostReportsResponse } from './types';\nimport { Response } from 'node-fetch';\n\n/** @public */\nexport const infraWalletApiRef = createApiRef<InfraWalletApi>({\n id: 'plugin.infrawallet',\n});\n\n/** @public */\nexport interface InfraWalletApi {\n get(path: string): Promise<Response>;\n getCostReports(\n filters: string,\n groups: string,\n granularity: string,\n startTime: Date,\n endTime: Date,\n ): Promise<CostReportsResponse>;\n}\n"],"names":[],"mappings":";;AAKO,MAAM,oBAAoB,YAA6B,CAAA;AAAA,EAC5D,EAAI,EAAA,oBAAA;AACN,CAAC;;;;"}
@@ -13,75 +13,22 @@ class InfraWalletApiClient {
13
13
  this.identityApi = options.identityApi;
14
14
  this.backendUrl = options.configApi.getString("backend.baseUrl");
15
15
  }
16
- async get(path, headers) {
17
- return await this.requestRaw(`${this.backendUrl}/${path}`, headers);
18
- }
19
- async post(path, headers, data) {
20
- const hdrs = {
21
- ...headers,
22
- "Content-Type": "application/json"
23
- };
24
- const method = "POST";
25
- return await this.requestRaw(
26
- `${this.backendUrl}/${path}`,
27
- hdrs,
28
- method,
29
- data
30
- );
31
- }
32
- async put(path, headers, data) {
33
- const hdrs = {
34
- ...headers,
35
- "Content-Type": "application/json"
36
- };
37
- const method = "PUT";
38
- return await this.requestRaw(
39
- `${this.backendUrl}/${path}`,
40
- hdrs,
41
- method,
42
- data
43
- );
44
- }
45
- async delete(path, headers, data) {
46
- const hdrs = {
47
- ...headers,
48
- "Content-Type": "application/json"
49
- };
50
- const method = "DELETE";
51
- return await this.requestRaw(
52
- `${this.backendUrl}/${path}`,
53
- hdrs,
54
- method,
55
- data
56
- );
57
- }
58
- async requestRaw(url, headers, method, data) {
59
- let payload;
60
- if (!method) {
61
- payload = {
62
- method: "GET",
63
- headers
64
- };
65
- } else {
66
- payload = {
67
- method,
68
- headers,
69
- body: JSON.stringify(data)
70
- };
16
+ async get(path) {
17
+ const url = `${this.backendUrl}/${path}`;
18
+ const { token: idToken } = await this.identityApi.getCredentials();
19
+ const response = await fetch(url, {
20
+ headers: idToken ? { Authorization: `Bearer ${idToken}` } : {}
21
+ });
22
+ if (!response.ok) {
23
+ const payload = await response.text();
24
+ const message = `Request failed with ${response.status} ${response.statusText}, ${payload}`;
25
+ throw new Error(message);
71
26
  }
72
- return await fetch(url, payload);
27
+ return await response.json();
73
28
  }
74
29
  async getCostReports(filters, groups, granularity, startTime, endTime) {
75
- const { token: idToken } = await this.identityApi.getCredentials();
76
- const headers = idToken ? { Authorization: `Bearer ${idToken}` } : {};
77
30
  const url = `api/infrawallet/reports?&filters=${filters}&groups=${groups}&granularity=${granularity}&startTime=${startTime.getTime()}&endTime=${endTime.getTime()}`;
78
- const response = await this.get(url, headers);
79
- if (!response.ok) {
80
- const r = await response.json();
81
- throw new Error(r.error.message);
82
- } else {
83
- return await response.json();
84
- }
31
+ return await this.get(url);
85
32
  }
86
33
  }
87
34
 
@@ -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, { Response } from 'node-fetch';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport { CostReportsResponse } 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 get(path: string, headers?: Record<string, string>): Promise<Response> {\n return await this.requestRaw(`${this.backendUrl}/${path}`, headers);\n }\n\n async post(\n path: string,\n headers?: Record<string, string>,\n data?: Record<string, any | undefined>,\n ): Promise<Response> {\n const hdrs = {\n ...headers,\n 'Content-Type': 'application/json',\n };\n const method = 'POST';\n\n return await this.requestRaw(\n `${this.backendUrl}/${path}`,\n hdrs,\n method,\n data,\n );\n }\n\n async put(\n path: string,\n headers?: Record<string, string>,\n data?: Record<string, any | undefined>,\n ): Promise<Response> {\n const hdrs = {\n ...headers,\n 'Content-Type': 'application/json',\n };\n const method = 'PUT';\n\n return await this.requestRaw(\n `${this.backendUrl}/${path}`,\n hdrs,\n method,\n data,\n );\n }\n\n async delete(\n path: string,\n headers?: Record<string, string>,\n data?: Record<string, any | undefined>,\n ): Promise<Response> {\n const hdrs = {\n ...headers,\n 'Content-Type': 'application/json',\n };\n const method = 'DELETE';\n\n return await this.requestRaw(\n `${this.backendUrl}/${path}`,\n hdrs,\n method,\n data,\n );\n }\n\n async requestRaw(\n url: string,\n headers?: Record<string, string>,\n method?: string,\n data?: Record<string, any | undefined>,\n ): Promise<Response> {\n let payload;\n if (!method) {\n payload = {\n method: 'GET',\n headers,\n };\n } else {\n payload = {\n method,\n headers,\n body: JSON.stringify(data),\n };\n }\n\n return await fetch(url, payload);\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 { token: idToken } = await this.identityApi.getCredentials();\n const headers = idToken ? { Authorization: `Bearer ${idToken}` } : {};\n\n const url = `api/infrawallet/reports?&filters=${filters}&groups=${groups}&granularity=${granularity}&startTime=${startTime.getTime()}&endTime=${endTime.getTime()}`;\n const response = await this.get(url, headers);\n\n if (!response.ok) {\n const r = await response.json();\n throw new Error(r.error.message);\n } else {\n return await response.json();\n }\n }\n}\n"],"names":[],"mappings":"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"}
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 { CostReportsResponse } 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 get(path: string): Promise<any> {\n const url = `${this.backendUrl}/${path}`;\n const { token: idToken } = await this.identityApi.getCredentials();\n const response = await fetch(url, {\n headers: idToken ? { Authorization: `Bearer ${idToken}` } : {},\n });\n\n if (!response.ok) {\n const payload = await response.text();\n const message = `Request failed with ${response.status} ${response.statusText}, ${payload}`;\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.get(url);\n }\n}\n"],"names":[],"mappings":";;;;;;;;AAMO,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,IAAI,IAA4B,EAAA;AACpC,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,QAAA,GAAW,MAAM,KAAA,CAAM,GAAK,EAAA;AAAA,MAChC,OAAA,EAAS,UAAU,EAAE,aAAA,EAAe,UAAU,OAAO,CAAA,CAAA,KAAO,EAAC;AAAA,KAC9D,CAAA,CAAA;AAED,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,OAAA,GAAU,MAAM,QAAA,CAAS,IAAK,EAAA,CAAA;AACpC,MAAM,MAAA,OAAA,GAAU,uBAAuB,QAAS,CAAA,MAAM,IAAI,QAAS,CAAA,UAAU,KAAK,OAAO,CAAA,CAAA,CAAA;AACzF,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,EAAA,WAAA,EACA,WACA,OAC8B,EAAA;AAC9B,IAAA,MAAM,GAAM,GAAA,CAAA,iCAAA,EAAoC,OAAO,CAAA,QAAA,EAAW,MAAM,CAAgB,aAAA,EAAA,WAAW,CAAc,WAAA,EAAA,SAAA,CAAU,OAAQ,EAAC,CAAY,SAAA,EAAA,OAAA,CAAQ,SAAS,CAAA,CAAA,CAAA;AACjK,IAAO,OAAA,MAAM,IAAK,CAAA,GAAA,CAAI,GAAG,CAAA,CAAA;AAAA,GAC3B;AACF;;;;"}
@@ -1,10 +1,8 @@
1
- import { reduce } from 'lodash';
2
1
  import { parse, subMonths, format } from 'date-fns';
2
+ import { reduce } from 'lodash';
3
+ import moment from 'moment';
3
4
 
4
5
  const mergeCostReports = (reports, threshold) => {
5
- if (reports.length <= threshold) {
6
- return reports;
7
- }
8
6
  const totalCosts = [];
9
7
  reports.forEach((report) => {
10
8
  let total = 0;
@@ -17,25 +15,25 @@ const mergeCostReports = (reports, threshold) => {
17
15
  const idsToBeKept = sortedTotalCosts.slice(0, threshold).map((v) => v.id);
18
16
  const mergedReports = reduce(
19
17
  reports,
20
- (acc, report) => {
18
+ (accumulator, report) => {
21
19
  let keyName = "others";
22
20
  if (idsToBeKept.includes(report.id)) {
23
21
  keyName = report.id;
24
22
  }
25
- if (!acc[keyName]) {
26
- acc[keyName] = {
23
+ if (!accumulator[keyName]) {
24
+ accumulator[keyName] = {
27
25
  id: keyName,
28
26
  reports: {}
29
27
  };
30
28
  }
31
29
  Object.keys(report.reports).forEach((key) => {
32
- if (acc[keyName].reports[key]) {
33
- acc[keyName].reports[key] += report.reports[key];
30
+ if (accumulator[keyName].reports[key]) {
31
+ accumulator[keyName].reports[key] += report.reports[key];
34
32
  } else {
35
- acc[keyName].reports[key] = report.reports[key];
33
+ accumulator[keyName].reports[key] = report.reports[key];
36
34
  }
37
35
  });
38
- return acc;
36
+ return accumulator;
39
37
  },
40
38
  {}
41
39
  );
@@ -44,28 +42,30 @@ const mergeCostReports = (reports, threshold) => {
44
42
  const aggregateCostReports = (reports, aggregatedBy) => {
45
43
  const aggregatedReports = reduce(
46
44
  reports,
47
- (acc, report) => {
45
+ (accumulator, report) => {
48
46
  let keyName = "no value";
49
47
  if (aggregatedBy && aggregatedBy in report) {
50
48
  keyName = report[aggregatedBy];
51
49
  } else if (aggregatedBy === "none") {
52
50
  keyName = "Total cloud costs";
53
51
  }
54
- if (!acc[keyName]) {
55
- acc[keyName] = {
52
+ if (!accumulator[keyName]) {
53
+ accumulator[keyName] = {
56
54
  id: keyName,
57
55
  reports: {}
58
56
  };
59
- acc[keyName][aggregatedBy] = keyName;
57
+ if (aggregatedBy !== void 0) {
58
+ accumulator[keyName][aggregatedBy] = keyName;
59
+ }
60
60
  }
61
61
  Object.keys(report.reports).forEach((key) => {
62
- if (acc[keyName].reports[key]) {
63
- acc[keyName].reports[key] += report.reports[key];
62
+ if (accumulator[keyName].reports[key]) {
63
+ accumulator[keyName].reports[key] += report.reports[key];
64
64
  } else {
65
- acc[keyName].reports[key] = report.reports[key];
65
+ accumulator[keyName].reports[key] = report.reports[key];
66
66
  }
67
67
  });
68
- return acc;
68
+ return accumulator;
69
69
  },
70
70
  {}
71
71
  );
@@ -73,14 +73,7 @@ const aggregateCostReports = (reports, aggregatedBy) => {
73
73
  };
74
74
  const getAllReportTags = (reports) => {
75
75
  const tags = /* @__PURE__ */ new Set();
76
- const reservedKeys = [
77
- "id",
78
- "name",
79
- "service",
80
- "category",
81
- "provider",
82
- "reports"
83
- ];
76
+ const reservedKeys = ["id", "name", "service", "category", "provider", "reports"];
84
77
  reports.forEach((report) => {
85
78
  Object.keys(report).forEach((key) => {
86
79
  if (reservedKeys.indexOf(key) === -1) {
@@ -95,6 +88,20 @@ const getPreviousMonth = (month) => {
95
88
  const previousMonth = subMonths(date, 1);
96
89
  return format(previousMonth, "yyyy-MM");
97
90
  };
91
+ const getPeriodStrings = (granularity, startTime, endTime) => {
92
+ const result = [];
93
+ const current = moment(startTime);
94
+ while (current.isSameOrBefore(endTime) && current.isSameOrBefore(moment())) {
95
+ if (granularity === "monthly") {
96
+ result.push(current.format("YYYY-MM"));
97
+ current.add(1, "months");
98
+ } else {
99
+ result.push(current.format("YYYY-MM-DD"));
100
+ current.add(1, "days");
101
+ }
102
+ }
103
+ return result;
104
+ };
98
105
 
99
- export { aggregateCostReports, getAllReportTags, getPreviousMonth, mergeCostReports };
106
+ export { aggregateCostReports, getAllReportTags, getPeriodStrings, getPreviousMonth, mergeCostReports };
100
107
  //# sourceMappingURL=functions.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"functions.esm.js","sources":["../../src/api/functions.ts"],"sourcesContent":["import { Report } from './types';\nimport { reduce } from 'lodash';\nimport { parse, format, subMonths } from 'date-fns';\n\nexport const mergeCostReports = (\n reports: Report[],\n threshold: number,\n): Report[] => {\n if (reports.length <= threshold) {\n return reports;\n }\n const totalCosts = [];\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 (acc, report) => {\n let keyName = 'others';\n if (idsToBeKept.includes(report.id)) {\n keyName = report.id;\n }\n if (!acc[keyName]) {\n acc[keyName] = {\n id: keyName,\n reports: {},\n };\n }\n\n Object.keys(report.reports).forEach(key => {\n if (acc[keyName].reports[key]) {\n acc[keyName].reports[key] += report.reports[key];\n } else {\n acc[keyName].reports[key] = report.reports[key];\n }\n });\n return acc;\n },\n {},\n );\n\n return Object.values(mergedReports);\n};\n\nexport const aggregateCostReports = (\n reports: Report[],\n aggregatedBy?: string,\n): Report[] => {\n const aggregatedReports = reduce(\n reports,\n (acc, report) => {\n let keyName = 'no value';\n if (aggregatedBy && aggregatedBy in report) {\n keyName = report[aggregatedBy];\n } else if (aggregatedBy === 'none') {\n keyName = 'Total cloud costs';\n }\n if (!acc[keyName]) {\n acc[keyName] = {\n id: keyName,\n reports: {},\n };\n acc[keyName][aggregatedBy] = keyName;\n }\n\n Object.keys(report.reports).forEach(key => {\n if (acc[keyName].reports[key]) {\n acc[keyName].reports[key] += report.reports[key];\n } else {\n acc[keyName].reports[key] = report.reports[key];\n }\n });\n return acc;\n },\n {},\n );\n return Object.values(aggregatedReports);\n};\n\nexport const getAllReportTags = (reports: Report[]): string[] => {\n const tags = new Set<string>();\n const reservedKeys = [\n 'id',\n 'name',\n 'service',\n 'category',\n 'provider',\n 'reports',\n ];\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"],"names":[],"mappings":";;;AAIa,MAAA,gBAAA,GAAmB,CAC9B,OAAA,EACA,SACa,KAAA;AACb,EAAI,IAAA,OAAA,CAAQ,UAAU,SAAW,EAAA;AAC/B,IAAO,OAAA,OAAA,CAAA;AAAA,GACT;AACA,EAAA,MAAM,aAAa,EAAC,CAAA;AACpB,EAAA,OAAA,CAAQ,QAAQ,CAAU,MAAA,KAAA;AACxB,IAAA,IAAI,KAAQ,GAAA,CAAA,CAAA;AACZ,IAAA,MAAA,CAAO,MAAO,CAAA,MAAA,CAAO,OAAO,CAAA,CAAE,QAAQ,CAAK,CAAA,KAAA;AACzC,MAAS,KAAA,IAAA,CAAA,CAAA;AAAA,KACV,CAAA,CAAA;AACD,IAAA,UAAA,CAAW,KAAK,EAAE,EAAA,EAAI,MAAO,CAAA,EAAA,EAAI,OAAc,CAAA,CAAA;AAAA,GAChD,CAAA,CAAA;AACD,EAAM,MAAA,gBAAA,GAAmB,WAAW,IAAK,CAAA,CAAC,GAAG,CAAM,KAAA,CAAA,CAAE,KAAQ,GAAA,CAAA,CAAE,KAAK,CAAA,CAAA;AACpE,EAAM,MAAA,WAAA,GAAc,iBAAiB,KAAM,CAAA,CAAA,EAAG,SAAS,CAAE,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA,CAAA,CAAE,EAAE,CAAA,CAAA;AAEtE,EAAA,MAAM,aAAgB,GAAA,MAAA;AAAA,IACpB,OAAA;AAAA,IACA,CAAC,KAAK,MAAW,KAAA;AACf,MAAA,IAAI,OAAU,GAAA,QAAA,CAAA;AACd,MAAA,IAAI,WAAY,CAAA,QAAA,CAAS,MAAO,CAAA,EAAE,CAAG,EAAA;AACnC,QAAA,OAAA,GAAU,MAAO,CAAA,EAAA,CAAA;AAAA,OACnB;AACA,MAAI,IAAA,CAAC,GAAI,CAAA,OAAO,CAAG,EAAA;AACjB,QAAA,GAAA,CAAI,OAAO,CAAI,GAAA;AAAA,UACb,EAAI,EAAA,OAAA;AAAA,UACJ,SAAS,EAAC;AAAA,SACZ,CAAA;AAAA,OACF;AAEA,MAAA,MAAA,CAAO,IAAK,CAAA,MAAA,CAAO,OAAO,CAAA,CAAE,QAAQ,CAAO,GAAA,KAAA;AACzC,QAAA,IAAI,GAAI,CAAA,OAAO,CAAE,CAAA,OAAA,CAAQ,GAAG,CAAG,EAAA;AAC7B,UAAA,GAAA,CAAI,OAAO,CAAE,CAAA,OAAA,CAAQ,GAAG,CAAK,IAAA,MAAA,CAAO,QAAQ,GAAG,CAAA,CAAA;AAAA,SAC1C,MAAA;AACL,UAAA,GAAA,CAAI,OAAO,CAAE,CAAA,OAAA,CAAQ,GAAG,CAAI,GAAA,MAAA,CAAO,QAAQ,GAAG,CAAA,CAAA;AAAA,SAChD;AAAA,OACD,CAAA,CAAA;AACD,MAAO,OAAA,GAAA,CAAA;AAAA,KACT;AAAA,IACA,EAAC;AAAA,GACH,CAAA;AAEA,EAAO,OAAA,MAAA,CAAO,OAAO,aAAa,CAAA,CAAA;AACpC,EAAA;AAEa,MAAA,oBAAA,GAAuB,CAClC,OAAA,EACA,YACa,KAAA;AACb,EAAA,MAAM,iBAAoB,GAAA,MAAA;AAAA,IACxB,OAAA;AAAA,IACA,CAAC,KAAK,MAAW,KAAA;AACf,MAAA,IAAI,OAAU,GAAA,UAAA,CAAA;AACd,MAAI,IAAA,YAAA,IAAgB,gBAAgB,MAAQ,EAAA;AAC1C,QAAA,OAAA,GAAU,OAAO,YAAY,CAAA,CAAA;AAAA,OAC/B,MAAA,IAAW,iBAAiB,MAAQ,EAAA;AAClC,QAAU,OAAA,GAAA,mBAAA,CAAA;AAAA,OACZ;AACA,MAAI,IAAA,CAAC,GAAI,CAAA,OAAO,CAAG,EAAA;AACjB,QAAA,GAAA,CAAI,OAAO,CAAI,GAAA;AAAA,UACb,EAAI,EAAA,OAAA;AAAA,UACJ,SAAS,EAAC;AAAA,SACZ,CAAA;AACA,QAAI,GAAA,CAAA,OAAO,CAAE,CAAA,YAAY,CAAI,GAAA,OAAA,CAAA;AAAA,OAC/B;AAEA,MAAA,MAAA,CAAO,IAAK,CAAA,MAAA,CAAO,OAAO,CAAA,CAAE,QAAQ,CAAO,GAAA,KAAA;AACzC,QAAA,IAAI,GAAI,CAAA,OAAO,CAAE,CAAA,OAAA,CAAQ,GAAG,CAAG,EAAA;AAC7B,UAAA,GAAA,CAAI,OAAO,CAAE,CAAA,OAAA,CAAQ,GAAG,CAAK,IAAA,MAAA,CAAO,QAAQ,GAAG,CAAA,CAAA;AAAA,SAC1C,MAAA;AACL,UAAA,GAAA,CAAI,OAAO,CAAE,CAAA,OAAA,CAAQ,GAAG,CAAI,GAAA,MAAA,CAAO,QAAQ,GAAG,CAAA,CAAA;AAAA,SAChD;AAAA,OACD,CAAA,CAAA;AACD,MAAO,OAAA,GAAA,CAAA;AAAA,KACT;AAAA,IACA,EAAC;AAAA,GACH,CAAA;AACA,EAAO,OAAA,MAAA,CAAO,OAAO,iBAAiB,CAAA,CAAA;AACxC,EAAA;AAEa,MAAA,gBAAA,GAAmB,CAAC,OAAgC,KAAA;AAC/D,EAAM,MAAA,IAAA,uBAAW,GAAY,EAAA,CAAA;AAC7B,EAAA,MAAM,YAAe,GAAA;AAAA,IACnB,IAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA;AAAA,GACF,CAAA;AACA,EAAA,OAAA,CAAQ,QAAQ,CAAU,MAAA,KAAA;AACxB,IAAA,MAAA,CAAO,IAAK,CAAA,MAAM,CAAE,CAAA,OAAA,CAAQ,CAAO,GAAA,KAAA;AACjC,MAAA,IAAI,YAAa,CAAA,OAAA,CAAQ,GAAG,CAAA,KAAM,CAAI,CAAA,EAAA;AACpC,QAAA,IAAA,CAAK,IAAI,GAAG,CAAA,CAAA;AAAA,OACd;AAAA,KACD,CAAA,CAAA;AAAA,GACF,CAAA,CAAA;AACD,EAAO,OAAA,KAAA,CAAM,KAAK,IAAI,CAAA,CAAA;AACxB,EAAA;AAEa,MAAA,gBAAA,GAAmB,CAAC,KAA0B,KAAA;AACzD,EAAA,MAAM,OAAO,KAAM,CAAA,KAAA,EAAO,SAAW,kBAAA,IAAI,MAAM,CAAA,CAAA;AAC/C,EAAM,MAAA,aAAA,GAAgB,SAAU,CAAA,IAAA,EAAM,CAAC,CAAA,CAAA;AACvC,EAAO,OAAA,MAAA,CAAO,eAAe,SAAS,CAAA,CAAA;AACxC;;;;"}
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 } 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 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 cloud costs';\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 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":";;;;AAKa,MAAA,gBAAA,GAAmB,CAAC,OAAA,EAAmB,SAAgC,KAAA;AAClF,EAAA,MAAM,aAA8C,EAAC,CAAA;AACrD,EAAA,OAAA,CAAQ,QAAQ,CAAU,MAAA,KAAA;AACxB,IAAA,IAAI,KAAQ,GAAA,CAAA,CAAA;AACZ,IAAA,MAAA,CAAO,MAAO,CAAA,MAAA,CAAO,OAAO,CAAA,CAAE,QAAQ,CAAK,CAAA,KAAA;AACzC,MAAS,KAAA,IAAA,CAAA,CAAA;AAAA,KACV,CAAA,CAAA;AACD,IAAA,UAAA,CAAW,KAAK,EAAE,EAAA,EAAI,MAAO,CAAA,EAAA,EAAI,OAAc,CAAA,CAAA;AAAA,GAChD,CAAA,CAAA;AACD,EAAM,MAAA,gBAAA,GAAmB,WAAW,IAAK,CAAA,CAAC,GAAG,CAAM,KAAA,CAAA,CAAE,KAAQ,GAAA,CAAA,CAAE,KAAK,CAAA,CAAA;AACpE,EAAM,MAAA,WAAA,GAAc,iBAAiB,KAAM,CAAA,CAAA,EAAG,SAAS,CAAE,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA,CAAA,CAAE,EAAE,CAAA,CAAA;AAEtE,EAAA,MAAM,aAAgB,GAAA,MAAA;AAAA,IACpB,OAAA;AAAA,IACA,CAAC,aAAwC,MAAW,KAAA;AAClD,MAAA,IAAI,OAAU,GAAA,QAAA,CAAA;AACd,MAAA,IAAI,WAAY,CAAA,QAAA,CAAS,MAAO,CAAA,EAAE,CAAG,EAAA;AACnC,QAAA,OAAA,GAAU,MAAO,CAAA,EAAA,CAAA;AAAA,OACnB;AACA,MAAI,IAAA,CAAC,WAAY,CAAA,OAAO,CAAG,EAAA;AACzB,QAAA,WAAA,CAAY,OAAO,CAAI,GAAA;AAAA,UACrB,EAAI,EAAA,OAAA;AAAA,UACJ,SAAS,EAAC;AAAA,SACZ,CAAA;AAAA,OACF;AAEA,MAAA,MAAA,CAAO,IAAK,CAAA,MAAA,CAAO,OAAO,CAAA,CAAE,QAAQ,CAAO,GAAA,KAAA;AACzC,QAAA,IAAI,WAAY,CAAA,OAAO,CAAE,CAAA,OAAA,CAAQ,GAAG,CAAG,EAAA;AACrC,UAAA,WAAA,CAAY,OAAO,CAAE,CAAA,OAAA,CAAQ,GAAG,CAAK,IAAA,MAAA,CAAO,QAAQ,GAAG,CAAA,CAAA;AAAA,SAClD,MAAA;AACL,UAAA,WAAA,CAAY,OAAO,CAAE,CAAA,OAAA,CAAQ,GAAG,CAAI,GAAA,MAAA,CAAO,QAAQ,GAAG,CAAA,CAAA;AAAA,SACxD;AAAA,OACD,CAAA,CAAA;AACD,MAAO,OAAA,WAAA,CAAA;AAAA,KACT;AAAA,IACA,EAAC;AAAA,GACH,CAAA;AAEA,EAAO,OAAA,MAAA,CAAO,OAAO,aAAa,CAAA,CAAA;AACpC,EAAA;AAEa,MAAA,oBAAA,GAAuB,CAAC,OAAA,EAAmB,YAAoC,KAAA;AAC1F,EAAA,MAAM,iBAA+C,GAAA,MAAA;AAAA,IACnD,OAAA;AAAA,IACA,CAAC,aAAa,MAAW,KAAA;AACvB,MAAA,IAAI,OAAkB,GAAA,UAAA,CAAA;AACtB,MAAI,IAAA,YAAA,IAAgB,gBAAgB,MAAQ,EAAA;AAC1C,QAAA,OAAA,GAAU,OAAO,YAAY,CAAA,CAAA;AAAA,OAC/B,MAAA,IAAW,iBAAiB,MAAQ,EAAA;AAClC,QAAU,OAAA,GAAA,mBAAA,CAAA;AAAA,OACZ;AAEA,MAAI,IAAA,CAAC,WAAY,CAAA,OAAO,CAAG,EAAA;AACzB,QAAA,WAAA,CAAY,OAAO,CAAI,GAAA;AAAA,UACrB,EAAI,EAAA,OAAA;AAAA,UACJ,SAAS,EAAC;AAAA,SACZ,CAAA;AAMA,QAAA,IAAI,iBAAiB,KAAW,CAAA,EAAA;AAC9B,UAAY,WAAA,CAAA,OAAO,CAAE,CAAA,YAAY,CAAI,GAAA,OAAA,CAAA;AAAA,SACvC;AAAA,OACF;AAEA,MAAA,MAAA,CAAO,IAAK,CAAA,MAAA,CAAO,OAAO,CAAA,CAAE,QAAQ,CAAO,GAAA,KAAA;AACzC,QAAA,IAAI,WAAY,CAAA,OAAO,CAAE,CAAA,OAAA,CAAQ,GAAG,CAAG,EAAA;AACrC,UAAA,WAAA,CAAY,OAAO,CAAE,CAAA,OAAA,CAAQ,GAAG,CAAK,IAAA,MAAA,CAAO,QAAQ,GAAG,CAAA,CAAA;AAAA,SAClD,MAAA;AACL,UAAA,WAAA,CAAY,OAAO,CAAE,CAAA,OAAA,CAAQ,GAAG,CAAI,GAAA,MAAA,CAAO,QAAQ,GAAG,CAAA,CAAA;AAAA,SACxD;AAAA,OACD,CAAA,CAAA;AACD,MAAO,OAAA,WAAA,CAAA;AAAA,KACT;AAAA,IACA,EAAC;AAAA,GACH,CAAA;AACA,EAAO,OAAA,MAAA,CAAO,OAAO,iBAAiB,CAAA,CAAA;AACxC,EAAA;AAEa,MAAA,gBAAA,GAAmB,CAAC,OAAgC,KAAA;AAC/D,EAAM,MAAA,IAAA,uBAAW,GAAY,EAAA,CAAA;AAC7B,EAAA,MAAM,eAAe,CAAC,IAAA,EAAM,QAAQ,SAAW,EAAA,UAAA,EAAY,YAAY,SAAS,CAAA,CAAA;AAChF,EAAA,OAAA,CAAQ,QAAQ,CAAU,MAAA,KAAA;AACxB,IAAA,MAAA,CAAO,IAAK,CAAA,MAAM,CAAE,CAAA,OAAA,CAAQ,CAAO,GAAA,KAAA;AACjC,MAAA,IAAI,YAAa,CAAA,OAAA,CAAQ,GAAG,CAAA,KAAM,CAAI,CAAA,EAAA;AACpC,QAAA,IAAA,CAAK,IAAI,GAAG,CAAA,CAAA;AAAA,OACd;AAAA,KACD,CAAA,CAAA;AAAA,GACF,CAAA,CAAA;AACD,EAAO,OAAA,KAAA,CAAM,KAAK,IAAI,CAAA,CAAA;AACxB,EAAA;AAEa,MAAA,gBAAA,GAAmB,CAAC,KAA0B,KAAA;AACzD,EAAA,MAAM,OAAO,KAAM,CAAA,KAAA,EAAO,SAAW,kBAAA,IAAI,MAAM,CAAA,CAAA;AAC/C,EAAM,MAAA,aAAA,GAAgB,SAAU,CAAA,IAAA,EAAM,CAAC,CAAA,CAAA;AACvC,EAAO,OAAA,MAAA,CAAO,eAAe,SAAS,CAAA,CAAA;AACxC,EAAA;AAEO,MAAM,gBAAmB,GAAA,CAAC,WAAqB,EAAA,SAAA,EAAiB,OAA4B,KAAA;AACjG,EAAA,MAAM,SAAmB,EAAC,CAAA;AAC1B,EAAM,MAAA,OAAA,GAAU,OAAO,SAAS,CAAA,CAAA;AAEhC,EAAO,OAAA,OAAA,CAAQ,eAAe,OAAO,CAAA,IAAK,QAAQ,cAAe,CAAA,MAAA,EAAQ,CAAG,EAAA;AAC1E,IAAA,IAAI,gBAAgB,SAAW,EAAA;AAC7B,MAAA,MAAA,CAAO,IAAK,CAAA,OAAA,CAAQ,MAAO,CAAA,SAAS,CAAC,CAAA,CAAA;AACrC,MAAQ,OAAA,CAAA,GAAA,CAAI,GAAG,QAAQ,CAAA,CAAA;AAAA,KAClB,MAAA;AACL,MAAA,MAAA,CAAO,IAAK,CAAA,OAAA,CAAQ,MAAO,CAAA,YAAY,CAAC,CAAA,CAAA;AACxC,MAAQ,OAAA,CAAA,GAAA,CAAI,GAAG,MAAM,CAAA,CAAA;AAAA,KACvB;AAAA,GACF;AAEA,EAAO,OAAA,MAAA,CAAA;AACT;;;;"}
@@ -1,10 +1,44 @@
1
- import { Paper } from '@material-ui/core';
2
- import { useTheme, makeStyles } from '@material-ui/core/styles';
1
+ import { Switch, Paper, Grid } from '@material-ui/core';
2
+ import { withStyles, useTheme, makeStyles } from '@material-ui/core/styles';
3
3
  import humanFormat from 'human-format';
4
4
  import React from 'react';
5
5
  import Chart from 'react-apexcharts';
6
6
 
7
+ const Toggle = withStyles((theme) => ({
8
+ root: {
9
+ width: 28,
10
+ height: 16,
11
+ padding: 0,
12
+ display: "flex"
13
+ },
14
+ switchBase: {
15
+ padding: 2,
16
+ color: theme.palette.grey[500],
17
+ "&$checked": {
18
+ transform: "translateX(12px)",
19
+ color: theme.palette.common.white,
20
+ "& + $track": {
21
+ opacity: 1,
22
+ backgroundColor: theme.palette.primary.main,
23
+ borderColor: theme.palette.primary.main
24
+ }
25
+ }
26
+ },
27
+ thumb: {
28
+ width: 12,
29
+ height: 12,
30
+ boxShadow: "none"
31
+ },
32
+ track: {
33
+ border: `1px solid ${theme.palette.grey[500]}`,
34
+ borderRadius: 16 / 2,
35
+ opacity: 1,
36
+ backgroundColor: theme.palette.common.white
37
+ },
38
+ checked: {}
39
+ }))(Switch);
7
40
  const ColumnsChartComponent = ({
41
+ granularitySetter,
8
42
  categories,
9
43
  series,
10
44
  height,
@@ -62,7 +96,7 @@ const ColumnsChartComponent = ({
62
96
  },
63
97
  stacked: true,
64
98
  toolbar: {
65
- show: true
99
+ show: false
66
100
  },
67
101
  events: {
68
102
  dataPointSelection: dataPointSelectionHandler
@@ -75,14 +109,16 @@ const ColumnsChartComponent = ({
75
109
  decimalsInFloat: 2
76
110
  },
77
111
  dataLabels: {
78
- formatter: (val) => {
79
- if (val) {
80
- return `$${humanFormat(val, {
112
+ enabled: false
113
+ },
114
+ tooltip: {
115
+ y: {
116
+ formatter: (value) => {
117
+ return `$${humanFormat(value, {
81
118
  scale: customScale,
82
119
  separator: ""
83
120
  })}`;
84
121
  }
85
- return "null";
86
122
  }
87
123
  },
88
124
  legend: {
@@ -147,21 +183,7 @@ const ColumnsChartComponent = ({
147
183
  },
148
184
  series
149
185
  };
150
- return /* @__PURE__ */ React.createElement(
151
- Paper,
152
- {
153
- className: thumbnail ? classes.thumbnailPaper : classes.fixedHeightPaper
154
- },
155
- /* @__PURE__ */ React.createElement(
156
- Chart,
157
- {
158
- options: state.options,
159
- series: state.series,
160
- type: "bar",
161
- height: height ? height - 50 : 250
162
- }
163
- )
164
- );
186
+ return /* @__PURE__ */ React.createElement(Paper, { className: thumbnail ? classes.thumbnailPaper : classes.fixedHeightPaper }, /* @__PURE__ */ React.createElement(Grid, { container: true, justifyContent: "flex-end", spacing: 1 }, /* @__PURE__ */ React.createElement(Grid, { item: true }, "Monthly"), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Toggle, { onChange: (event) => granularitySetter(event.target.checked ? "daily" : "monthly") })), /* @__PURE__ */ React.createElement(Grid, { item: true }, "Daily")), /* @__PURE__ */ React.createElement(Chart, { options: state.options, series: state.series, type: "bar", height: height ? height - 50 : 250 }));
165
187
  };
166
188
 
167
189
  export { ColumnsChartComponent };
@@ -1 +1 @@
1
- {"version":3,"file":"ColumnsChartComponent.esm.js","sources":["../../../src/components/ColumnsChartComponent/ColumnsChartComponent.tsx"],"sourcesContent":["import { Paper } from '@material-ui/core';\nimport { makeStyles, useTheme } from '@material-ui/core/styles';\nimport humanFormat from 'human-format';\nimport React, { FC } from 'react';\nimport Chart from 'react-apexcharts';\nimport { ColumnsChartComponentProps } from '../types';\n\nexport const ColumnsChartComponent: FC<ColumnsChartComponentProps> = ({\n categories,\n series,\n height,\n thumbnail,\n dataPointSelectionHandler,\n}) => {\n const defaultTheme = useTheme();\n const useStyles = makeStyles({\n fixedHeightPaper: {\n padding: '16px',\n display: 'flex',\n overflow: 'auto',\n flexDirection: 'column',\n height: height ? height : 300,\n },\n thumbnailPaper: {\n display: 'flex',\n overflow: 'auto',\n flexDirection: 'column',\n height: height ? height - 50 : 100,\n },\n });\n const classes = useStyles();\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: true,\n },\n events: {\n dataPointSelection: dataPointSelectionHandler,\n },\n },\n xaxis: {\n categories: categories,\n },\n yaxis: {\n decimalsInFloat: 2,\n },\n dataLabels: {\n formatter: (val: number) => {\n if (val) {\n return `$${humanFormat(val, {\n scale: customScale,\n separator: '',\n })}`;\n }\n return 'null';\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: [\n '#008FFB',\n '#00E396',\n '#FEB019',\n '#FF4560',\n '#775DD0',\n '#3F51B5',\n '#03A9F4',\n '#4CAF50',\n '#F9CE1D',\n '#FF9800',\n '#33B2DF',\n '#546E7A',\n '#D4526E',\n '#13D8AA',\n '#A5978B',\n '#4ECDC4',\n '#C7F464',\n '#81D4FA',\n '#546E7A',\n '#FD6A6A',\n '#2B908F',\n '#F9A3A4',\n '#90EE7E',\n '#FA4443',\n '#69D2E7',\n '#449DD1',\n '#F86624',\n '#EA3546',\n '#662E9B',\n '#C5D86D',\n '#D7263D',\n '#1B998B',\n '#2E294E',\n '#F46036',\n '#E2C044',\n '#662E9B',\n '#F86624',\n '#F9C80E',\n '#EA3546',\n '#43BCCD',\n '#5C4742',\n '#A5978B',\n '#8D5B4C',\n '#5A2A27',\n '#C4BBAF',\n '#A300D6',\n '#7D02EB',\n '#5653FE',\n '#2983FF',\n '#00B1F2',\n ],\n },\n series: series,\n };\n\n return (\n <Paper\n className={thumbnail ? classes.thumbnailPaper : classes.fixedHeightPaper}\n >\n <Chart\n options={state.options}\n series={state.series}\n type=\"bar\"\n height={height ? height - 50 : 250}\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 { withStyles, makeStyles, useTheme } from '@material-ui/core/styles';\nimport humanFormat from 'human-format';\nimport React, { FC } from 'react';\nimport Chart from 'react-apexcharts';\nimport { ColumnsChartComponentProps } from '../types';\n\nconst Toggle = withStyles(theme => ({\n root: {\n width: 28,\n height: 16,\n padding: 0,\n display: 'flex',\n },\n switchBase: {\n padding: 2,\n color: theme.palette.grey[500],\n '&$checked': {\n transform: 'translateX(12px)',\n color: theme.palette.common.white,\n '& + $track': {\n opacity: 1,\n backgroundColor: theme.palette.primary.main,\n borderColor: theme.palette.primary.main,\n },\n },\n },\n thumb: {\n width: 12,\n height: 12,\n boxShadow: 'none',\n },\n track: {\n border: `1px solid ${theme.palette.grey[500]}`,\n borderRadius: 16 / 2,\n opacity: 1,\n backgroundColor: theme.palette.common.white,\n },\n checked: {},\n}))(Switch);\n\nexport const ColumnsChartComponent: FC<ColumnsChartComponentProps> = ({\n granularitySetter,\n categories,\n series,\n height,\n thumbnail,\n dataPointSelectionHandler,\n}) => {\n const defaultTheme = useTheme();\n const useStyles = makeStyles({\n fixedHeightPaper: {\n padding: '16px',\n display: 'flex',\n overflow: 'auto',\n flexDirection: 'column',\n height: height ? height : 300,\n },\n thumbnailPaper: {\n display: 'flex',\n overflow: 'auto',\n flexDirection: 'column',\n height: height ? height - 50 : 100,\n },\n });\n const classes = useStyles();\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 yaxis: {\n decimalsInFloat: 2,\n },\n dataLabels: {\n enabled: false,\n },\n tooltip: {\n y: {\n formatter: (value: number) => {\n return `$${humanFormat(value, {\n scale: customScale,\n separator: '',\n })}`;\n },\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: [\n '#008FFB',\n '#00E396',\n '#FEB019',\n '#FF4560',\n '#775DD0',\n '#3F51B5',\n '#03A9F4',\n '#4CAF50',\n '#F9CE1D',\n '#FF9800',\n '#33B2DF',\n '#546E7A',\n '#D4526E',\n '#13D8AA',\n '#A5978B',\n '#4ECDC4',\n '#C7F464',\n '#81D4FA',\n '#546E7A',\n '#FD6A6A',\n '#2B908F',\n '#F9A3A4',\n '#90EE7E',\n '#FA4443',\n '#69D2E7',\n '#449DD1',\n '#F86624',\n '#EA3546',\n '#662E9B',\n '#C5D86D',\n '#D7263D',\n '#1B998B',\n '#2E294E',\n '#F46036',\n '#E2C044',\n '#662E9B',\n '#F86624',\n '#F9C80E',\n '#EA3546',\n '#43BCCD',\n '#5C4742',\n '#A5978B',\n '#8D5B4C',\n '#5A2A27',\n '#C4BBAF',\n '#A300D6',\n '#7D02EB',\n '#5653FE',\n '#2983FF',\n '#00B1F2',\n ],\n },\n series: series,\n };\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 <Toggle onChange={event => granularitySetter(event.target.checked ? 'daily' : 'monthly')} />\n </Grid>\n <Grid item>Daily</Grid>\n </Grid>\n <Chart options={state.options} series={state.series} type=\"bar\" height={height ? height - 50 : 250} />\n </Paper>\n );\n};\n"],"names":[],"mappings":"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"}