@backstage-community/plugin-cost-insights 0.12.24 → 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 (231) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +6 -6
  3. package/dist/alerts/ProjectGrowthAlert.esm.js +24 -0
  4. package/dist/alerts/ProjectGrowthAlert.esm.js.map +1 -0
  5. package/dist/alerts/UnlabeledDataflowAlert.esm.js +25 -0
  6. package/dist/alerts/UnlabeledDataflowAlert.esm.js.map +1 -0
  7. package/dist/api/CostInsightsApi.esm.js +8 -0
  8. package/dist/api/CostInsightsApi.esm.js.map +1 -0
  9. package/dist/components/ActionItems/ActionItemCard.esm.js +46 -0
  10. package/dist/components/ActionItems/ActionItemCard.esm.js.map +1 -0
  11. package/dist/components/ActionItems/ActionItems.esm.js +90 -0
  12. package/dist/components/ActionItems/ActionItems.esm.js.map +1 -0
  13. package/dist/components/AlertInsights/AlertDialog.esm.js +123 -0
  14. package/dist/components/AlertInsights/AlertDialog.esm.js.map +1 -0
  15. package/dist/components/AlertInsights/AlertInsights.esm.js +157 -0
  16. package/dist/components/AlertInsights/AlertInsights.esm.js.map +1 -0
  17. package/dist/components/AlertInsights/AlertInsightsHeader.esm.js +17 -0
  18. package/dist/components/AlertInsights/AlertInsightsHeader.esm.js.map +1 -0
  19. package/dist/components/AlertInsights/AlertInsightsSection.esm.js +57 -0
  20. package/dist/components/AlertInsights/AlertInsightsSection.esm.js.map +1 -0
  21. package/dist/components/AlertInsights/AlertInsightsSectionHeader.esm.js +30 -0
  22. package/dist/components/AlertInsights/AlertInsightsSectionHeader.esm.js.map +1 -0
  23. package/dist/components/AlertInsights/AlertStatusSummary.esm.js +93 -0
  24. package/dist/components/AlertInsights/AlertStatusSummary.esm.js.map +1 -0
  25. package/dist/components/AlertInsights/AlertStatusSummaryButton.esm.js +35 -0
  26. package/dist/components/AlertInsights/AlertStatusSummaryButton.esm.js.map +1 -0
  27. package/dist/components/AlertInstructionsLayout/AlertInstructionsLayout.esm.js +47 -0
  28. package/dist/components/AlertInstructionsLayout/AlertInstructionsLayout.esm.js.map +1 -0
  29. package/dist/components/BarChart/BarChart.esm.js +167 -0
  30. package/dist/components/BarChart/BarChart.esm.js.map +1 -0
  31. package/dist/components/BarChart/BarChartLabel.esm.js +31 -0
  32. package/dist/components/BarChart/BarChartLabel.esm.js.map +1 -0
  33. package/dist/components/BarChart/BarChartLegend.esm.js +47 -0
  34. package/dist/components/BarChart/BarChartLegend.esm.js.map +1 -0
  35. package/dist/components/BarChart/BarChartStepper.esm.js +91 -0
  36. package/dist/components/BarChart/BarChartStepper.esm.js.map +1 -0
  37. package/dist/components/BarChart/BarChartStepperButton.esm.js +27 -0
  38. package/dist/components/BarChart/BarChartStepperButton.esm.js.map +1 -0
  39. package/dist/components/BarChart/BarChartSteps.esm.js +25 -0
  40. package/dist/components/BarChart/BarChartSteps.esm.js.map +1 -0
  41. package/dist/components/BarChart/BarChartTick.esm.js +29 -0
  42. package/dist/components/BarChart/BarChartTick.esm.js.map +1 -0
  43. package/dist/components/BarChart/BarChartTooltip.esm.js +30 -0
  44. package/dist/components/BarChart/BarChartTooltip.esm.js.map +1 -0
  45. package/dist/components/BarChart/BarChartTooltipItem.esm.js +24 -0
  46. package/dist/components/BarChart/BarChartTooltipItem.esm.js.map +1 -0
  47. package/dist/components/CopyUrlToClipboard/CopyUrlToClipboard.esm.js +44 -0
  48. package/dist/components/CopyUrlToClipboard/CopyUrlToClipboard.esm.js.map +1 -0
  49. package/dist/components/CostGrowth/CostGrowth.esm.js +55 -0
  50. package/dist/components/CostGrowth/CostGrowth.esm.js.map +1 -0
  51. package/dist/components/CostGrowth/CostGrowthIndicator.esm.js +31 -0
  52. package/dist/components/CostGrowth/CostGrowthIndicator.esm.js.map +1 -0
  53. package/dist/components/CostInsightsHeader/CostInsightsHeader.esm.js +57 -0
  54. package/dist/components/CostInsightsHeader/CostInsightsHeader.esm.js.map +1 -0
  55. package/dist/components/CostInsightsLayout/CostInsightsLayout.esm.js +35 -0
  56. package/dist/components/CostInsightsLayout/CostInsightsLayout.esm.js.map +1 -0
  57. package/dist/components/CostInsightsNavigation/CostInsightsNavigation.esm.js +87 -0
  58. package/dist/components/CostInsightsNavigation/CostInsightsNavigation.esm.js.map +1 -0
  59. package/dist/components/CostInsightsPage/CostInsightsPage.esm.js +229 -0
  60. package/dist/components/CostInsightsPage/CostInsightsPage.esm.js.map +1 -0
  61. package/dist/components/CostInsightsPage/CostInsightsPageRoot.esm.js +15 -0
  62. package/dist/components/CostInsightsPage/CostInsightsPageRoot.esm.js.map +1 -0
  63. package/dist/components/CostInsightsPage/CostInsightsThemeProvider.esm.js +24 -0
  64. package/dist/components/CostInsightsPage/CostInsightsThemeProvider.esm.js.map +1 -0
  65. package/dist/components/CostInsightsPage/index.esm.js +2 -0
  66. package/dist/components/CostInsightsPage/index.esm.js.map +1 -0
  67. package/dist/components/CostInsightsPage/selector.esm.js +15 -0
  68. package/dist/components/CostInsightsPage/selector.esm.js.map +1 -0
  69. package/dist/components/CostInsightsTabs/CostInsightsTabs.esm.js +89 -0
  70. package/dist/components/CostInsightsTabs/CostInsightsTabs.esm.js.map +1 -0
  71. package/dist/components/CostInsightsTabs/selector.esm.js +17 -0
  72. package/dist/components/CostInsightsTabs/selector.esm.js.map +1 -0
  73. package/dist/components/CostOverviewCard/CostOverviewBreakdownChart.esm.js +196 -0
  74. package/dist/components/CostOverviewCard/CostOverviewBreakdownChart.esm.js.map +1 -0
  75. package/dist/components/CostOverviewCard/CostOverviewCard.esm.js +99 -0
  76. package/dist/components/CostOverviewCard/CostOverviewCard.esm.js.map +1 -0
  77. package/dist/components/CostOverviewCard/CostOverviewChart.esm.js +157 -0
  78. package/dist/components/CostOverviewCard/CostOverviewChart.esm.js.map +1 -0
  79. package/dist/components/CostOverviewCard/CostOverviewHeader.esm.js +25 -0
  80. package/dist/components/CostOverviewCard/CostOverviewHeader.esm.js.map +1 -0
  81. package/dist/components/CostOverviewCard/CostOverviewLegend.esm.js +54 -0
  82. package/dist/components/CostOverviewCard/CostOverviewLegend.esm.js.map +1 -0
  83. package/dist/components/CostOverviewCard/selector.esm.js +22 -0
  84. package/dist/components/CostOverviewCard/selector.esm.js.map +1 -0
  85. package/dist/components/CurrencySelect/CurrencySelect.esm.js +52 -0
  86. package/dist/components/CurrencySelect/CurrencySelect.esm.js.map +1 -0
  87. package/dist/{esm/index-BPzWHt3A.esm.js → components/EntityCosts/EntityCosts.esm.js} +14 -80
  88. package/dist/{esm/index-BPzWHt3A.esm.js.map → components/EntityCosts/EntityCosts.esm.js.map} +1 -1
  89. package/dist/components/EntityCosts/index.esm.js +2 -0
  90. package/dist/components/EntityCosts/index.esm.js.map +1 -0
  91. package/dist/{esm/index-BA6m_qFS.esm.js → components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.esm.js} +2 -79
  92. package/dist/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.esm.js.map +1 -0
  93. package/dist/components/LabelDataflowInstructionsPage/index.esm.js +2 -0
  94. package/dist/components/LabelDataflowInstructionsPage/index.esm.js.map +1 -0
  95. package/dist/components/LegendItem/LegendItem.esm.js +44 -0
  96. package/dist/components/LegendItem/LegendItem.esm.js.map +1 -0
  97. package/dist/components/MetricSelect/MetricSelect.esm.js +37 -0
  98. package/dist/components/MetricSelect/MetricSelect.esm.js.map +1 -0
  99. package/dist/components/PeriodSelect/PeriodSelect.esm.js +72 -0
  100. package/dist/components/PeriodSelect/PeriodSelect.esm.js.map +1 -0
  101. package/dist/components/ProductInsights/ProductInsights.esm.js +98 -0
  102. package/dist/components/ProductInsights/ProductInsights.esm.js.map +1 -0
  103. package/dist/components/ProductInsightsCard/ProductEntityDialog.esm.js +42 -0
  104. package/dist/components/ProductInsightsCard/ProductEntityDialog.esm.js.map +1 -0
  105. package/dist/components/ProductInsightsCard/ProductEntityTable.esm.js +139 -0
  106. package/dist/components/ProductInsightsCard/ProductEntityTable.esm.js.map +1 -0
  107. package/dist/components/ProductInsightsCard/ProductInsightsCard.esm.js +83 -0
  108. package/dist/components/ProductInsightsCard/ProductInsightsCard.esm.js.map +1 -0
  109. package/dist/components/ProductInsightsCard/ProductInsightsCardList.esm.js +34 -0
  110. package/dist/components/ProductInsightsCard/ProductInsightsCardList.esm.js.map +1 -0
  111. package/dist/components/ProductInsightsCard/ProductInsightsChart.esm.js +148 -0
  112. package/dist/components/ProductInsightsCard/ProductInsightsChart.esm.js.map +1 -0
  113. package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertCard.esm.js +20 -0
  114. package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertCard.esm.js.map +1 -0
  115. package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertChart.esm.js +46 -0
  116. package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertChart.esm.js.map +1 -0
  117. package/dist/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.esm.js +111 -0
  118. package/dist/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.esm.js.map +1 -0
  119. package/dist/components/ProjectGrowthInstructionsPage/index.esm.js +2 -0
  120. package/dist/components/ProjectGrowthInstructionsPage/index.esm.js.map +1 -0
  121. package/dist/components/ProjectSelect/ProjectSelect.esm.js +47 -0
  122. package/dist/components/ProjectSelect/ProjectSelect.esm.js.map +1 -0
  123. package/dist/components/UnlabeledDataflowAlertCard/UnlabeledDataflowAlertCard.esm.js +41 -0
  124. package/dist/components/UnlabeledDataflowAlertCard/UnlabeledDataflowAlertCard.esm.js.map +1 -0
  125. package/dist/components/WhyCostsMatter/WhyCostsMatter.esm.js +21 -0
  126. package/dist/components/WhyCostsMatter/WhyCostsMatter.esm.js.map +1 -0
  127. package/dist/example/alerts/KubernetesMigrationAlert.esm.js +86 -0
  128. package/dist/example/alerts/KubernetesMigrationAlert.esm.js.map +1 -0
  129. package/dist/example/client.esm.js +194 -0
  130. package/dist/example/client.esm.js.map +1 -0
  131. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationAlertCard.esm.js +33 -0
  132. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationAlertCard.esm.js.map +1 -0
  133. package/dist/{esm/index-BTIHr4n_.esm.js → example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChart.esm.js} +69 -48
  134. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChart.esm.js.map +1 -0
  135. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChartLegend.esm.js +107 -0
  136. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChartLegend.esm.js.map +1 -0
  137. package/dist/example/forms/KubernetesMigrationDismissForm.esm.js +57 -0
  138. package/dist/example/forms/KubernetesMigrationDismissForm.esm.js.map +1 -0
  139. package/dist/forms/AlertAcceptForm.esm.js +27 -0
  140. package/dist/forms/AlertAcceptForm.esm.js.map +1 -0
  141. package/dist/forms/AlertDismissForm.esm.js +100 -0
  142. package/dist/forms/AlertDismissForm.esm.js.map +1 -0
  143. package/dist/forms/AlertSnoozeForm.esm.js +52 -0
  144. package/dist/forms/AlertSnoozeForm.esm.js.map +1 -0
  145. package/dist/hooks/useConfig.esm.js +153 -0
  146. package/dist/hooks/useConfig.esm.js.map +1 -0
  147. package/dist/hooks/useCurrency.esm.js +26 -0
  148. package/dist/hooks/useCurrency.esm.js.map +1 -0
  149. package/dist/hooks/useFilters.esm.js +67 -0
  150. package/dist/hooks/useFilters.esm.js.map +1 -0
  151. package/dist/hooks/useGroups.esm.js +55 -0
  152. package/dist/hooks/useGroups.esm.js.map +1 -0
  153. package/dist/hooks/useLastCompleteBillingDate.esm.js +65 -0
  154. package/dist/hooks/useLastCompleteBillingDate.esm.js.map +1 -0
  155. package/dist/hooks/useLoading.esm.js +54 -0
  156. package/dist/hooks/useLoading.esm.js.map +1 -0
  157. package/dist/hooks/useScroll.esm.js +24 -0
  158. package/dist/hooks/useScroll.esm.js.map +1 -0
  159. package/dist/index.esm.js +37 -22
  160. package/dist/index.esm.js.map +1 -1
  161. package/dist/plugin.esm.js +55 -0
  162. package/dist/plugin.esm.js.map +1 -0
  163. package/dist/testUtils/filters.esm.js +8 -0
  164. package/dist/testUtils/filters.esm.js.map +1 -0
  165. package/dist/testUtils/loading.esm.js +14 -0
  166. package/dist/testUtils/loading.esm.js.map +1 -0
  167. package/dist/testUtils/mockData.esm.js +485 -0
  168. package/dist/testUtils/mockData.esm.js.map +1 -0
  169. package/dist/testUtils/products.esm.js +49 -0
  170. package/dist/testUtils/products.esm.js.map +1 -0
  171. package/dist/testUtils/providers.esm.js +41 -0
  172. package/dist/testUtils/providers.esm.js.map +1 -0
  173. package/dist/testUtils/testUtils.esm.js +142 -0
  174. package/dist/testUtils/testUtils.esm.js.map +1 -0
  175. package/dist/types/Alert.esm.js +66 -0
  176. package/dist/types/Alert.esm.js.map +1 -0
  177. package/dist/types/ChangeStatistic.esm.js +15 -0
  178. package/dist/types/ChangeStatistic.esm.js.map +1 -0
  179. package/dist/types/CurrencyType.esm.js +10 -0
  180. package/dist/types/CurrencyType.esm.js.map +1 -0
  181. package/dist/types/DateFormat.esm.js +4 -0
  182. package/dist/types/DateFormat.esm.js.map +1 -0
  183. package/dist/types/Duration.esm.js +10 -0
  184. package/dist/types/Duration.esm.js.map +1 -0
  185. package/dist/types/Icon.esm.js +12 -0
  186. package/dist/types/Icon.esm.js.map +1 -0
  187. package/dist/utils/alerts.esm.js +72 -0
  188. package/dist/utils/alerts.esm.js.map +1 -0
  189. package/dist/utils/assert.esm.js +29 -0
  190. package/dist/utils/assert.esm.js.map +1 -0
  191. package/dist/utils/change.esm.js +58 -0
  192. package/dist/utils/change.esm.js.map +1 -0
  193. package/dist/utils/charts.esm.js +9 -0
  194. package/dist/utils/charts.esm.js.map +1 -0
  195. package/dist/utils/config.esm.js +19 -0
  196. package/dist/utils/config.esm.js.map +1 -0
  197. package/dist/utils/currency.esm.js +56 -0
  198. package/dist/utils/currency.esm.js.map +1 -0
  199. package/dist/utils/duration.esm.js +55 -0
  200. package/dist/utils/duration.esm.js.map +1 -0
  201. package/dist/utils/filters.esm.js +14 -0
  202. package/dist/utils/filters.esm.js.map +1 -0
  203. package/dist/utils/formatters.esm.js +103 -0
  204. package/dist/utils/formatters.esm.js.map +1 -0
  205. package/dist/utils/grammar.esm.js +14 -0
  206. package/dist/utils/grammar.esm.js.map +1 -0
  207. package/dist/utils/graphs.esm.js +48 -0
  208. package/dist/utils/graphs.esm.js.map +1 -0
  209. package/dist/utils/history.esm.js +32 -0
  210. package/dist/utils/history.esm.js.map +1 -0
  211. package/dist/utils/loading.esm.js +51 -0
  212. package/dist/utils/loading.esm.js.map +1 -0
  213. package/dist/utils/navigation.esm.js +56 -0
  214. package/dist/utils/navigation.esm.js.map +1 -0
  215. package/dist/utils/scroll.esm.js +38 -0
  216. package/dist/utils/scroll.esm.js.map +1 -0
  217. package/dist/utils/sort.esm.js +10 -0
  218. package/dist/utils/sort.esm.js.map +1 -0
  219. package/dist/utils/styles.esm.js +562 -0
  220. package/dist/utils/styles.esm.js.map +1 -0
  221. package/dist/utils/sum.esm.js +4 -0
  222. package/dist/utils/sum.esm.js.map +1 -0
  223. package/package.json +17 -12
  224. package/dist/esm/index-BA6m_qFS.esm.js.map +0 -1
  225. package/dist/esm/index-BFM2mP6Z.esm.js +0 -4084
  226. package/dist/esm/index-BFM2mP6Z.esm.js.map +0 -1
  227. package/dist/esm/index-BTIHr4n_.esm.js.map +0 -1
  228. package/dist/esm/index-DaitkcPN.esm.js +0 -1136
  229. package/dist/esm/index-DaitkcPN.esm.js.map +0 -1
  230. package/dist/esm/selector-D7iXJwd9.esm.js +0 -594
  231. package/dist/esm/selector-D7iXJwd9.esm.js.map +0 -1
@@ -1,594 +0,0 @@
1
- import React, { useRef, useEffect, useState } from 'react';
2
- import Box from '@material-ui/core/Box';
3
- import { capitalize } from '@material-ui/core/utils';
4
- import Card from '@material-ui/core/Card';
5
- import CardContent from '@material-ui/core/CardContent';
6
- import Divider from '@material-ui/core/Divider';
7
- import Tab from '@material-ui/core/Tab';
8
- import Tabs from '@material-ui/core/Tabs';
9
- import { useTheme } from '@material-ui/core/styles';
10
- import { DateTime } from 'luxon';
11
- import { ResponsiveContainer, ComposedChart, CartesianGrid, XAxis, YAxis, Area, Line, Tooltip, AreaChart } from 'recharts';
12
- import { f as useScroll, e as useFilters, d as useLastCompleteBillingDate, g as getComparedChange, h as LegendItem, j as formatChange, k as choose, l as CostGrowth, m as useCostOverviewStyles, n as useConfig, o as aggregationSort, p as overviewGraphTickFormatter, q as isInvalid, D as DEFAULT_DATE_FORMAT, r as BarChartTooltip, s as BarChartTooltipItem, t as formatGraphValue, v as getPreviousPeriodTotalCost, w as formatPeriod, x as BarChartLegend, y as useSelectStyles, z as Duration, E as formatLastTwoLookaheadQuarters, H as findAlways, I as useOverviewTabsStyles, J as DefaultNavigation, K as DefaultLoadingAction, M as getResetState, N as getResetStateWithoutInitial } from './index-BFM2mP6Z.esm.js';
13
- import Typography from '@material-ui/core/Typography';
14
- import '@material-ui/core/Paper';
15
- import '@material-ui/core/Slide';
16
- import '@material-ui/icons/ChevronLeft';
17
- import '@material-ui/icons/ChevronRight';
18
- import '@material-ui/core/ButtonBase';
19
- import 'pluralize';
20
- import '@material-ui/core/Tooltip';
21
- import '@material-ui/icons/Lens';
22
- import '@material-ui/icons/HelpOutlineOutlined';
23
- import 'classnames';
24
- import '@material-ui/icons/ArrowDropUp';
25
- import '@material-ui/icons/ArrowDropDown';
26
- import { emphasize } from '@material-ui/core/styles/colorManipulator';
27
- import FullScreenIcon from '@material-ui/icons/Fullscreen';
28
- import InputLabel from '@material-ui/core/InputLabel';
29
- import FormControl from '@material-ui/core/FormControl';
30
- import Select from '@material-ui/core/Select';
31
- import MenuItem from '@material-ui/core/MenuItem';
32
-
33
- const ScrollAnchor = ({
34
- id,
35
- left = 0,
36
- top = -20,
37
- block = "start",
38
- inline = "nearest",
39
- behavior = "smooth"
40
- }) => {
41
- const divRef = useRef(null);
42
- const [scroll, setScroll] = useScroll();
43
- useEffect(() => {
44
- function scrollIntoView() {
45
- if (divRef.current && scroll === id) {
46
- divRef.current.scrollIntoView({
47
- block,
48
- inline,
49
- behavior
50
- });
51
- setScroll(null);
52
- }
53
- }
54
- scrollIntoView();
55
- }, [scroll, setScroll, id, behavior, block, inline]);
56
- return /* @__PURE__ */ React.createElement(
57
- "div",
58
- {
59
- ref: divRef,
60
- style: { position: "absolute", height: 0, width: 0, top, left },
61
- "data-testid": `scroll-test-${id}`
62
- }
63
- );
64
- };
65
-
66
- function trendFrom(trendline, date) {
67
- return trendline.slope * (date / 1e3) + trendline.intercept;
68
- }
69
- function groupByDate(acc, entry) {
70
- return { ...acc, [entry.date]: entry.amount };
71
- }
72
-
73
- const mapFiltersToProps = ({
74
- pageFilters,
75
- setPageFilters
76
- }) => ({
77
- ...pageFilters,
78
- project: pageFilters.project || "all",
79
- setDuration: (duration) => setPageFilters({
80
- ...pageFilters,
81
- duration
82
- }),
83
- setProject: (project) => setPageFilters({
84
- ...pageFilters,
85
- project: project === "all" ? null : project
86
- }),
87
- setMetric: (metric) => setPageFilters({
88
- ...pageFilters,
89
- metric
90
- })
91
- });
92
-
93
- const CostOverviewLegend = ({
94
- dailyCostData,
95
- metric,
96
- metricData
97
- }) => {
98
- const theme = useTheme();
99
- const { duration } = useFilters(mapFiltersToProps);
100
- const lastCompleteBillingDate = useLastCompleteBillingDate();
101
- const comparedChange = metricData ? getComparedChange(
102
- dailyCostData,
103
- metricData,
104
- duration,
105
- lastCompleteBillingDate
106
- ) : null;
107
- return /* @__PURE__ */ React.createElement(Box, { display: "flex", flexDirection: "row" }, dailyCostData.change && /* @__PURE__ */ React.createElement(Box, { mr: 2 }, /* @__PURE__ */ React.createElement(LegendItem, { title: "Cost Trend", markerColor: theme.palette.blue }, formatChange(dailyCostData.change))), metricData && metric && comparedChange && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { mr: 2 }, /* @__PURE__ */ React.createElement(
108
- LegendItem,
109
- {
110
- title: `${metric.name} Trend`,
111
- markerColor: theme.palette.magenta
112
- },
113
- formatChange(metricData.change)
114
- )), /* @__PURE__ */ React.createElement(
115
- LegendItem,
116
- {
117
- title: choose(["Your Savings", "Your Excess"], comparedChange)
118
- },
119
- /* @__PURE__ */ React.createElement(CostGrowth, { change: comparedChange, duration })
120
- )));
121
- };
122
-
123
- const CostOverviewChart = ({
124
- dailyCostData,
125
- metric,
126
- metricData,
127
- responsive = true
128
- }) => {
129
- var _a, _b, _c;
130
- const theme = useTheme();
131
- const styles = useCostOverviewStyles(theme);
132
- const { baseCurrency, hideTrendLine } = useConfig();
133
- const data = {
134
- dailyCost: {
135
- dataKey: "dailyCost",
136
- name: `Daily Cost`,
137
- format: "currency",
138
- data: dailyCostData
139
- },
140
- metric: {
141
- dataKey: (_a = metric == null ? void 0 : metric.kind) != null ? _a : "Unknown",
142
- name: (_b = metric == null ? void 0 : metric.name) != null ? _b : "Unknown",
143
- format: (_c = metricData == null ? void 0 : metricData.format) != null ? _c : "number",
144
- data: metricData
145
- }
146
- };
147
- const metricsByDate = data.metric.data ? data.metric.data.aggregation.reduce(groupByDate, {}) : {};
148
- const chartData = data.dailyCost.data.aggregation.slice().sort(aggregationSort).map((entry) => ({
149
- date: Date.parse(entry.date),
150
- trend: trendFrom(data.dailyCost.data.trendline, Date.parse(entry.date)),
151
- dailyCost: entry.amount,
152
- ...metric && data.metric.data ? { [data.metric.dataKey]: metricsByDate[`${entry.date}`] } : {}
153
- }));
154
- const tooltipRenderer = ({ label, payload = [] }) => {
155
- if (isInvalid({ label, payload }))
156
- return null;
157
- const dataKeys = [data.dailyCost.dataKey, data.metric.dataKey];
158
- const date = typeof label === "number" ? DateTime.fromMillis(label) : DateTime.fromISO(label);
159
- const title = date.toUTC().toFormat(DEFAULT_DATE_FORMAT);
160
- const formatGraphValueWith = formatGraphValue(baseCurrency);
161
- const items = payload.filter((p) => dataKeys.includes(p.dataKey)).map((p, i) => ({
162
- label: p.dataKey === data.dailyCost.dataKey ? data.dailyCost.name : data.metric.name,
163
- value: p.dataKey === data.dailyCost.dataKey ? formatGraphValueWith(Number(p.value), i, data.dailyCost.format) : formatGraphValueWith(Number(p.value), i, data.metric.format),
164
- fill: p.dataKey === data.dailyCost.dataKey ? theme.palette.blue : theme.palette.magenta
165
- }));
166
- return /* @__PURE__ */ React.createElement(BarChartTooltip, { title }, items.map((item, index) => /* @__PURE__ */ React.createElement(BarChartTooltipItem, { key: `${item.label}-${index}`, item })));
167
- };
168
- const localizedTickFormatter = formatGraphValue(baseCurrency);
169
- return /* @__PURE__ */ React.createElement(Box, { display: "flex", flexDirection: "column" }, /* @__PURE__ */ React.createElement(
170
- CostOverviewLegend,
171
- {
172
- dailyCostData,
173
- metric,
174
- metricData
175
- }
176
- ), /* @__PURE__ */ React.createElement(
177
- ResponsiveContainer,
178
- {
179
- width: responsive ? "100%" : styles.container.width,
180
- height: styles.container.height,
181
- className: "cost-overview-chart"
182
- },
183
- /* @__PURE__ */ React.createElement(ComposedChart, { margin: styles.chart.margin, data: chartData }, /* @__PURE__ */ React.createElement(CartesianGrid, { stroke: styles.cartesianGrid.stroke }), /* @__PURE__ */ React.createElement(
184
- XAxis,
185
- {
186
- dataKey: "date",
187
- domain: ["dataMin", "dataMax"],
188
- tickFormatter: overviewGraphTickFormatter,
189
- tickCount: 6,
190
- type: "number",
191
- stroke: styles.axis.fill
192
- }
193
- ), /* @__PURE__ */ React.createElement(
194
- YAxis,
195
- {
196
- domain: [() => 0, "dataMax"],
197
- tick: { fill: styles.axis.fill },
198
- tickFormatter: localizedTickFormatter,
199
- width: styles.yAxis.width,
200
- yAxisId: data.dailyCost.dataKey
201
- }
202
- ), metric && /* @__PURE__ */ React.createElement(
203
- YAxis,
204
- {
205
- domain: ["auto", "auto"],
206
- width: styles.yAxis.width,
207
- yAxisId: data.metric.dataKey,
208
- tickFormatter: (value, index) => localizedTickFormatter(value, index, data.metric.format),
209
- orientation: "right"
210
- }
211
- ), /* @__PURE__ */ React.createElement(
212
- Area,
213
- {
214
- dataKey: data.dailyCost.dataKey,
215
- isAnimationActive: false,
216
- fill: theme.palette.blue,
217
- fillOpacity: 0.4,
218
- stroke: "none",
219
- yAxisId: data.dailyCost.dataKey
220
- }
221
- ), !hideTrendLine && /* @__PURE__ */ React.createElement(
222
- Line,
223
- {
224
- activeDot: false,
225
- dataKey: "trend",
226
- dot: false,
227
- isAnimationActive: false,
228
- strokeWidth: 2,
229
- stroke: theme.palette.blue,
230
- yAxisId: data.dailyCost.dataKey
231
- }
232
- ), metric && /* @__PURE__ */ React.createElement(
233
- Line,
234
- {
235
- dataKey: data.metric.dataKey,
236
- dot: false,
237
- isAnimationActive: false,
238
- strokeWidth: 2,
239
- stroke: theme.palette.magenta,
240
- yAxisId: data.metric.dataKey
241
- }
242
- ), /* @__PURE__ */ React.createElement(Tooltip, { content: tooltipRenderer, animationDuration: 100 }))
243
- ));
244
- };
245
-
246
- const aggregationSum = (aggregation) => aggregation.reduce((total, curAgg) => total + curAgg.amount, 0);
247
-
248
- const LOW_COST_THRESHOLD = 0.1;
249
- const CostOverviewBreakdownChart = ({
250
- costBreakdown,
251
- responsive = true
252
- }) => {
253
- const theme = useTheme();
254
- const classes = useCostOverviewStyles(theme);
255
- const { baseCurrency } = useConfig();
256
- const lastCompleteBillingDate = useLastCompleteBillingDate();
257
- const { duration } = useFilters(mapFiltersToProps);
258
- const [isExpanded, setExpanded] = useState(false);
259
- if (!costBreakdown) {
260
- return null;
261
- }
262
- const flattenedAggregation = costBreakdown.map((cost) => cost.aggregation).flat();
263
- const totalCost = aggregationSum(flattenedAggregation);
264
- const previousPeriodTotal = getPreviousPeriodTotalCost(
265
- flattenedAggregation,
266
- duration,
267
- lastCompleteBillingDate
268
- );
269
- const currentPeriodTotal = totalCost - previousPeriodTotal;
270
- const canExpand = costBreakdown.length >= 8;
271
- const otherCategoryIds = [];
272
- const breakdownsByDate = costBreakdown.reduce(
273
- (breakdownByDate, breakdown) => {
274
- const breakdownTotal = aggregationSum(breakdown.aggregation);
275
- const isOtherCategory = canExpand && breakdownTotal < totalCost * LOW_COST_THRESHOLD;
276
- const updatedBreakdownByDate = { ...breakdownByDate };
277
- if (isOtherCategory) {
278
- otherCategoryIds.push(breakdown.id);
279
- }
280
- breakdown.aggregation.forEach((curAggregation) => {
281
- const costsForDate = updatedBreakdownByDate[curAggregation.date] || {};
282
- updatedBreakdownByDate[curAggregation.date] = {
283
- ...costsForDate,
284
- [breakdown.id]: (costsForDate[breakdown.id] || 0) + curAggregation.amount
285
- };
286
- });
287
- return updatedBreakdownByDate;
288
- },
289
- {}
290
- );
291
- const chartData = Object.keys(breakdownsByDate).map((date) => {
292
- const costsForDate = Object.keys(breakdownsByDate[date]).reduce(
293
- (dateCosts, breakdown) => {
294
- const cost = breakdownsByDate[date][breakdown];
295
- const breakdownCost = !isExpanded && otherCategoryIds.includes(breakdown) ? { Other: (dateCosts.Other || 0) + cost } : { [breakdown]: cost };
296
- return { ...dateCosts, ...breakdownCost };
297
- },
298
- {}
299
- );
300
- return {
301
- ...costsForDate,
302
- date: Date.parse(date)
303
- };
304
- }).sort((a, b) => a.date - b.date);
305
- const sortedBreakdowns = costBreakdown.sort(
306
- (a, b) => aggregationSum(a.aggregation) - aggregationSum(b.aggregation)
307
- );
308
- const renderAreas = () => {
309
- const separatedBreakdowns = sortedBreakdowns.filter(
310
- (breakdown) => breakdown.id !== "Other" && !otherCategoryIds.includes(breakdown.id)
311
- ).map((breakdown) => breakdown.id);
312
- const breakdownsToDisplay = isExpanded ? sortedBreakdowns.map((breakdown) => breakdown.id) : ["Other", ...separatedBreakdowns];
313
- return breakdownsToDisplay.map((breakdown, i) => {
314
- const color = theme.palette.dataViz[(breakdownsToDisplay.length - 1 - i) % (theme.palette.dataViz.length - 1)];
315
- return /* @__PURE__ */ React.createElement(
316
- Area,
317
- {
318
- key: breakdown,
319
- dataKey: breakdown,
320
- isAnimationActive: false,
321
- stackId: "1",
322
- stroke: color,
323
- fill: color,
324
- onClick: () => setExpanded(true),
325
- style: {
326
- cursor: breakdown === "Other" && !isExpanded ? "pointer" : void 0
327
- }
328
- }
329
- );
330
- });
331
- };
332
- const tooltipRenderer = ({ label, payload = [] }) => {
333
- if (isInvalid({ label, payload }))
334
- return null;
335
- const date = typeof label === "number" ? DateTime.fromMillis(label) : DateTime.fromISO(label);
336
- const dateTitle = date.toUTC().toFormat(DEFAULT_DATE_FORMAT);
337
- const formatGraphValueWith = formatGraphValue(baseCurrency);
338
- const items = payload.map((p, i) => ({
339
- label: p.dataKey,
340
- value: formatGraphValueWith(Number(p.value), i),
341
- fill: p.color
342
- }));
343
- const expandText = /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
344
- Divider,
345
- {
346
- style: {
347
- backgroundColor: emphasize(theme.palette.divider, 1),
348
- margin: "10px 0"
349
- }
350
- }
351
- ), /* @__PURE__ */ React.createElement(Box, { display: "flex", justifyContent: "space-between", alignItems: "center" }, /* @__PURE__ */ React.createElement(FullScreenIcon, null), /* @__PURE__ */ React.createElement(Typography, null, "Click to expand")));
352
- return /* @__PURE__ */ React.createElement(BarChartTooltip, { title: dateTitle }, items.reverse().map((item, index) => /* @__PURE__ */ React.createElement(BarChartTooltipItem, { key: `${item.label}-${index}`, item })), canExpand && !isExpanded ? expandText : null);
353
- };
354
- const options = {
355
- previousName: formatPeriod(duration, lastCompleteBillingDate, false),
356
- currentName: formatPeriod(duration, lastCompleteBillingDate, true),
357
- hideMarker: true
358
- };
359
- return /* @__PURE__ */ React.createElement(Box, { display: "flex", flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { display: "flex", flexDirection: "row" }, /* @__PURE__ */ React.createElement(
360
- BarChartLegend,
361
- {
362
- costStart: previousPeriodTotal,
363
- costEnd: currentPeriodTotal,
364
- options
365
- }
366
- )), /* @__PURE__ */ React.createElement(
367
- ResponsiveContainer,
368
- {
369
- width: responsive ? "100%" : classes.container.width,
370
- height: classes.container.height
371
- },
372
- /* @__PURE__ */ React.createElement(
373
- AreaChart,
374
- {
375
- data: chartData,
376
- margin: {
377
- top: 16,
378
- right: 30,
379
- bottom: 40
380
- }
381
- },
382
- /* @__PURE__ */ React.createElement(CartesianGrid, { stroke: classes.cartesianGrid.stroke }),
383
- /* @__PURE__ */ React.createElement(
384
- XAxis,
385
- {
386
- dataKey: "date",
387
- domain: ["dataMin", "dataMax"],
388
- tickFormatter: overviewGraphTickFormatter,
389
- tickCount: 6,
390
- type: "number",
391
- stroke: classes.axis.fill
392
- }
393
- ),
394
- /* @__PURE__ */ React.createElement(
395
- YAxis,
396
- {
397
- domain: [() => 0, "dataMax"],
398
- tick: { fill: classes.axis.fill },
399
- tickFormatter: formatGraphValue(baseCurrency),
400
- width: classes.yAxis.width
401
- }
402
- ),
403
- renderAreas(),
404
- /* @__PURE__ */ React.createElement(Tooltip, { content: tooltipRenderer, animationDuration: 100 })
405
- )
406
- ));
407
- };
408
-
409
- const CostOverviewHeader = ({
410
- title,
411
- subtitle,
412
- children
413
- }) => /* @__PURE__ */ React.createElement(
414
- Box,
415
- {
416
- mt: 2,
417
- ml: 1,
418
- mb: 1,
419
- display: "flex",
420
- flexDirection: "row",
421
- justifyContent: "space-between",
422
- alignItems: "center"
423
- },
424
- /* @__PURE__ */ React.createElement(Box, { minHeight: 40, paddingRight: 5 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5", gutterBottom: true }, title), !!subtitle && /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle2", color: "textSecondary", component: "div" }, subtitle)),
425
- /* @__PURE__ */ React.createElement(Box, { minHeight: 40, maxHeight: 60, display: "flex" }, children)
426
- );
427
-
428
- const MetricSelect = ({
429
- metric,
430
- metrics,
431
- onSelect
432
- }) => {
433
- const classes = useSelectStyles();
434
- function onChange(e) {
435
- if (e.target.value === "none") {
436
- onSelect(null);
437
- } else {
438
- onSelect(e.target.value);
439
- }
440
- }
441
- return /* @__PURE__ */ React.createElement(FormControl, { variant: "outlined" }, /* @__PURE__ */ React.createElement(InputLabel, { shrink: true, id: "metric-select-label" }, "Compare to:"), /* @__PURE__ */ React.createElement(
442
- Select,
443
- {
444
- id: "metric-select",
445
- labelId: "metric-select-label",
446
- labelWidth: 100,
447
- className: classes.select,
448
- value: metric != null ? metric : "none",
449
- onChange
450
- },
451
- /* @__PURE__ */ React.createElement(MenuItem, { className: classes.menuItem, key: "none", value: "none" }, /* @__PURE__ */ React.createElement("em", null, "None")),
452
- metrics.map((m) => /* @__PURE__ */ React.createElement(MenuItem, { className: classes.menuItem, key: m.kind, value: m.kind }, /* @__PURE__ */ React.createElement("b", null, m.name)))
453
- ));
454
- };
455
-
456
- function getDefaultOptions(lastCompleteBillingDate) {
457
- return [
458
- {
459
- value: Duration.P90D,
460
- label: "Past 6 Months"
461
- },
462
- {
463
- value: Duration.P30D,
464
- label: "Past 60 Days"
465
- },
466
- {
467
- value: Duration.P3M,
468
- label: formatLastTwoLookaheadQuarters(lastCompleteBillingDate)
469
- }
470
- ];
471
- }
472
- const PeriodSelect = ({
473
- duration,
474
- onSelect,
475
- options
476
- }) => {
477
- const classes = useSelectStyles();
478
- const lastCompleteBillingDate = useLastCompleteBillingDate();
479
- const optionsOrDefault = options != null ? options : getDefaultOptions(lastCompleteBillingDate);
480
- const handleOnChange = (e) => {
481
- onSelect(e.target.value);
482
- };
483
- const renderValue = (value) => {
484
- const option = findAlways(optionsOrDefault, (o) => o.value === value);
485
- return /* @__PURE__ */ React.createElement("b", null, option.label);
486
- };
487
- return /* @__PURE__ */ React.createElement(
488
- Select,
489
- {
490
- className: classes.select,
491
- variant: "outlined",
492
- onChange: handleOnChange,
493
- value: duration,
494
- renderValue,
495
- "data-testid": "period-select"
496
- },
497
- optionsOrDefault.map((option) => /* @__PURE__ */ React.createElement(
498
- MenuItem,
499
- {
500
- className: classes.menuItem,
501
- key: option.value,
502
- value: option.value,
503
- "data-testid": `period-select-option-${option.value}`
504
- },
505
- option.label
506
- ))
507
- );
508
- };
509
-
510
- const CostOverviewCard = ({
511
- dailyCostData,
512
- metricData
513
- }) => {
514
- var _a;
515
- const theme = useTheme();
516
- const styles = useOverviewTabsStyles(theme);
517
- const config = useConfig();
518
- const [tabIndex, setTabIndex] = useState(0);
519
- const { setDuration, setProject, setMetric, ...filters } = useFilters(mapFiltersToProps);
520
- useEffect(() => {
521
- var _a2;
522
- const lastIndex = Object.keys((_a2 = dailyCostData.groupedCosts) != null ? _a2 : {}).length;
523
- if (tabIndex > lastIndex) {
524
- setTabIndex(0);
525
- }
526
- }, [dailyCostData, tabIndex, setTabIndex]);
527
- const metric = filters.metric ? findAlways(config.metrics, (m) => m.kind === filters.metric) : null;
528
- const breakdownTabs = Object.keys((_a = dailyCostData.groupedCosts) != null ? _a : {}).map(
529
- (key) => ({
530
- id: key,
531
- label: `Breakdown by ${key}`,
532
- title: `Cloud Cost By ${capitalize(key)}`
533
- })
534
- );
535
- const tabs = [
536
- { id: "overview", label: "Total cost", title: "Cloud Cost" }
537
- ].concat(breakdownTabs);
538
- const safeTabIndex = tabIndex > tabs.length - 1 ? 0 : tabIndex;
539
- const OverviewTabs = () => {
540
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
541
- Tabs,
542
- {
543
- indicatorColor: "primary",
544
- onChange: (_, index) => setTabIndex(index),
545
- value: safeTabIndex
546
- },
547
- tabs.map((tab, index) => /* @__PURE__ */ React.createElement(
548
- Tab,
549
- {
550
- className: styles.default,
551
- label: tab.label,
552
- key: tab.id,
553
- value: index,
554
- classes: { selected: styles.selected }
555
- }
556
- ))
557
- ));
558
- };
559
- const showMetricSelect = metricData && config.metrics.length && safeTabIndex === 0;
560
- return /* @__PURE__ */ React.createElement(Card, { style: { position: "relative", overflow: "visible" } }, /* @__PURE__ */ React.createElement(ScrollAnchor, { id: DefaultNavigation.CostOverviewCard }), /* @__PURE__ */ React.createElement(CardContent, null, dailyCostData.groupedCosts && /* @__PURE__ */ React.createElement(OverviewTabs, null), /* @__PURE__ */ React.createElement(CostOverviewHeader, { title: tabs[safeTabIndex].title }, /* @__PURE__ */ React.createElement(PeriodSelect, { duration: filters.duration, onSelect: setDuration })), /* @__PURE__ */ React.createElement(Divider, null), /* @__PURE__ */ React.createElement(Box, { ml: 2, my: 1, display: "flex", flexDirection: "column" }, safeTabIndex === 0 ? /* @__PURE__ */ React.createElement(
561
- CostOverviewChart,
562
- {
563
- dailyCostData,
564
- metric,
565
- metricData
566
- }
567
- ) : /* @__PURE__ */ React.createElement(
568
- CostOverviewBreakdownChart,
569
- {
570
- costBreakdown: dailyCostData.groupedCosts[tabs[safeTabIndex].id]
571
- }
572
- )), /* @__PURE__ */ React.createElement(Box, { display: "flex", justifyContent: "flex-end", alignItems: "center" }, showMetricSelect && /* @__PURE__ */ React.createElement(
573
- MetricSelect,
574
- {
575
- metric: filters.metric,
576
- metrics: config.metrics,
577
- onSelect: setMetric
578
- }
579
- ))));
580
- };
581
-
582
- const mapLoadingToProps = ({ state, actions, dispatch }) => ({
583
- loadingActions: actions,
584
- loadingGroups: state[DefaultLoadingAction.UserGroups],
585
- loadingBillingDate: state[DefaultLoadingAction.LastCompleteBillingDate],
586
- loadingInitial: state[DefaultLoadingAction.CostInsightsInitial],
587
- dispatchInitial: (isLoading) => dispatch({ [DefaultLoadingAction.CostInsightsInitial]: isLoading }),
588
- dispatchInsights: (isLoading) => dispatch({ [DefaultLoadingAction.CostInsightsPage]: isLoading }),
589
- dispatchNone: (loadingActions) => dispatch(getResetState(loadingActions)),
590
- dispatchReset: (loadingActions) => dispatch(getResetStateWithoutInitial(loadingActions))
591
- });
592
-
593
- export { CostOverviewCard as C, PeriodSelect as P, ScrollAnchor as S, mapLoadingToProps as m };
594
- //# sourceMappingURL=selector-D7iXJwd9.esm.js.map