@backstage-community/plugin-cost-insights 0.12.25 → 0.12.26

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 (230) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/alerts/ProjectGrowthAlert.esm.js +24 -0
  3. package/dist/alerts/ProjectGrowthAlert.esm.js.map +1 -0
  4. package/dist/alerts/UnlabeledDataflowAlert.esm.js +25 -0
  5. package/dist/alerts/UnlabeledDataflowAlert.esm.js.map +1 -0
  6. package/dist/api/CostInsightsApi.esm.js +8 -0
  7. package/dist/api/CostInsightsApi.esm.js.map +1 -0
  8. package/dist/components/ActionItems/ActionItemCard.esm.js +46 -0
  9. package/dist/components/ActionItems/ActionItemCard.esm.js.map +1 -0
  10. package/dist/components/ActionItems/ActionItems.esm.js +90 -0
  11. package/dist/components/ActionItems/ActionItems.esm.js.map +1 -0
  12. package/dist/components/AlertInsights/AlertDialog.esm.js +123 -0
  13. package/dist/components/AlertInsights/AlertDialog.esm.js.map +1 -0
  14. package/dist/components/AlertInsights/AlertInsights.esm.js +157 -0
  15. package/dist/components/AlertInsights/AlertInsights.esm.js.map +1 -0
  16. package/dist/components/AlertInsights/AlertInsightsHeader.esm.js +17 -0
  17. package/dist/components/AlertInsights/AlertInsightsHeader.esm.js.map +1 -0
  18. package/dist/components/AlertInsights/AlertInsightsSection.esm.js +57 -0
  19. package/dist/components/AlertInsights/AlertInsightsSection.esm.js.map +1 -0
  20. package/dist/components/AlertInsights/AlertInsightsSectionHeader.esm.js +30 -0
  21. package/dist/components/AlertInsights/AlertInsightsSectionHeader.esm.js.map +1 -0
  22. package/dist/components/AlertInsights/AlertStatusSummary.esm.js +93 -0
  23. package/dist/components/AlertInsights/AlertStatusSummary.esm.js.map +1 -0
  24. package/dist/components/AlertInsights/AlertStatusSummaryButton.esm.js +35 -0
  25. package/dist/components/AlertInsights/AlertStatusSummaryButton.esm.js.map +1 -0
  26. package/dist/components/AlertInstructionsLayout/AlertInstructionsLayout.esm.js +47 -0
  27. package/dist/components/AlertInstructionsLayout/AlertInstructionsLayout.esm.js.map +1 -0
  28. package/dist/components/BarChart/BarChart.esm.js +167 -0
  29. package/dist/components/BarChart/BarChart.esm.js.map +1 -0
  30. package/dist/components/BarChart/BarChartLabel.esm.js +31 -0
  31. package/dist/components/BarChart/BarChartLabel.esm.js.map +1 -0
  32. package/dist/components/BarChart/BarChartLegend.esm.js +47 -0
  33. package/dist/components/BarChart/BarChartLegend.esm.js.map +1 -0
  34. package/dist/components/BarChart/BarChartStepper.esm.js +91 -0
  35. package/dist/components/BarChart/BarChartStepper.esm.js.map +1 -0
  36. package/dist/components/BarChart/BarChartStepperButton.esm.js +27 -0
  37. package/dist/components/BarChart/BarChartStepperButton.esm.js.map +1 -0
  38. package/dist/components/BarChart/BarChartSteps.esm.js +25 -0
  39. package/dist/components/BarChart/BarChartSteps.esm.js.map +1 -0
  40. package/dist/components/BarChart/BarChartTick.esm.js +29 -0
  41. package/dist/components/BarChart/BarChartTick.esm.js.map +1 -0
  42. package/dist/components/BarChart/BarChartTooltip.esm.js +30 -0
  43. package/dist/components/BarChart/BarChartTooltip.esm.js.map +1 -0
  44. package/dist/components/BarChart/BarChartTooltipItem.esm.js +24 -0
  45. package/dist/components/BarChart/BarChartTooltipItem.esm.js.map +1 -0
  46. package/dist/components/CopyUrlToClipboard/CopyUrlToClipboard.esm.js +44 -0
  47. package/dist/components/CopyUrlToClipboard/CopyUrlToClipboard.esm.js.map +1 -0
  48. package/dist/components/CostGrowth/CostGrowth.esm.js +55 -0
  49. package/dist/components/CostGrowth/CostGrowth.esm.js.map +1 -0
  50. package/dist/components/CostGrowth/CostGrowthIndicator.esm.js +31 -0
  51. package/dist/components/CostGrowth/CostGrowthIndicator.esm.js.map +1 -0
  52. package/dist/components/CostInsightsHeader/CostInsightsHeader.esm.js +57 -0
  53. package/dist/components/CostInsightsHeader/CostInsightsHeader.esm.js.map +1 -0
  54. package/dist/components/CostInsightsLayout/CostInsightsLayout.esm.js +35 -0
  55. package/dist/components/CostInsightsLayout/CostInsightsLayout.esm.js.map +1 -0
  56. package/dist/components/CostInsightsNavigation/CostInsightsNavigation.esm.js +87 -0
  57. package/dist/components/CostInsightsNavigation/CostInsightsNavigation.esm.js.map +1 -0
  58. package/dist/components/CostInsightsPage/CostInsightsPage.esm.js +229 -0
  59. package/dist/components/CostInsightsPage/CostInsightsPage.esm.js.map +1 -0
  60. package/dist/components/CostInsightsPage/CostInsightsPageRoot.esm.js +15 -0
  61. package/dist/components/CostInsightsPage/CostInsightsPageRoot.esm.js.map +1 -0
  62. package/dist/components/CostInsightsPage/CostInsightsThemeProvider.esm.js +24 -0
  63. package/dist/components/CostInsightsPage/CostInsightsThemeProvider.esm.js.map +1 -0
  64. package/dist/components/CostInsightsPage/index.esm.js +2 -0
  65. package/dist/components/CostInsightsPage/index.esm.js.map +1 -0
  66. package/dist/components/CostInsightsPage/selector.esm.js +15 -0
  67. package/dist/components/CostInsightsPage/selector.esm.js.map +1 -0
  68. package/dist/components/CostInsightsTabs/CostInsightsTabs.esm.js +89 -0
  69. package/dist/components/CostInsightsTabs/CostInsightsTabs.esm.js.map +1 -0
  70. package/dist/components/CostInsightsTabs/selector.esm.js +17 -0
  71. package/dist/components/CostInsightsTabs/selector.esm.js.map +1 -0
  72. package/dist/components/CostOverviewCard/CostOverviewBreakdownChart.esm.js +196 -0
  73. package/dist/components/CostOverviewCard/CostOverviewBreakdownChart.esm.js.map +1 -0
  74. package/dist/components/CostOverviewCard/CostOverviewCard.esm.js +99 -0
  75. package/dist/components/CostOverviewCard/CostOverviewCard.esm.js.map +1 -0
  76. package/dist/components/CostOverviewCard/CostOverviewChart.esm.js +157 -0
  77. package/dist/components/CostOverviewCard/CostOverviewChart.esm.js.map +1 -0
  78. package/dist/components/CostOverviewCard/CostOverviewHeader.esm.js +25 -0
  79. package/dist/components/CostOverviewCard/CostOverviewHeader.esm.js.map +1 -0
  80. package/dist/components/CostOverviewCard/CostOverviewLegend.esm.js +54 -0
  81. package/dist/components/CostOverviewCard/CostOverviewLegend.esm.js.map +1 -0
  82. package/dist/components/CostOverviewCard/selector.esm.js +22 -0
  83. package/dist/components/CostOverviewCard/selector.esm.js.map +1 -0
  84. package/dist/components/CurrencySelect/CurrencySelect.esm.js +52 -0
  85. package/dist/components/CurrencySelect/CurrencySelect.esm.js.map +1 -0
  86. package/dist/{esm/index-BPzWHt3A.esm.js → components/EntityCosts/EntityCosts.esm.js} +14 -80
  87. package/dist/{esm/index-BPzWHt3A.esm.js.map → components/EntityCosts/EntityCosts.esm.js.map} +1 -1
  88. package/dist/components/EntityCosts/index.esm.js +2 -0
  89. package/dist/components/EntityCosts/index.esm.js.map +1 -0
  90. package/dist/{esm/index-BA6m_qFS.esm.js → components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.esm.js} +2 -79
  91. package/dist/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.esm.js.map +1 -0
  92. package/dist/components/LabelDataflowInstructionsPage/index.esm.js +2 -0
  93. package/dist/components/LabelDataflowInstructionsPage/index.esm.js.map +1 -0
  94. package/dist/components/LegendItem/LegendItem.esm.js +44 -0
  95. package/dist/components/LegendItem/LegendItem.esm.js.map +1 -0
  96. package/dist/components/MetricSelect/MetricSelect.esm.js +37 -0
  97. package/dist/components/MetricSelect/MetricSelect.esm.js.map +1 -0
  98. package/dist/components/PeriodSelect/PeriodSelect.esm.js +72 -0
  99. package/dist/components/PeriodSelect/PeriodSelect.esm.js.map +1 -0
  100. package/dist/components/ProductInsights/ProductInsights.esm.js +98 -0
  101. package/dist/components/ProductInsights/ProductInsights.esm.js.map +1 -0
  102. package/dist/components/ProductInsightsCard/ProductEntityDialog.esm.js +42 -0
  103. package/dist/components/ProductInsightsCard/ProductEntityDialog.esm.js.map +1 -0
  104. package/dist/components/ProductInsightsCard/ProductEntityTable.esm.js +139 -0
  105. package/dist/components/ProductInsightsCard/ProductEntityTable.esm.js.map +1 -0
  106. package/dist/components/ProductInsightsCard/ProductInsightsCard.esm.js +83 -0
  107. package/dist/components/ProductInsightsCard/ProductInsightsCard.esm.js.map +1 -0
  108. package/dist/components/ProductInsightsCard/ProductInsightsCardList.esm.js +34 -0
  109. package/dist/components/ProductInsightsCard/ProductInsightsCardList.esm.js.map +1 -0
  110. package/dist/components/ProductInsightsCard/ProductInsightsChart.esm.js +148 -0
  111. package/dist/components/ProductInsightsCard/ProductInsightsChart.esm.js.map +1 -0
  112. package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertCard.esm.js +20 -0
  113. package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertCard.esm.js.map +1 -0
  114. package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertChart.esm.js +46 -0
  115. package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertChart.esm.js.map +1 -0
  116. package/dist/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.esm.js +111 -0
  117. package/dist/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.esm.js.map +1 -0
  118. package/dist/components/ProjectGrowthInstructionsPage/index.esm.js +2 -0
  119. package/dist/components/ProjectGrowthInstructionsPage/index.esm.js.map +1 -0
  120. package/dist/components/ProjectSelect/ProjectSelect.esm.js +47 -0
  121. package/dist/components/ProjectSelect/ProjectSelect.esm.js.map +1 -0
  122. package/dist/components/UnlabeledDataflowAlertCard/UnlabeledDataflowAlertCard.esm.js +41 -0
  123. package/dist/components/UnlabeledDataflowAlertCard/UnlabeledDataflowAlertCard.esm.js.map +1 -0
  124. package/dist/components/WhyCostsMatter/WhyCostsMatter.esm.js +21 -0
  125. package/dist/components/WhyCostsMatter/WhyCostsMatter.esm.js.map +1 -0
  126. package/dist/example/alerts/KubernetesMigrationAlert.esm.js +86 -0
  127. package/dist/example/alerts/KubernetesMigrationAlert.esm.js.map +1 -0
  128. package/dist/example/client.esm.js +194 -0
  129. package/dist/example/client.esm.js.map +1 -0
  130. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationAlertCard.esm.js +33 -0
  131. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationAlertCard.esm.js.map +1 -0
  132. package/dist/{esm/index-BTIHr4n_.esm.js → example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChart.esm.js} +69 -48
  133. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChart.esm.js.map +1 -0
  134. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChartLegend.esm.js +107 -0
  135. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChartLegend.esm.js.map +1 -0
  136. package/dist/example/forms/KubernetesMigrationDismissForm.esm.js +57 -0
  137. package/dist/example/forms/KubernetesMigrationDismissForm.esm.js.map +1 -0
  138. package/dist/forms/AlertAcceptForm.esm.js +27 -0
  139. package/dist/forms/AlertAcceptForm.esm.js.map +1 -0
  140. package/dist/forms/AlertDismissForm.esm.js +100 -0
  141. package/dist/forms/AlertDismissForm.esm.js.map +1 -0
  142. package/dist/forms/AlertSnoozeForm.esm.js +52 -0
  143. package/dist/forms/AlertSnoozeForm.esm.js.map +1 -0
  144. package/dist/hooks/useConfig.esm.js +153 -0
  145. package/dist/hooks/useConfig.esm.js.map +1 -0
  146. package/dist/hooks/useCurrency.esm.js +26 -0
  147. package/dist/hooks/useCurrency.esm.js.map +1 -0
  148. package/dist/hooks/useFilters.esm.js +67 -0
  149. package/dist/hooks/useFilters.esm.js.map +1 -0
  150. package/dist/hooks/useGroups.esm.js +55 -0
  151. package/dist/hooks/useGroups.esm.js.map +1 -0
  152. package/dist/hooks/useLastCompleteBillingDate.esm.js +65 -0
  153. package/dist/hooks/useLastCompleteBillingDate.esm.js.map +1 -0
  154. package/dist/hooks/useLoading.esm.js +54 -0
  155. package/dist/hooks/useLoading.esm.js.map +1 -0
  156. package/dist/hooks/useScroll.esm.js +24 -0
  157. package/dist/hooks/useScroll.esm.js.map +1 -0
  158. package/dist/index.esm.js +37 -22
  159. package/dist/index.esm.js.map +1 -1
  160. package/dist/plugin.esm.js +55 -0
  161. package/dist/plugin.esm.js.map +1 -0
  162. package/dist/testUtils/filters.esm.js +8 -0
  163. package/dist/testUtils/filters.esm.js.map +1 -0
  164. package/dist/testUtils/loading.esm.js +14 -0
  165. package/dist/testUtils/loading.esm.js.map +1 -0
  166. package/dist/testUtils/mockData.esm.js +485 -0
  167. package/dist/testUtils/mockData.esm.js.map +1 -0
  168. package/dist/testUtils/products.esm.js +49 -0
  169. package/dist/testUtils/products.esm.js.map +1 -0
  170. package/dist/testUtils/providers.esm.js +41 -0
  171. package/dist/testUtils/providers.esm.js.map +1 -0
  172. package/dist/testUtils/testUtils.esm.js +142 -0
  173. package/dist/testUtils/testUtils.esm.js.map +1 -0
  174. package/dist/types/Alert.esm.js +66 -0
  175. package/dist/types/Alert.esm.js.map +1 -0
  176. package/dist/types/ChangeStatistic.esm.js +15 -0
  177. package/dist/types/ChangeStatistic.esm.js.map +1 -0
  178. package/dist/types/CurrencyType.esm.js +10 -0
  179. package/dist/types/CurrencyType.esm.js.map +1 -0
  180. package/dist/types/DateFormat.esm.js +4 -0
  181. package/dist/types/DateFormat.esm.js.map +1 -0
  182. package/dist/types/Duration.esm.js +10 -0
  183. package/dist/types/Duration.esm.js.map +1 -0
  184. package/dist/types/Icon.esm.js +12 -0
  185. package/dist/types/Icon.esm.js.map +1 -0
  186. package/dist/utils/alerts.esm.js +72 -0
  187. package/dist/utils/alerts.esm.js.map +1 -0
  188. package/dist/utils/assert.esm.js +29 -0
  189. package/dist/utils/assert.esm.js.map +1 -0
  190. package/dist/utils/change.esm.js +58 -0
  191. package/dist/utils/change.esm.js.map +1 -0
  192. package/dist/utils/charts.esm.js +9 -0
  193. package/dist/utils/charts.esm.js.map +1 -0
  194. package/dist/utils/config.esm.js +19 -0
  195. package/dist/utils/config.esm.js.map +1 -0
  196. package/dist/utils/currency.esm.js +56 -0
  197. package/dist/utils/currency.esm.js.map +1 -0
  198. package/dist/utils/duration.esm.js +55 -0
  199. package/dist/utils/duration.esm.js.map +1 -0
  200. package/dist/utils/filters.esm.js +14 -0
  201. package/dist/utils/filters.esm.js.map +1 -0
  202. package/dist/utils/formatters.esm.js +103 -0
  203. package/dist/utils/formatters.esm.js.map +1 -0
  204. package/dist/utils/grammar.esm.js +14 -0
  205. package/dist/utils/grammar.esm.js.map +1 -0
  206. package/dist/utils/graphs.esm.js +48 -0
  207. package/dist/utils/graphs.esm.js.map +1 -0
  208. package/dist/utils/history.esm.js +32 -0
  209. package/dist/utils/history.esm.js.map +1 -0
  210. package/dist/utils/loading.esm.js +51 -0
  211. package/dist/utils/loading.esm.js.map +1 -0
  212. package/dist/utils/navigation.esm.js +56 -0
  213. package/dist/utils/navigation.esm.js.map +1 -0
  214. package/dist/utils/scroll.esm.js +38 -0
  215. package/dist/utils/scroll.esm.js.map +1 -0
  216. package/dist/utils/sort.esm.js +10 -0
  217. package/dist/utils/sort.esm.js.map +1 -0
  218. package/dist/utils/styles.esm.js +562 -0
  219. package/dist/utils/styles.esm.js.map +1 -0
  220. package/dist/utils/sum.esm.js +4 -0
  221. package/dist/utils/sum.esm.js.map +1 -0
  222. package/package.json +17 -12
  223. package/dist/esm/index-BA6m_qFS.esm.js.map +0 -1
  224. package/dist/esm/index-BFM2mP6Z.esm.js +0 -4084
  225. package/dist/esm/index-BFM2mP6Z.esm.js.map +0 -1
  226. package/dist/esm/index-BTIHr4n_.esm.js.map +0 -1
  227. package/dist/esm/index-DaitkcPN.esm.js +0 -1136
  228. package/dist/esm/index-DaitkcPN.esm.js.map +0 -1
  229. package/dist/esm/selector-D7iXJwd9.esm.js +0 -594
  230. package/dist/esm/selector-D7iXJwd9.esm.js.map +0 -1
@@ -1,1136 +0,0 @@
1
- import React, { Fragment, useState, useRef, useEffect, useCallback, useMemo } from 'react';
2
- import Box from '@material-ui/core/Box';
3
- import Collapse from '@material-ui/core/Collapse';
4
- import Container from '@material-ui/core/Container';
5
- import Divider from '@material-ui/core/Divider';
6
- import Grid from '@material-ui/core/Grid';
7
- import Typography from '@material-ui/core/Typography';
8
- import Alert from '@material-ui/lab/Alert';
9
- import { O as useActionItemCardStyles, f as useScroll, Q as AlertStatus, R as ScrollType, T as useAlertDialogStyles, U as choose, V as formOf, W as useAlertStatusSummaryButtonStyles, X as useCostInsightsStyles, J as DefaultNavigation, Y as useAlertInsightsSectionStyles, Z as isSnoozeEnabled, _ as isAcceptEnabled, $ as isDismissEnabled, u as useLoading, a0 as isStatusSnoozed, a1 as isStatusAccepted, a2 as isStatusDismissed, a3 as sumOfAllAlerts, K as DefaultLoadingAction, y as useSelectStyles, H as findAlways, a4 as useProductInsightsCardStyles, d as useLastCompleteBillingDate, a5 as findAnyKey, a6 as ProductInsightsChart, c as costInsightsApiRef, i as intervalsOf, a7 as DEFAULT_DURATION, a8 as settledResponseOf, a9 as initialStatesOf, aa as totalAggregationSort, ab as useSubtleTypographyStyles, n as useConfig, ac as useGroups, ad as useCurrency, e as useFilters, ae as isAlertActive, af as isAlertSnoozed, ag as isAlertAccepted, ah as isAlertDismissed, ai as CostInsightsLayout, aj as CostInsightsNavigation, C as CostInsightsThemeProvider, a as ConfigProvider, L as LoadingProvider, G as GroupsProvider, B as BillingDateProvider, F as FilterProvider, S as ScrollProvider, b as CurrencyProvider } from './index-BFM2mP6Z.esm.js';
10
- import Avatar from '@material-ui/core/Avatar';
11
- import Tooltip from '@material-ui/core/Tooltip';
12
- import IconButton from '@material-ui/core/IconButton';
13
- import Badge from '@material-ui/core/Badge';
14
- import Paper from '@material-ui/core/Paper';
15
- import SnoozeIcon from '@material-ui/icons/AccessTime';
16
- import AcceptIcon from '@material-ui/icons/Check';
17
- import DismissIcon from '@material-ui/icons/Delete';
18
- import classnames from 'classnames';
19
- import Card from '@material-ui/core/Card';
20
- import CardHeader from '@material-ui/core/CardHeader';
21
- import pluralize from 'pluralize';
22
- import Snackbar from '@material-ui/core/Snackbar';
23
- import { capitalize } from '@material-ui/core/utils';
24
- import Button from '@material-ui/core/Button';
25
- import Dialog from '@material-ui/core/Dialog';
26
- import DialogActions from '@material-ui/core/DialogActions';
27
- import DialogContent from '@material-ui/core/DialogContent';
28
- import CloseIcon from '@material-ui/icons/Close';
29
- import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
30
- import { S as ScrollAnchor, P as PeriodSelect, C as CostOverviewCard, m as mapLoadingToProps$2 } from './selector-D7iXJwd9.esm.js';
31
- import { useLocation } from 'react-router-dom';
32
- import useCopyToClipboard from 'react-use/esm/useCopyToClipboard';
33
- import AssignmentOutlinedIcon from '@material-ui/icons/AssignmentOutlined';
34
- import AssignmentTurnedInOutlinedIcon from '@material-ui/icons/AssignmentTurnedInOutlined';
35
- import SentimentVeryDissatisfiedIcon from '@material-ui/icons/SentimentVeryDissatisfied';
36
- import InputLabel from '@material-ui/core/InputLabel';
37
- import Select from '@material-ui/core/Select';
38
- import FormControl from '@material-ui/core/FormControl';
39
- import MenuItem from '@material-ui/core/MenuItem';
40
- import useAsync from 'react-use/esm/useAsync';
41
- import { useApi, identityApiRef } from '@backstage/core-plugin-api';
42
- import CircularProgress from '@material-ui/core/CircularProgress';
43
- import { InfoCard, Progress } from '@backstage/core-components';
44
- import '@material-ui/core/styles';
45
- import '@material-ui/icons/MonetizationOn';
46
- import '@material-ui/icons/Whatshot';
47
- import '@material-ui/icons/Settings';
48
- import '@material-ui/icons/AccountTree';
49
- import '@material-ui/icons/Storage';
50
- import '@material-ui/icons/Search';
51
- import '@material-ui/icons/CloudQueue';
52
- import '@material-ui/icons/School';
53
- import '@material-ui/icons/ViewHeadline';
54
- import 'qs';
55
- import 'yup';
56
- import '@material-ui/core/Backdrop';
57
- import 'luxon';
58
- import '@material-ui/core/styles/colorManipulator';
59
- import '@backstage/catalog-model';
60
- import '@material-ui/core/Checkbox';
61
- import '@material-ui/core/FormControlLabel';
62
- import '@material-ui/core/RadioGroup';
63
- import '@material-ui/core/Radio';
64
- import '@material-ui/core/TextField';
65
- import '@material-ui/icons/ChevronLeft';
66
- import 'recharts';
67
- import '@material-ui/core/Slide';
68
- import '@material-ui/icons/ChevronRight';
69
- import '@material-ui/core/ButtonBase';
70
- import '@material-ui/icons/Lens';
71
- import '@material-ui/icons/HelpOutlineOutlined';
72
- import '@material-ui/icons/ArrowDropUp';
73
- import '@material-ui/icons/ArrowDropDown';
74
- import '@material-ui/core/Menu';
75
- import '@material-ui/core/Tab';
76
- import '@material-ui/core/Tabs';
77
- import '@material-ui/core/MenuList';
78
- import '@material-ui/core/ListItemIcon';
79
- import '@material-ui/core/ListItemText';
80
- import '@material-ui/core/CardContent';
81
- import '@material-ui/icons/Fullscreen';
82
- import '@material-ui/core/FormGroup';
83
- import 'regression';
84
-
85
- const ActionItemCard = ({
86
- alert,
87
- avatar,
88
- number,
89
- disableScroll = false
90
- }) => {
91
- const classes = useActionItemCardStyles();
92
- const rootClasses = classnames(classes.root, {
93
- [classes.activeRoot]: !disableScroll
94
- });
95
- const [, setScroll] = useScroll();
96
- const onActionItemClick = () => {
97
- if (!disableScroll && number) {
98
- setScroll(`alert-${number}`);
99
- }
100
- };
101
- return /* @__PURE__ */ React.createElement(Card, { className: classes.card, raised: false, onClick: onActionItemClick }, /* @__PURE__ */ React.createElement(
102
- CardHeader,
103
- {
104
- classes: {
105
- root: rootClasses,
106
- action: classes.action,
107
- title: classes.title
108
- },
109
- title: alert.title,
110
- subheader: alert.subtitle,
111
- avatar
112
- }
113
- ));
114
- };
115
-
116
- const AlertStatusButton = ({
117
- title,
118
- amount,
119
- icon,
120
- onClick,
121
- ...buttonProps
122
- }) => /* @__PURE__ */ React.createElement(Tooltip, { title }, /* @__PURE__ */ React.createElement(
123
- IconButton,
124
- {
125
- onClick,
126
- role: "button",
127
- "aria-hidden": false,
128
- ...buttonProps
129
- },
130
- /* @__PURE__ */ React.createElement(Badge, { badgeContent: amount }, icon)
131
- ));
132
- const ActionItems = ({
133
- active,
134
- snoozed,
135
- accepted,
136
- dismissed
137
- }) => {
138
- const classes = useActionItemCardStyles();
139
- const [, setScroll] = useScroll();
140
- const isSnoozedButtonDisplayed = !!snoozed.length;
141
- const isAcceptedButtonDisplayed = !!accepted.length;
142
- const isDismissedButtonDisplayed = !!dismissed.length;
143
- const isStatusButtonGroupDisplayed = !!active.length;
144
- const onStatusButtonClick = () => setScroll(ScrollType.AlertSummary);
145
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Paper, null, active.map((alert, index) => /* @__PURE__ */ React.createElement(Fragment, { key: `alert-${index}` }, /* @__PURE__ */ React.createElement(
146
- ActionItemCard,
147
- {
148
- alert,
149
- number: index + 1,
150
- avatar: /* @__PURE__ */ React.createElement(Avatar, { className: classes.avatar }, index + 1)
151
- }
152
- ), index < active.length - 1 && /* @__PURE__ */ React.createElement(Divider, null)))), isStatusButtonGroupDisplayed && /* @__PURE__ */ React.createElement(Box, { display: "flex", justifyContent: "flex-end", mt: 2 }, isAcceptedButtonDisplayed && /* @__PURE__ */ React.createElement(
153
- AlertStatusButton,
154
- {
155
- title: "Accepted",
156
- "aria-label": AlertStatus.Accepted,
157
- icon: /* @__PURE__ */ React.createElement(AcceptIcon, null),
158
- amount: accepted.length,
159
- onClick: onStatusButtonClick
160
- }
161
- ), isSnoozedButtonDisplayed && /* @__PURE__ */ React.createElement(
162
- AlertStatusButton,
163
- {
164
- title: "Snoozed",
165
- "aria-label": AlertStatus.Snoozed,
166
- amount: snoozed.length,
167
- icon: /* @__PURE__ */ React.createElement(SnoozeIcon, null),
168
- onClick: onStatusButtonClick
169
- }
170
- ), isDismissedButtonDisplayed && /* @__PURE__ */ React.createElement(
171
- AlertStatusButton,
172
- {
173
- title: "Dismissed",
174
- "aria-label": AlertStatus.Dismissed,
175
- icon: /* @__PURE__ */ React.createElement(DismissIcon, null),
176
- amount: dismissed.length,
177
- onClick: onStatusButtonClick
178
- }
179
- )));
180
- };
181
-
182
- const DEFAULT_FORM_ID = "alert-form";
183
- const AlertDialog = ({
184
- open,
185
- group,
186
- alert,
187
- status,
188
- onClose,
189
- onSubmit
190
- }) => {
191
- const classes = useAlertDialogStyles();
192
- const [isSubmitDisabled, setSubmitDisabled] = useState(true);
193
- const formRef = useRef(null);
194
- useEffect(() => {
195
- setSubmitDisabled(open);
196
- }, [open]);
197
- function disableSubmit(isDisabled) {
198
- setSubmitDisabled(isDisabled);
199
- }
200
- function onDialogClose() {
201
- onClose();
202
- setSubmitDisabled(true);
203
- }
204
- const [action, actioned] = choose(
205
- status,
206
- [
207
- ["snooze", "snoozed"],
208
- ["accept", "accepted"],
209
- ["dismiss", "dismissed"]
210
- ],
211
- ["", ""]
212
- );
213
- const TransitionProps = {
214
- mountOnEnter: true,
215
- unmountOnExit: true,
216
- onEntered() {
217
- if (formRef.current) {
218
- formRef.current.id = DEFAULT_FORM_ID;
219
- }
220
- }
221
- };
222
- const Form = formOf(alert, status);
223
- return /* @__PURE__ */ React.createElement(
224
- Dialog,
225
- {
226
- open,
227
- onClose: onDialogClose,
228
- scroll: "body",
229
- maxWidth: "lg",
230
- TransitionProps
231
- },
232
- /* @__PURE__ */ React.createElement(Box, { display: "flex", justifyContent: "flex-end" }, /* @__PURE__ */ React.createElement(
233
- IconButton,
234
- {
235
- className: classes.icon,
236
- disableRipple: true,
237
- "aria-label": "Close",
238
- onClick: onDialogClose
239
- },
240
- /* @__PURE__ */ React.createElement(CloseIcon, null)
241
- )),
242
- /* @__PURE__ */ React.createElement(DialogContent, { className: classes.content }, /* @__PURE__ */ React.createElement(Box, { mb: 1.5 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, /* @__PURE__ */ React.createElement("b", null, capitalize(action), " this action item?")), /* @__PURE__ */ React.createElement(Typography, { variant: "h6", color: "textSecondary" }, /* @__PURE__ */ React.createElement("b", null, "This action item will be ", actioned, " for all of ", group, "."))), /* @__PURE__ */ React.createElement(
243
- Box,
244
- {
245
- display: "flex",
246
- flexDirection: "column",
247
- bgcolor: "alertBackground",
248
- p: 2,
249
- mb: 1.5,
250
- borderRadius: 4
251
- },
252
- /* @__PURE__ */ React.createElement(Typography, null, /* @__PURE__ */ React.createElement("b", null, alert == null ? void 0 : alert.title)),
253
- /* @__PURE__ */ React.createElement(Typography, { color: "textSecondary" }, alert == null ? void 0 : alert.subtitle)
254
- ), Form && /* @__PURE__ */ React.createElement(
255
- Form,
256
- {
257
- ref: formRef,
258
- alert,
259
- onSubmit,
260
- disableSubmit
261
- }
262
- )),
263
- /* @__PURE__ */ React.createElement(Divider, null),
264
- /* @__PURE__ */ React.createElement(DialogActions, { className: classes.actions, disableSpacing: true }, Form ? /* @__PURE__ */ React.createElement(
265
- Button,
266
- {
267
- type: "submit",
268
- color: "primary",
269
- variant: "contained",
270
- "aria-label": action,
271
- form: DEFAULT_FORM_ID,
272
- disabled: isSubmitDisabled
273
- },
274
- capitalize(action)
275
- ) : /* @__PURE__ */ React.createElement(
276
- Button,
277
- {
278
- type: "button",
279
- color: "primary",
280
- variant: "contained",
281
- "aria-label": action,
282
- onClick: () => onSubmit(null)
283
- },
284
- capitalize(action)
285
- ))
286
- );
287
- };
288
-
289
- const AlertGroup = ({ alerts, status, title, icon }) => {
290
- const classes = useActionItemCardStyles();
291
- return /* @__PURE__ */ React.createElement(Box, { p: 1 }, alerts.map((alert, index) => /* @__PURE__ */ React.createElement(Fragment, { key: `alert-${status}-${index}` }, /* @__PURE__ */ React.createElement(
292
- ActionItemCard,
293
- {
294
- disableScroll: true,
295
- alert,
296
- avatar: /* @__PURE__ */ React.createElement(Tooltip, { title }, /* @__PURE__ */ React.createElement(Avatar, { className: classes.avatar }, icon))
297
- }
298
- ), index < alerts.length - 1 && /* @__PURE__ */ React.createElement(Divider, null))));
299
- };
300
- const AlertStatusSummary = ({
301
- open,
302
- snoozed,
303
- accepted,
304
- dismissed
305
- }) => {
306
- const isSnoozedListDisplayed = !!snoozed.length;
307
- const isAcceptedListDisplayed = !!accepted.length;
308
- const isDismissedListDisplayed = !!dismissed.length;
309
- return /* @__PURE__ */ React.createElement(Collapse, { in: open }, isAcceptedListDisplayed && /* @__PURE__ */ React.createElement(
310
- AlertGroup,
311
- {
312
- title: "Accepted",
313
- alerts: accepted,
314
- status: AlertStatus.Accepted,
315
- icon: /* @__PURE__ */ React.createElement(
316
- AcceptIcon,
317
- {
318
- role: "img",
319
- "aria-hidden": false,
320
- "aria-label": AlertStatus.Accepted
321
- }
322
- )
323
- }
324
- ), isSnoozedListDisplayed && /* @__PURE__ */ React.createElement(
325
- AlertGroup,
326
- {
327
- title: "Snoozed",
328
- alerts: snoozed,
329
- status: AlertStatus.Snoozed,
330
- icon: /* @__PURE__ */ React.createElement(
331
- SnoozeIcon,
332
- {
333
- role: "img",
334
- "aria-hidden": false,
335
- "aria-label": AlertStatus.Snoozed
336
- }
337
- )
338
- }
339
- ), isDismissedListDisplayed && /* @__PURE__ */ React.createElement(
340
- AlertGroup,
341
- {
342
- title: "Dismissed",
343
- alerts: dismissed,
344
- status: AlertStatus.Dismissed,
345
- icon: /* @__PURE__ */ React.createElement(
346
- DismissIcon,
347
- {
348
- role: "img",
349
- "aria-hidden": false,
350
- "aria-label": AlertStatus.Dismissed
351
- }
352
- )
353
- }
354
- ));
355
- };
356
-
357
- const AlertStatusSummaryButton = ({
358
- children,
359
- onClick
360
- }) => {
361
- const classes = useAlertStatusSummaryButtonStyles();
362
- const [clicked, setClicked] = useState(false);
363
- const iconClassName = classnames(classes.icon, {
364
- [classes.clicked]: clicked
365
- });
366
- const handleOnClick = (e) => {
367
- setClicked((prevClicked) => !prevClicked);
368
- onClick(e);
369
- };
370
- return /* @__PURE__ */ React.createElement(
371
- Button,
372
- {
373
- variant: "text",
374
- color: "primary",
375
- disableElevation: true,
376
- "aria-label": "expand",
377
- endIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, { className: iconClassName }),
378
- onClick: handleOnClick
379
- },
380
- children
381
- );
382
- };
383
-
384
- const AlertInsightsHeader = ({
385
- title,
386
- subtitle
387
- }) => {
388
- const classes = useCostInsightsStyles();
389
- return /* @__PURE__ */ React.createElement(Box, { mb: 6, position: "relative" }, /* @__PURE__ */ React.createElement(ScrollAnchor, { id: DefaultNavigation.AlertInsightsHeader }), /* @__PURE__ */ React.createElement(Typography, { variant: "h4", align: "center" }, title, " ", /* @__PURE__ */ React.createElement(Typography, { component: "span", role: "img", "aria-label": "direct-hit" }, "\u{1F3AF}")), /* @__PURE__ */ React.createElement(Typography, { className: classes.h6Subtle, align: "center", gutterBottom: true }, subtitle));
390
- };
391
-
392
- const AlertInsightsSectionHeader = ({
393
- alert,
394
- number
395
- }) => {
396
- const classes = useAlertInsightsSectionStyles();
397
- const isViewInstructionsButtonDisplayed = !!alert.url;
398
- return /* @__PURE__ */ React.createElement(Box, { position: "relative", mb: 3, textAlign: "left" }, /* @__PURE__ */ React.createElement(ScrollAnchor, { id: `alert-${number}` }), /* @__PURE__ */ React.createElement(
399
- Grid,
400
- {
401
- container: true,
402
- spacing: 2,
403
- justifyContent: "space-between",
404
- alignItems: "center"
405
- },
406
- /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Box, { display: "flex", alignItems: "center" }, /* @__PURE__ */ React.createElement(Box, { mr: 2 }, /* @__PURE__ */ React.createElement(Avatar, { className: classes.button }, number)), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, alert.title), /* @__PURE__ */ React.createElement(Typography, { gutterBottom: true }, alert.subtitle)))),
407
- isViewInstructionsButtonDisplayed && /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Button, { variant: "text", color: "primary", href: alert.url }, alert.buttonText || "View Instructions"))
408
- ));
409
- };
410
-
411
- const AlertInsightsSection = ({
412
- alert,
413
- number,
414
- onSnooze,
415
- onAccept,
416
- onDismiss
417
- }) => {
418
- const isSnoozeButtonDisplayed = isSnoozeEnabled(alert);
419
- const isAcceptButtonDisplayed = isAcceptEnabled(alert);
420
- const isDismissButtonDisplayed = isDismissEnabled(alert);
421
- const isButtonGroupDisplayed = isSnoozeButtonDisplayed || isAcceptButtonDisplayed || isDismissButtonDisplayed;
422
- return /* @__PURE__ */ React.createElement(Box, { display: "flex", flexDirection: "column", mb: 6 }, /* @__PURE__ */ React.createElement(AlertInsightsSectionHeader, { alert, number }), isButtonGroupDisplayed && /* @__PURE__ */ React.createElement(Box, { display: "flex", alignItems: "center", mb: 4 }, isAcceptButtonDisplayed && /* @__PURE__ */ React.createElement(Box, { mr: 1 }, /* @__PURE__ */ React.createElement(
423
- Button,
424
- {
425
- color: "primary",
426
- variant: "contained",
427
- "aria-label": "accept",
428
- onClick: () => onAccept(alert),
429
- startIcon: /* @__PURE__ */ React.createElement(AcceptIcon, null)
430
- },
431
- "Accept"
432
- )), isSnoozeButtonDisplayed && /* @__PURE__ */ React.createElement(Box, { mr: 1 }, /* @__PURE__ */ React.createElement(
433
- Button,
434
- {
435
- color: "default",
436
- variant: "outlined",
437
- "aria-label": "snooze",
438
- disableElevation: true,
439
- onClick: () => onSnooze(alert),
440
- startIcon: /* @__PURE__ */ React.createElement(SnoozeIcon, null)
441
- },
442
- "Snooze"
443
- )), isDismissButtonDisplayed && /* @__PURE__ */ React.createElement(
444
- Button,
445
- {
446
- color: "secondary",
447
- variant: "outlined",
448
- "aria-label": "dismiss",
449
- disableElevation: true,
450
- onClick: () => onDismiss(alert),
451
- startIcon: /* @__PURE__ */ React.createElement(DismissIcon, null)
452
- },
453
- "Dismiss"
454
- )), alert.element);
455
- };
456
-
457
- const mapLoadingToAlerts = ({ dispatch }) => (isLoading) => dispatch({ [DefaultLoadingAction.CostInsightsAlerts]: isLoading });
458
- const AlertInsights = ({
459
- group,
460
- active,
461
- snoozed,
462
- accepted,
463
- dismissed,
464
- onChange
465
- }) => {
466
- const [scroll] = useScroll();
467
- const [alert, setAlert] = useState(null);
468
- const dispatchLoadingAlerts = useLoading(mapLoadingToAlerts);
469
- const [status, setStatus] = useState(null);
470
- const [data, setData] = useState(void 0);
471
- const [error, setError] = useState(null);
472
- const [isDialogOpen, setDialogOpen] = useState(false);
473
- const [isSummaryOpen, setSummaryOpen] = useState(false);
474
- const [isSnackbarOpen, setSnackbarOpen] = useState(false);
475
- useEffect(() => {
476
- var _a, _b, _c;
477
- async function callAlertHook(options2, callback) {
478
- setAlert(null);
479
- setStatus(null);
480
- setData(void 0);
481
- setDialogOpen(false);
482
- dispatchLoadingAlerts(true);
483
- try {
484
- const alerts = await callback(options2);
485
- onChange(alerts);
486
- } catch (e) {
487
- setError(e);
488
- } finally {
489
- dispatchLoadingAlerts(false);
490
- }
491
- }
492
- const options = { data, group };
493
- const onSnoozed = (_a = alert == null ? void 0 : alert.onSnoozed) == null ? void 0 : _a.bind(alert);
494
- const onAccepted = (_b = alert == null ? void 0 : alert.onAccepted) == null ? void 0 : _b.bind(alert);
495
- const onDismissed = (_c = alert == null ? void 0 : alert.onDismissed) == null ? void 0 : _c.bind(alert);
496
- if (data !== void 0) {
497
- if (isStatusSnoozed(status) && onSnoozed) {
498
- callAlertHook(options, onSnoozed);
499
- } else if (isStatusAccepted(status) && onAccepted) {
500
- callAlertHook(options, onAccepted);
501
- } else if (isStatusDismissed(status) && onDismissed) {
502
- callAlertHook(options, onDismissed);
503
- }
504
- }
505
- }, [group, data, alert, status, onChange, dispatchLoadingAlerts]);
506
- useEffect(() => {
507
- if (scroll === ScrollType.AlertSummary) {
508
- setSummaryOpen(true);
509
- }
510
- }, [scroll]);
511
- useEffect(() => {
512
- setDialogOpen(!!status);
513
- }, [status]);
514
- useEffect(() => {
515
- setSnackbarOpen(!!error);
516
- }, [error]);
517
- function onSnooze(alertToSnooze) {
518
- setAlert(alertToSnooze);
519
- setStatus(AlertStatus.Snoozed);
520
- }
521
- function onAccept(alertToAccept) {
522
- setAlert(alertToAccept);
523
- setStatus(AlertStatus.Accepted);
524
- }
525
- function onDismiss(alertToDismiss) {
526
- setAlert(alertToDismiss);
527
- setStatus(AlertStatus.Dismissed);
528
- }
529
- function onSnackbarClose() {
530
- setError(null);
531
- }
532
- function onDialogClose() {
533
- setAlert(null);
534
- setStatus(null);
535
- }
536
- function onDialogFormSubmit(formData) {
537
- setData(formData);
538
- }
539
- function onSummaryButtonClick() {
540
- setSummaryOpen((prevOpen) => !prevOpen);
541
- }
542
- const total = [accepted, snoozed, dismissed].reduce(sumOfAllAlerts, 0);
543
- const isAlertStatusSummaryDisplayed = !!total;
544
- const isAlertInsightSectionDisplayed = !!active.length;
545
- return /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "column", spacing: 2 }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(
546
- AlertInsightsHeader,
547
- {
548
- title: "Your team's action items",
549
- subtitle: isAlertInsightSectionDisplayed ? "This section outlines suggested action items your team can address to improve cloud costs." : "All of your team's action items are hidden. Maybe it's time to give them another look?"
550
- }
551
- )), isAlertInsightSectionDisplayed && /* @__PURE__ */ React.createElement(Grid, { item: true, container: true, direction: "column", spacing: 4 }, active.map((activeAlert, index) => /* @__PURE__ */ React.createElement(Grid, { item: true, key: `alert-insights-section-${index}` }, /* @__PURE__ */ React.createElement(
552
- AlertInsightsSection,
553
- {
554
- alert: activeAlert,
555
- number: index + 1,
556
- onSnooze,
557
- onAccept,
558
- onDismiss
559
- }
560
- )))), isAlertStatusSummaryDisplayed && /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Box, { position: "relative", display: "flex", justifyContent: "flex-end" }, /* @__PURE__ */ React.createElement(ScrollAnchor, { id: ScrollType.AlertSummary }), /* @__PURE__ */ React.createElement(AlertStatusSummaryButton, { onClick: onSummaryButtonClick }, pluralize("Hidden Action Item", total))), /* @__PURE__ */ React.createElement(
561
- AlertStatusSummary,
562
- {
563
- open: isSummaryOpen,
564
- snoozed,
565
- accepted,
566
- dismissed
567
- }
568
- )), /* @__PURE__ */ React.createElement(
569
- AlertDialog,
570
- {
571
- group,
572
- open: isDialogOpen,
573
- alert,
574
- status,
575
- onClose: onDialogClose,
576
- onSubmit: onDialogFormSubmit
577
- }
578
- ), /* @__PURE__ */ React.createElement(
579
- Snackbar,
580
- {
581
- open: isSnackbarOpen,
582
- autoHideDuration: 6e3,
583
- anchorOrigin: { vertical: "top", horizontal: "center" },
584
- onClose: onSnackbarClose
585
- },
586
- /* @__PURE__ */ React.createElement(Alert, { onClose: onSnackbarClose, severity: "error" }, error == null ? void 0 : error.message)
587
- ));
588
- };
589
-
590
- const ClipboardMessage = {
591
- default: "Copy URL to clipboard",
592
- success: "Copied!",
593
- error: "Couldn't copy to clipboard"
594
- };
595
- const CopyUrlToClipboard = () => {
596
- const location = useLocation();
597
- const [state, copyToClipboard] = useCopyToClipboard();
598
- const [copied, setCopied] = useState(false);
599
- const origin = window.location.origin;
600
- const pathname = location.pathname;
601
- const search = location.search;
602
- const url = `${origin}${pathname}${search}`;
603
- useEffect(() => {
604
- if (state.error) {
605
- setCopied(false);
606
- } else if (state.value) {
607
- setCopied(true);
608
- setTimeout(setCopied, 1500, false);
609
- }
610
- }, [state]);
611
- let text = ClipboardMessage.default;
612
- let Icon = AssignmentOutlinedIcon;
613
- if (state.error) {
614
- text = ClipboardMessage.error;
615
- Icon = SentimentVeryDissatisfiedIcon;
616
- } else if (copied) {
617
- text = ClipboardMessage.success;
618
- Icon = AssignmentTurnedInOutlinedIcon;
619
- }
620
- return /* @__PURE__ */ React.createElement(Tooltip, { title: text, arrow: true }, /* @__PURE__ */ React.createElement(IconButton, { onClick: () => copyToClipboard(url) }, /* @__PURE__ */ React.createElement(Icon, null)));
621
- };
622
-
623
- function useDisplayName() {
624
- var _a;
625
- const identityApi = useApi(identityApiRef);
626
- const state = useAsync(() => identityApi.getProfileInfo(), [identityApi]);
627
- return state.loading ? "" : ((_a = state.value) == null ? void 0 : _a.displayName) || "Mysterious Stranger";
628
- }
629
- const CostInsightsHeaderNoData = ({
630
- groupId,
631
- groups
632
- }) => {
633
- var _a, _b;
634
- const displayName = useDisplayName();
635
- const classes = useCostInsightsStyles();
636
- const hasMultipleGroups = groups.length > 1;
637
- const ownerName = (_b = (_a = groups.find(({ id }) => id === groupId)) == null ? void 0 : _a.name) != null ? _b : groupId;
638
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "h4", align: "center", gutterBottom: true }, /* @__PURE__ */ React.createElement(Typography, { component: "span", role: "img", "aria-label": "flushed-face" }, "\u{1F633}"), " ", "Well this is awkward"), /* @__PURE__ */ React.createElement(Typography, { className: classes.h6Subtle, align: "center", gutterBottom: true }, /* @__PURE__ */ React.createElement("b", null, "Hey, ", displayName, "!"), " ", /* @__PURE__ */ React.createElement("b", null, ownerName), " doesn't seem to have any cloud costs."), hasMultipleGroups && /* @__PURE__ */ React.createElement(Typography, { align: "center", gutterBottom: true }, "Maybe we picked the wrong team, choose another from the menu above?"));
639
- };
640
- const CostInsightsHeaderAlerts = ({
641
- groupId,
642
- groups,
643
- alerts
644
- }) => {
645
- var _a, _b;
646
- const displayName = useDisplayName();
647
- const classes = useCostInsightsStyles();
648
- const ownerName = (_b = (_a = groups.find(({ id }) => id === groupId)) == null ? void 0 : _a.name) != null ? _b : groupId;
649
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "h4", align: "center", gutterBottom: true }, /* @__PURE__ */ React.createElement(Typography, { component: "span", role: "img", "aria-label": "magnifying-glass" }, "\u{1F50E}"), " ", "You have ", alerts, " thing", alerts > 1 && "s", " to look into"), /* @__PURE__ */ React.createElement(Typography, { className: classes.h6Subtle, align: "center", gutterBottom: true }, /* @__PURE__ */ React.createElement("b", null, "Hey, ", displayName, "!"), " We've identified", " ", alerts > 1 ? "a few things " : "one thing ", /* @__PURE__ */ React.createElement("b", null, ownerName), " should look into next."));
650
- };
651
- const CostInsightsHeaderNoAlerts = ({
652
- groupId,
653
- groups
654
- }) => {
655
- var _a, _b;
656
- const displayName = useDisplayName();
657
- const classes = useCostInsightsStyles();
658
- const ownerName = (_b = (_a = groups.find(({ id }) => id === groupId)) == null ? void 0 : _a.name) != null ? _b : groupId;
659
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "h4", gutterBottom: true, align: "center" }, /* @__PURE__ */ React.createElement(Typography, { component: "span", role: "img", "aria-label": "thumbs-up" }, "\u{1F44D}"), " ", "Your team is doing great"), /* @__PURE__ */ React.createElement(Typography, { className: classes.h6Subtle, align: "center", gutterBottom: true }, /* @__PURE__ */ React.createElement("b", null, "Hey, ", displayName, "!"), " ", /* @__PURE__ */ React.createElement("b", null, ownerName), " is doing well. No major changes this month."));
660
- };
661
- const CostInsightsHeaderNoGroups = () => {
662
- const displayName = useDisplayName();
663
- const classes = useCostInsightsStyles();
664
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "h4", align: "center", gutterBottom: true }, /* @__PURE__ */ React.createElement(Typography, { component: "span", role: "img", "aria-label": "flushed-face" }, "\u{1F633}"), " ", "Well this is awkward"), /* @__PURE__ */ React.createElement(Typography, { className: classes.h6Subtle, align: "center", gutterBottom: true }, /* @__PURE__ */ React.createElement("b", null, "Hey, ", displayName, "!"), " It doesn't look like you belong to any teams."));
665
- };
666
- const CostInsightsHeader = (props) => {
667
- if (!props.hasCostData) {
668
- return /* @__PURE__ */ React.createElement(CostInsightsHeaderNoData, { ...props });
669
- }
670
- if (props.alerts) {
671
- return /* @__PURE__ */ React.createElement(CostInsightsHeaderAlerts, { ...props });
672
- }
673
- return /* @__PURE__ */ React.createElement(CostInsightsHeaderNoAlerts, { ...props });
674
- };
675
-
676
- const NULL_VALUE = "engineers";
677
- const CurrencySelect = ({
678
- currency,
679
- currencies,
680
- onSelect
681
- }) => {
682
- const classes = useSelectStyles();
683
- const getOption = (value) => {
684
- const kind = value === NULL_VALUE ? null : value;
685
- return findAlways(currencies, (c) => c.kind === kind);
686
- };
687
- const handleOnChange = (e) => {
688
- const option = getOption(e.target.value);
689
- onSelect(option);
690
- };
691
- const renderValue = (value) => {
692
- const option = getOption(value);
693
- return /* @__PURE__ */ React.createElement("b", null, option.label);
694
- };
695
- return /* @__PURE__ */ React.createElement(FormControl, { variant: "outlined" }, /* @__PURE__ */ React.createElement(InputLabel, { shrink: true }, "Convert to:"), /* @__PURE__ */ React.createElement(
696
- Select,
697
- {
698
- className: classes.select,
699
- variant: "outlined",
700
- labelWidth: 100,
701
- onChange: handleOnChange,
702
- value: currency.kind || NULL_VALUE,
703
- renderValue
704
- },
705
- currencies.map((c) => /* @__PURE__ */ React.createElement(
706
- MenuItem,
707
- {
708
- className: classes.menuItem,
709
- key: c.kind || NULL_VALUE,
710
- value: c.kind || NULL_VALUE
711
- },
712
- /* @__PURE__ */ React.createElement(Typography, { component: "span", role: "img", "aria-label": c.label }, c.label)
713
- ))
714
- ));
715
- };
716
-
717
- const WhyCostsMatter = () => {
718
- return /* @__PURE__ */ React.createElement(Box, { mt: 10, mb: 4 }, /* @__PURE__ */ React.createElement(Container, { maxWidth: "md" }, /* @__PURE__ */ React.createElement(Box, { mt: 2, mb: 2 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5", align: "center", gutterBottom: true }, "Why cloud costs matter")), /* @__PURE__ */ React.createElement(Grid, { container: true, alignContent: "space-around", spacing: 3, wrap: "nowrap" }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, "Sustainability", " ", /* @__PURE__ */ React.createElement(Typography, { component: "span", role: "img", "aria-label": "globe" }, "\u{1F30E}")), /* @__PURE__ */ React.createElement(Typography, null, "Reducing cloud usage improves our carbon footprint.")), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Divider, { orientation: "vertical" })), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, "Revenue", " ", /* @__PURE__ */ React.createElement(
719
- Typography,
720
- {
721
- component: "span",
722
- role: "img",
723
- "aria-label": "money-with-wings"
724
- },
725
- "\u{1F4B8}"
726
- )), /* @__PURE__ */ React.createElement(Typography, null, "Keeping cloud costs well-tuned prevents infrastructure from eating into revenue.")), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Divider, { orientation: "vertical" })), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, "Innovation", " ", /* @__PURE__ */ React.createElement(Typography, { component: "span", role: "img", "aria-label": "medal" }, "\u{1F947}")), /* @__PURE__ */ React.createElement(Typography, null, "The more we save, the more we can reinvest in speed and innovation.")))));
727
- };
728
-
729
- const mapLoadingToProps$1 = ({ dispatch }) => (isLoading) => dispatch({ [DefaultLoadingAction.CostInsightsProducts]: isLoading });
730
- const ProductInsightsCard = ({
731
- initialState,
732
- product,
733
- onSelectAsync
734
- }) => {
735
- const classes = useProductInsightsCardStyles();
736
- const mountedRef = useRef(false);
737
- const [error, setError] = useState(null);
738
- const dispatchLoading = useLoading(mapLoadingToProps$1);
739
- const lastCompleteBillingDate = useLastCompleteBillingDate();
740
- const [entity, setEntity] = useState(initialState.entity);
741
- const [duration, setDuration] = useState(initialState.duration);
742
- const dispatchLoadingProduct = useCallback(dispatchLoading, []);
743
- useEffect(() => {
744
- async function handleOnSelectAsync() {
745
- dispatchLoadingProduct(true);
746
- try {
747
- const e = await onSelectAsync(product, duration);
748
- setEntity(e);
749
- } catch (e) {
750
- setEntity(null);
751
- setError(e);
752
- } finally {
753
- dispatchLoadingProduct(false);
754
- }
755
- }
756
- if (mountedRef.current) {
757
- handleOnSelectAsync();
758
- } else {
759
- mountedRef.current = true;
760
- }
761
- }, [product, duration, onSelectAsync, dispatchLoadingProduct]);
762
- const entityKey = findAnyKey(entity == null ? void 0 : entity.entities);
763
- const entities = entityKey ? entity.entities[entityKey] : [];
764
- const subheader = entityKey && entities.length ? `${pluralize(entityKey, entities.length, true)}, sorted by cost` : null;
765
- const headerProps = {
766
- classes,
767
- action: /* @__PURE__ */ React.createElement(PeriodSelect, { duration, onSelect: setDuration })
768
- };
769
- if (error || !entity) {
770
- return /* @__PURE__ */ React.createElement(InfoCard, { title: product.name, headerProps }, /* @__PURE__ */ React.createElement(ScrollAnchor, { id: product.kind }), /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, error ? error.message : `Error: Could not fetch product insights for ${product.name}`));
771
- }
772
- return /* @__PURE__ */ React.createElement(
773
- InfoCard,
774
- {
775
- title: product.name,
776
- subheader,
777
- headerProps
778
- },
779
- /* @__PURE__ */ React.createElement(ScrollAnchor, { id: product.kind }),
780
- entities.length ? /* @__PURE__ */ React.createElement(
781
- ProductInsightsChart,
782
- {
783
- entity,
784
- duration,
785
- billingDate: lastCompleteBillingDate
786
- }
787
- ) : /* @__PURE__ */ React.createElement(Typography, null, "There are no ", product.name, " costs within this time frame for your team's projects.")
788
- );
789
- };
790
-
791
- const ProductInsightsCardList = ({
792
- initialStates,
793
- onSelectAsync
794
- }) => {
795
- if (!initialStates.length) {
796
- return /* @__PURE__ */ React.createElement(Box, { display: "flex", justifyContent: "space-around", alignItems: "center" }, /* @__PURE__ */ React.createElement(CircularProgress, null));
797
- }
798
- return /* @__PURE__ */ React.createElement(Collapse, { in: true, timeout: 1e3 }, initialStates.map(({ product, entity, duration }) => /* @__PURE__ */ React.createElement(
799
- Box,
800
- {
801
- key: product.kind,
802
- mb: 6,
803
- position: "relative",
804
- "data-testid": `product-list-item-${product.kind}`
805
- },
806
- /* @__PURE__ */ React.createElement(
807
- ProductInsightsCard,
808
- {
809
- product,
810
- onSelectAsync,
811
- initialState: { entity, duration }
812
- }
813
- )
814
- )));
815
- };
816
-
817
- const mapLoadingToProps = ({ dispatch }) => (isLoading) => dispatch({ [DefaultLoadingAction.CostInsightsProducts]: isLoading });
818
- const ProductInsights = ({
819
- group,
820
- project,
821
- products,
822
- onLoaded
823
- }) => {
824
- const client = useApi(costInsightsApiRef);
825
- const onceRef = useRef(false);
826
- const [initialStates, setStates] = useState([]);
827
- const [error, setError] = useState(null);
828
- const lastCompleteBillingDate = useLastCompleteBillingDate();
829
- const dispatchLoading = useLoading(mapLoadingToProps);
830
- const dispatchLoadingProducts = useCallback(dispatchLoading, []);
831
- const onSelectAsyncMemo = useCallback(
832
- async function onSelectAsync(product, duration) {
833
- return client.getProductInsights({
834
- group,
835
- project,
836
- product: product.kind,
837
- intervals: intervalsOf(duration, lastCompleteBillingDate)
838
- });
839
- },
840
- [client, group, project, lastCompleteBillingDate]
841
- );
842
- useEffect(() => {
843
- async function getAllProductInsights() {
844
- try {
845
- dispatchLoadingProducts(true);
846
- const responses = await Promise.allSettled(
847
- products.map(
848
- (product) => client.getProductInsights({
849
- group,
850
- project,
851
- product: product.kind,
852
- intervals: intervalsOf(DEFAULT_DURATION, lastCompleteBillingDate)
853
- })
854
- )
855
- ).then(settledResponseOf);
856
- const updatedInitialStates = initialStatesOf(products, responses).sort(
857
- totalAggregationSort
858
- );
859
- setStates(updatedInitialStates);
860
- } catch (e) {
861
- setError(e);
862
- } finally {
863
- dispatchLoadingProducts(false);
864
- }
865
- }
866
- getAllProductInsights();
867
- }, [
868
- client,
869
- group,
870
- project,
871
- products,
872
- lastCompleteBillingDate,
873
- dispatchLoadingProducts
874
- ]);
875
- useEffect(
876
- function handleOnLoaded() {
877
- if (onceRef.current) {
878
- const initialProducts = initialStates.map((state) => state.product);
879
- onLoaded(initialProducts);
880
- } else {
881
- onceRef.current = true;
882
- }
883
- },
884
- [initialStates, onLoaded]
885
- );
886
- return /* @__PURE__ */ React.createElement(Box, { px: 3, py: 6 }, /* @__PURE__ */ React.createElement(Box, { mt: 0, mb: 5, textAlign: "center" }, /* @__PURE__ */ React.createElement(Typography, { variant: "h4", gutterBottom: true }, "Your team's product usage")), error ? /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, error.message) : /* @__PURE__ */ React.createElement(
887
- ProductInsightsCardList,
888
- {
889
- initialStates,
890
- onSelectAsync: onSelectAsyncMemo
891
- }
892
- ));
893
- };
894
-
895
- const ProjectSelect = ({
896
- project,
897
- projects,
898
- onSelect
899
- }) => {
900
- const classes = useSelectStyles();
901
- const projectOptions = projects.filter((p) => p.id).sort(
902
- (a, b) => {
903
- var _a, _b;
904
- return ((_a = a.name) != null ? _a : a.id).localeCompare((_b = b.name) != null ? _b : b.id);
905
- }
906
- );
907
- const handleOnChange = (e) => {
908
- onSelect(e.target.value);
909
- };
910
- const renderValue = (value) => {
911
- var _a;
912
- const proj = value;
913
- const projectObj = projects.find((p) => p.id === proj);
914
- return /* @__PURE__ */ React.createElement("b", { "data-testid": `selected-${proj}` }, proj === "all" ? "All Projects" : (_a = projectObj == null ? void 0 : projectObj.name) != null ? _a : proj);
915
- };
916
- return /* @__PURE__ */ React.createElement(
917
- Select,
918
- {
919
- className: classes.select,
920
- variant: "outlined",
921
- value: project != null ? project : "all",
922
- renderValue,
923
- onChange: handleOnChange,
924
- "data-testid": "project-filter-select"
925
- },
926
- [{ id: "all" }, ...projectOptions].map((proj) => {
927
- var _a;
928
- return /* @__PURE__ */ React.createElement(
929
- MenuItem,
930
- {
931
- className: `${classes.menuItem} compact`,
932
- key: proj.id,
933
- value: proj.id,
934
- "data-testid": `option-${proj.id}`
935
- },
936
- proj.id === "all" ? "All Projects" : (_a = proj.name) != null ? _a : proj.id
937
- );
938
- })
939
- );
940
- };
941
-
942
- const CostInsightsPage = () => {
943
- var _a;
944
- const classes = useSubtleTypographyStyles();
945
- const client = useApi(costInsightsApiRef);
946
- const config = useConfig();
947
- const groups = useGroups();
948
- const lastCompleteBillingDate = useLastCompleteBillingDate();
949
- const [alerts, setAlerts] = useState([]);
950
- const [currency, setCurrency] = useCurrency();
951
- const [projects, setProjects] = useState(null);
952
- const [products, setProducts] = useState(null);
953
- const [dailyCost, setDailyCost] = useState(null);
954
- const [metricData, setMetricData] = useState(null);
955
- const [error, setError] = useState(null);
956
- const { pageFilters, setPageFilters } = useFilters((p) => p);
957
- const active = useMemo(() => alerts.filter(isAlertActive), [alerts]);
958
- const snoozed = useMemo(() => alerts.filter(isAlertSnoozed), [alerts]);
959
- const accepted = useMemo(() => alerts.filter(isAlertAccepted), [alerts]);
960
- const dismissed = useMemo(() => alerts.filter(isAlertDismissed), [alerts]);
961
- const isProductsDisplayed = !!((_a = config.products) == null ? void 0 : _a.length);
962
- const isActionItemsDisplayed = !!active.length;
963
- const isAlertInsightsDisplayed = !!alerts.length;
964
- const {
965
- loadingActions,
966
- loadingGroups,
967
- loadingBillingDate,
968
- loadingInitial,
969
- dispatchInitial,
970
- dispatchInsights,
971
- dispatchNone,
972
- dispatchReset
973
- } = useLoading(mapLoadingToProps$2);
974
- const dispatchLoadingInitial = useCallback(dispatchInitial, []);
975
- const dispatchLoadingInsights = useCallback(dispatchInsights, []);
976
- const dispatchLoadingNone = useCallback(dispatchNone, []);
977
- const dispatchLoadingReset = useCallback(dispatchReset, []);
978
- const setProject = (project) => setPageFilters({
979
- ...pageFilters,
980
- project: project === "all" ? null : project
981
- });
982
- useEffect(() => {
983
- async function getInsights() {
984
- setError(null);
985
- try {
986
- if (pageFilters.group) {
987
- dispatchLoadingInsights(true);
988
- const intervals = intervalsOf(
989
- pageFilters.duration,
990
- lastCompleteBillingDate
991
- );
992
- const [
993
- fetchedProjects,
994
- fetchedAlerts,
995
- fetchedMetricData,
996
- fetchedDailyCost
997
- ] = await Promise.all([
998
- client.getGroupProjects(pageFilters.group),
999
- client.getAlerts(pageFilters.group),
1000
- pageFilters.metric ? client.getDailyMetricData(pageFilters.metric, intervals) : null,
1001
- pageFilters.project ? client.getProjectDailyCost(pageFilters.project, intervals) : client.getGroupDailyCost(pageFilters.group, intervals)
1002
- ]);
1003
- setProjects(fetchedProjects);
1004
- setAlerts(fetchedAlerts);
1005
- setMetricData(fetchedMetricData);
1006
- setDailyCost(fetchedDailyCost);
1007
- } else {
1008
- dispatchLoadingNone(loadingActions);
1009
- }
1010
- } catch (e) {
1011
- setError(e);
1012
- dispatchLoadingNone(loadingActions);
1013
- } finally {
1014
- dispatchLoadingInitial(false);
1015
- dispatchLoadingInsights(false);
1016
- }
1017
- }
1018
- if (!(loadingGroups && loadingBillingDate)) {
1019
- getInsights();
1020
- }
1021
- }, [
1022
- client,
1023
- pageFilters,
1024
- loadingActions,
1025
- loadingGroups,
1026
- loadingBillingDate,
1027
- dispatchLoadingInsights,
1028
- dispatchLoadingInitial,
1029
- dispatchLoadingNone,
1030
- lastCompleteBillingDate
1031
- ]);
1032
- if (loadingInitial) {
1033
- return /* @__PURE__ */ React.createElement(Progress, null);
1034
- }
1035
- if (error) {
1036
- return /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, error.message);
1037
- }
1038
- if (!pageFilters.group) {
1039
- return /* @__PURE__ */ React.createElement(CostInsightsLayout, { groups }, /* @__PURE__ */ React.createElement(Box, { textAlign: "right" }, /* @__PURE__ */ React.createElement(CopyUrlToClipboard, null)), /* @__PURE__ */ React.createElement(Container, { maxWidth: "lg" }, /* @__PURE__ */ React.createElement(CostInsightsHeaderNoGroups, null)), /* @__PURE__ */ React.createElement(Divider, null), /* @__PURE__ */ React.createElement(Container, { maxWidth: "lg" }, /* @__PURE__ */ React.createElement(WhyCostsMatter, null)));
1040
- }
1041
- if (!dailyCost) {
1042
- return /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, `Error: Could not fetch cost insights data for team ${pageFilters.group}`);
1043
- }
1044
- const onProjectSelect = (project) => {
1045
- setProject(project);
1046
- dispatchLoadingReset(loadingActions);
1047
- };
1048
- const CostOverviewBanner = () => /* @__PURE__ */ React.createElement(
1049
- Box,
1050
- {
1051
- px: 3,
1052
- pt: 6,
1053
- display: "flex",
1054
- justifyContent: "space-between",
1055
- alignItems: "center",
1056
- minHeight: 40
1057
- },
1058
- /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Typography, { variant: "h4" }, "Cost Overview"), /* @__PURE__ */ React.createElement(Typography, { classes }, "Billing data as of ", lastCompleteBillingDate)),
1059
- /* @__PURE__ */ React.createElement(Box, { display: "flex" }, /* @__PURE__ */ React.createElement(Box, { mr: 1 }, /* @__PURE__ */ React.createElement(
1060
- CurrencySelect,
1061
- {
1062
- currency,
1063
- currencies: config.currencies,
1064
- onSelect: setCurrency
1065
- }
1066
- )), /* @__PURE__ */ React.createElement(
1067
- ProjectSelect,
1068
- {
1069
- project: pageFilters.project,
1070
- projects: projects || [],
1071
- onSelect: onProjectSelect
1072
- }
1073
- ))
1074
- );
1075
- return /* @__PURE__ */ React.createElement(CostInsightsLayout, { groups }, /* @__PURE__ */ React.createElement(Grid, { container: true, wrap: "nowrap" }, (isProductsDisplayed || isActionItemsDisplayed) && /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Box, { position: "sticky", top: 20 }, /* @__PURE__ */ React.createElement(
1076
- CostInsightsNavigation,
1077
- {
1078
- products,
1079
- alerts: active.length
1080
- }
1081
- ))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React.createElement(
1082
- Box,
1083
- {
1084
- display: "flex",
1085
- flexDirection: "row",
1086
- justifyContent: "flex-end",
1087
- mb: 2
1088
- },
1089
- /* @__PURE__ */ React.createElement(CopyUrlToClipboard, null)
1090
- ), /* @__PURE__ */ React.createElement(Container, { maxWidth: "lg", disableGutters: true }, /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "column" }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React.createElement(
1091
- CostInsightsHeader,
1092
- {
1093
- groupId: pageFilters.group,
1094
- groups,
1095
- hasCostData: !!dailyCost.aggregation.length,
1096
- alerts: active.length
1097
- }
1098
- )), /* @__PURE__ */ React.createElement(Collapse, { in: isActionItemsDisplayed, enter: false }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React.createElement(Box, { px: 3, py: 6 }, /* @__PURE__ */ React.createElement(
1099
- ActionItems,
1100
- {
1101
- active,
1102
- snoozed,
1103
- accepted,
1104
- dismissed
1105
- }
1106
- ))), /* @__PURE__ */ React.createElement(Divider, null)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React.createElement(CostOverviewBanner, null)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React.createElement(Box, { px: 3, py: 6 }, !!dailyCost.aggregation.length && /* @__PURE__ */ React.createElement(
1107
- CostOverviewCard,
1108
- {
1109
- dailyCostData: dailyCost,
1110
- metricData
1111
- }
1112
- ), /* @__PURE__ */ React.createElement(WhyCostsMatter, null))), /* @__PURE__ */ React.createElement(Collapse, { in: isAlertInsightsDisplayed, enter: false }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React.createElement(Box, { px: 6, py: 6, mx: -3, bgcolor: "alertBackground" }, /* @__PURE__ */ React.createElement(
1113
- AlertInsights,
1114
- {
1115
- group: pageFilters.group,
1116
- active,
1117
- snoozed,
1118
- accepted,
1119
- dismissed,
1120
- onChange: setAlerts
1121
- }
1122
- )))), !isAlertInsightsDisplayed && isProductsDisplayed && /* @__PURE__ */ React.createElement(Divider, null), isProductsDisplayed && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React.createElement(Box, { px: 3, py: 6 }, /* @__PURE__ */ React.createElement(
1123
- ProductInsights,
1124
- {
1125
- group: pageFilters.group,
1126
- project: pageFilters.project,
1127
- products: config.products,
1128
- onLoaded: setProducts
1129
- }
1130
- ))))))));
1131
- };
1132
-
1133
- const CostInsightsPageRoot = () => /* @__PURE__ */ React.createElement(CostInsightsThemeProvider, null, /* @__PURE__ */ React.createElement(ConfigProvider, null, /* @__PURE__ */ React.createElement(LoadingProvider, null, /* @__PURE__ */ React.createElement(GroupsProvider, null, /* @__PURE__ */ React.createElement(BillingDateProvider, null, /* @__PURE__ */ React.createElement(FilterProvider, null, /* @__PURE__ */ React.createElement(ScrollProvider, null, /* @__PURE__ */ React.createElement(CurrencyProvider, null, /* @__PURE__ */ React.createElement(CostInsightsPage, null)))))))));
1134
-
1135
- export { CostInsightsPageRoot as CostInsightsPage };
1136
- //# sourceMappingURL=index-DaitkcPN.esm.js.map