@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
@@ -0,0 +1,142 @@
1
+ import { DateTime } from 'luxon';
2
+ import regression from 'regression';
3
+ import '../types/Alert.esm.js';
4
+ import { DEFAULT_DATE_FORMAT } from '../types/DateFormat.esm.js';
5
+ import { inclusiveEndDateOf, inclusiveStartDateOf } from '../utils/duration.esm.js';
6
+ import { MockEventsInsights, MockBigQueryInsights, MockCloudStorageInsights, MockCloudDataflowInsights, MockComputeEngineInsights } from './mockData.esm.js';
7
+
8
+ function parseIntervals(intervals) {
9
+ const match = intervals.match(
10
+ /\/(?<duration>P\d+[DM])\/(?<date>\d{4}-\d{2}-\d{2})/
11
+ );
12
+ if (Object.keys(match?.groups || {}).length !== 2) {
13
+ throw new Error(`Invalid intervals: ${intervals}`);
14
+ }
15
+ const { duration, date } = match.groups;
16
+ return {
17
+ duration,
18
+ endDate: date
19
+ };
20
+ }
21
+ function aggregationFor(intervals, baseline) {
22
+ const { duration, endDate } = parseIntervals(intervals);
23
+ const inclusiveEndDate = inclusiveEndDateOf(duration, endDate);
24
+ const days = DateTime.fromISO(endDate).diff(
25
+ DateTime.fromISO(inclusiveStartDateOf(duration, inclusiveEndDate)),
26
+ "days"
27
+ ).days;
28
+ function nextDelta() {
29
+ const varianceFromBaseline = 0.15;
30
+ const positiveTrendChance = 0.55;
31
+ const normalization = positiveTrendChance - 1;
32
+ return baseline * (Math.random() + normalization) * varianceFromBaseline;
33
+ }
34
+ return [...Array(days).keys()].reduce(
35
+ (values, i) => {
36
+ const last = values.length ? values[values.length - 1].amount : baseline;
37
+ const date = DateTime.fromISO(
38
+ inclusiveStartDateOf(duration, inclusiveEndDate)
39
+ ).plus({ days: i }).toFormat(DEFAULT_DATE_FORMAT);
40
+ const amount = Math.max(0, last + nextDelta());
41
+ values.push({
42
+ date,
43
+ amount
44
+ });
45
+ return values;
46
+ },
47
+ []
48
+ );
49
+ }
50
+ function changeOf(aggregation) {
51
+ const firstAmount = aggregation.length ? aggregation[0].amount : 0;
52
+ const lastAmount = aggregation.length ? aggregation[aggregation.length - 1].amount : 0;
53
+ if (!firstAmount || !lastAmount) {
54
+ return {
55
+ amount: lastAmount - firstAmount
56
+ };
57
+ }
58
+ return {
59
+ ratio: (lastAmount - firstAmount) / firstAmount,
60
+ amount: lastAmount - firstAmount
61
+ };
62
+ }
63
+ function trendlineOf(aggregation) {
64
+ const data = aggregation.map((a) => [
65
+ Date.parse(a.date) / 1e3,
66
+ a.amount
67
+ ]);
68
+ const result = regression.linear(data, { precision: 5 });
69
+ return {
70
+ slope: result.equation[0],
71
+ intercept: result.equation[1]
72
+ };
73
+ }
74
+ function entityOf(product) {
75
+ switch (product) {
76
+ case "computeEngine":
77
+ return MockComputeEngineInsights;
78
+ case "cloudDataflow":
79
+ return MockCloudDataflowInsights;
80
+ case "cloudStorage":
81
+ return MockCloudStorageInsights;
82
+ case "bigQuery":
83
+ return MockBigQueryInsights;
84
+ case "events":
85
+ return MockEventsInsights;
86
+ default:
87
+ throw new Error(
88
+ `Cannot get insights for ${product}. Make sure product matches product property in app-info.yaml`
89
+ );
90
+ }
91
+ }
92
+ const getGroupedProducts = (intervals) => [
93
+ {
94
+ id: "Cloud Dataflow",
95
+ aggregation: aggregationFor(intervals, 1700)
96
+ },
97
+ {
98
+ id: "Compute Engine",
99
+ aggregation: aggregationFor(intervals, 350)
100
+ },
101
+ {
102
+ id: "Cloud Storage",
103
+ aggregation: aggregationFor(intervals, 1300)
104
+ },
105
+ {
106
+ id: "BigQuery",
107
+ aggregation: aggregationFor(intervals, 2e3)
108
+ },
109
+ {
110
+ id: "Cloud SQL",
111
+ aggregation: aggregationFor(intervals, 750)
112
+ },
113
+ {
114
+ id: "Cloud Spanner",
115
+ aggregation: aggregationFor(intervals, 50)
116
+ },
117
+ {
118
+ id: "Cloud Pub/Sub",
119
+ aggregation: aggregationFor(intervals, 1e3)
120
+ },
121
+ {
122
+ id: "Cloud Bigtable",
123
+ aggregation: aggregationFor(intervals, 250)
124
+ }
125
+ ];
126
+ const getGroupedProjects = (intervals) => [
127
+ {
128
+ id: "project-a",
129
+ aggregation: aggregationFor(intervals, 1700)
130
+ },
131
+ {
132
+ id: "project-b",
133
+ aggregation: aggregationFor(intervals, 350)
134
+ },
135
+ {
136
+ id: "project-c",
137
+ aggregation: aggregationFor(intervals, 1300)
138
+ }
139
+ ];
140
+
141
+ export { aggregationFor, changeOf, entityOf, getGroupedProducts, getGroupedProjects, trendlineOf };
142
+ //# sourceMappingURL=testUtils.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testUtils.esm.js","sources":["../../src/testUtils/testUtils.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DateTime } from 'luxon';\nimport regression, { DataPoint } from 'regression';\nimport { Duration, DEFAULT_DATE_FORMAT } from '../types';\nimport {\n ChangeStatistic,\n Entity,\n Trendline,\n DateAggregation,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { inclusiveEndDateOf, inclusiveStartDateOf } from '../utils/duration';\nimport {\n MockComputeEngineInsights,\n MockCloudDataflowInsights,\n MockCloudStorageInsights,\n MockBigQueryInsights,\n MockEventsInsights,\n} from './mockData';\n\ntype IntervalFields = {\n duration: Duration;\n endDate: string;\n};\n\nfunction parseIntervals(intervals: string): IntervalFields {\n const match = intervals.match(\n /\\/(?<duration>P\\d+[DM])\\/(?<date>\\d{4}-\\d{2}-\\d{2})/,\n );\n if (Object.keys(match?.groups || {}).length !== 2) {\n throw new Error(`Invalid intervals: ${intervals}`);\n }\n const { duration, date } = match!.groups!;\n return {\n duration: duration as Duration,\n endDate: date,\n };\n}\n\nexport function aggregationFor(\n intervals: string,\n baseline: number,\n): DateAggregation[] {\n const { duration, endDate } = parseIntervals(intervals);\n const inclusiveEndDate = inclusiveEndDateOf(duration, endDate);\n const days = DateTime.fromISO(endDate).diff(\n DateTime.fromISO(inclusiveStartDateOf(duration, inclusiveEndDate)),\n 'days',\n ).days;\n\n function nextDelta(): number {\n const varianceFromBaseline = 0.15;\n // Let's give positive vibes in trendlines - higher change for positive delta with >0.5 value\n const positiveTrendChance = 0.55;\n const normalization = positiveTrendChance - 1;\n return baseline * (Math.random() + normalization) * varianceFromBaseline;\n }\n\n return [...Array(days).keys()].reduce(\n (values: DateAggregation[], i: number): DateAggregation[] => {\n const last = values.length ? values[values.length - 1].amount : baseline;\n const date = DateTime.fromISO(\n inclusiveStartDateOf(duration, inclusiveEndDate),\n )\n .plus({ days: i })\n .toFormat(DEFAULT_DATE_FORMAT);\n const amount = Math.max(0, last + nextDelta());\n values.push({\n date: date,\n amount: amount,\n });\n return values;\n },\n [],\n );\n}\n\nexport function changeOf(aggregation: DateAggregation[]): ChangeStatistic {\n const firstAmount = aggregation.length ? aggregation[0].amount : 0;\n const lastAmount = aggregation.length\n ? aggregation[aggregation.length - 1].amount\n : 0;\n\n // if either the first or last amounts are zero, the rate of increase/decrease is infinite\n if (!firstAmount || !lastAmount) {\n return {\n amount: lastAmount - firstAmount,\n };\n }\n\n return {\n ratio: (lastAmount - firstAmount) / firstAmount,\n amount: lastAmount - firstAmount,\n };\n}\n\nexport function trendlineOf(aggregation: DateAggregation[]): Trendline {\n const data: ReadonlyArray<DataPoint> = aggregation.map(a => [\n Date.parse(a.date) / 1000,\n a.amount,\n ]);\n const result = regression.linear(data, { precision: 5 });\n return {\n slope: result.equation[0],\n intercept: result.equation[1],\n };\n}\n\nexport function entityOf(product: string): Entity {\n switch (product) {\n case 'computeEngine':\n return MockComputeEngineInsights;\n case 'cloudDataflow':\n return MockCloudDataflowInsights;\n case 'cloudStorage':\n return MockCloudStorageInsights;\n case 'bigQuery':\n return MockBigQueryInsights;\n case 'events':\n return MockEventsInsights;\n default:\n throw new Error(\n `Cannot get insights for ${product}. Make sure product matches product property in app-info.yaml`,\n );\n }\n}\n\nexport const getGroupedProducts = (intervals: string) => [\n {\n id: 'Cloud Dataflow',\n aggregation: aggregationFor(intervals, 1_700),\n },\n {\n id: 'Compute Engine',\n aggregation: aggregationFor(intervals, 350),\n },\n {\n id: 'Cloud Storage',\n aggregation: aggregationFor(intervals, 1_300),\n },\n {\n id: 'BigQuery',\n aggregation: aggregationFor(intervals, 2_000),\n },\n {\n id: 'Cloud SQL',\n aggregation: aggregationFor(intervals, 750),\n },\n {\n id: 'Cloud Spanner',\n aggregation: aggregationFor(intervals, 50),\n },\n {\n id: 'Cloud Pub/Sub',\n aggregation: aggregationFor(intervals, 1_000),\n },\n {\n id: 'Cloud Bigtable',\n aggregation: aggregationFor(intervals, 250),\n },\n];\n\nexport const getGroupedProjects = (intervals: string) => [\n {\n id: 'project-a',\n aggregation: aggregationFor(intervals, 1_700),\n },\n {\n id: 'project-b',\n aggregation: aggregationFor(intervals, 350),\n },\n {\n id: 'project-c',\n aggregation: aggregationFor(intervals, 1_300),\n },\n];\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { Duration } from './Duration.esm.js';
2
+
3
+ var AlertStatus = /* @__PURE__ */ ((AlertStatus2) => {
4
+ AlertStatus2["Snoozed"] = "snoozed";
5
+ AlertStatus2["Accepted"] = "accepted";
6
+ AlertStatus2["Dismissed"] = "dismissed";
7
+ return AlertStatus2;
8
+ })(AlertStatus || {});
9
+ var AlertDismissReason = /* @__PURE__ */ ((AlertDismissReason2) => {
10
+ AlertDismissReason2["Other"] = "other";
11
+ AlertDismissReason2["Resolved"] = "resolved";
12
+ AlertDismissReason2["Expected"] = "expected";
13
+ AlertDismissReason2["Seasonal"] = "seasonal";
14
+ AlertDismissReason2["Migration"] = "migration";
15
+ AlertDismissReason2["NotApplicable"] = "not-applicable";
16
+ return AlertDismissReason2;
17
+ })(AlertDismissReason || {});
18
+ const AlertDismissOptions = [
19
+ {
20
+ reason: "resolved" /* Resolved */,
21
+ label: "This action item is now resolved."
22
+ },
23
+ {
24
+ reason: "seasonal" /* Seasonal */,
25
+ label: "This is an expected increase at this time of year."
26
+ },
27
+ {
28
+ reason: "migration" /* Migration */,
29
+ label: "This increase is from a migration in process."
30
+ },
31
+ {
32
+ reason: "expected" /* Expected */,
33
+ label: "This is an expected increase due to our team\u2019s priorities."
34
+ },
35
+ {
36
+ reason: "not-applicable" /* NotApplicable */,
37
+ label: "This action item doesn\u2019t make sense for my team."
38
+ },
39
+ {
40
+ reason: "other" /* Other */,
41
+ label: "Other (please specify)"
42
+ }
43
+ ];
44
+ const AlertSnoozeOptions = [
45
+ {
46
+ duration: Duration.P7D,
47
+ label: "1 Week"
48
+ },
49
+ {
50
+ duration: Duration.P30D,
51
+ label: "1 Month"
52
+ },
53
+ {
54
+ duration: Duration.P90D,
55
+ label: "1 Quarter"
56
+ }
57
+ ];
58
+ var DataKey = /* @__PURE__ */ ((DataKey2) => {
59
+ DataKey2["Previous"] = "previous";
60
+ DataKey2["Current"] = "current";
61
+ DataKey2["Name"] = "name";
62
+ return DataKey2;
63
+ })(DataKey || {});
64
+
65
+ export { AlertDismissOptions, AlertDismissReason, AlertSnoozeOptions, AlertStatus, DataKey };
66
+ //# sourceMappingURL=Alert.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Alert.esm.js","sources":["../../src/types/Alert.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ForwardRefExoticComponent, RefAttributes } from 'react';\nimport {\n ChangeStatistic,\n Maybe,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { Duration } from './Duration';\n\n/**\n * Generic alert type with required fields for display. The `element` field will be rendered in\n * the Cost Insights \"Action Items\" section. This should use data fetched in the CostInsightsApi\n * implementation to render an InfoCard or other visualization.\n *\n * The alert type exposes hooks which can be used to enable and access various events,\n * such as when a user dismisses or snoozes an alert. Default forms and buttons\n * will be rendered if a hook is defined.\n *\n * Each default form can be overridden with a custom component. It must be implemented using\n * React.forwardRef. See https://reactjs.org/docs/forwarding-refs\n *\n * Errors thrown within hooks will generate a snackbar error notification.\n *\n * @public\n */\nexport type Alert = {\n title: string | JSX.Element;\n subtitle: string | JSX.Element;\n element?: JSX.Element;\n status?: AlertStatus;\n url?: string;\n buttonText?: string; // Default: View Instructions\n SnoozeForm?: Maybe<AlertForm>;\n AcceptForm?: Maybe<AlertForm>;\n DismissForm?: Maybe<AlertForm>;\n onSnoozed?(options: AlertOptions): Promise<Alert[]>;\n onAccepted?(options: AlertOptions): Promise<Alert[]>;\n onDismissed?(options: AlertOptions): Promise<Alert[]>;\n};\n\n/** @public */\nexport type AlertForm<\n A extends Alert = any,\n Data = any,\n> = ForwardRefExoticComponent<\n AlertFormProps<A, Data> & RefAttributes<HTMLFormElement>\n>;\n\n/** @public */\nexport interface AlertOptions<T = any> {\n data: T;\n group: string;\n}\n\n/**\n * Default snooze form intervals are expressed using an ISO 8601 repeating interval string.\n * For example, R1/P7D/2020-09-02 for 1 week or R1/P30D/2020-09-02 for 1 month.\n *\n * For example, if a user dismisses an alert on Monday January 01 for 1 week,\n * it can be re-served on Monday, January 08. 7 calendar days from January 02,\n * inclusive of the last day.\n *\n * https://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals\n *\n * @public\n */\nexport interface AlertSnoozeFormData {\n intervals: string;\n}\n\n/** @public */\nexport interface AlertDismissFormData {\n other: Maybe<string>;\n reason: AlertDismissReason;\n feedback: Maybe<string>;\n}\n\n// TODO: Convert enum to literal\n/** @public */\nexport enum AlertStatus {\n Snoozed = 'snoozed',\n Accepted = 'accepted',\n Dismissed = 'dismissed',\n}\n\n/** @public */\nexport type AlertFormProps<A extends Alert, FormData = {}> = {\n alert: A;\n onSubmit: (data: FormData) => void;\n disableSubmit: (isDisabled: boolean) => void;\n};\n\n/** @public */\nexport interface AlertDismissOption {\n label: string;\n reason: string;\n}\n\n/** @public */\nexport enum AlertDismissReason {\n Other = 'other',\n Resolved = 'resolved',\n Expected = 'expected',\n Seasonal = 'seasonal',\n Migration = 'migration',\n NotApplicable = 'not-applicable',\n}\n\n/** @public */\nexport const AlertDismissOptions: AlertDismissOption[] = [\n {\n reason: AlertDismissReason.Resolved,\n label: 'This action item is now resolved.',\n },\n {\n reason: AlertDismissReason.Seasonal,\n label: 'This is an expected increase at this time of year.',\n },\n {\n reason: AlertDismissReason.Migration,\n label: 'This increase is from a migration in process.',\n },\n {\n reason: AlertDismissReason.Expected,\n label: 'This is an expected increase due to our team’s priorities.',\n },\n {\n reason: AlertDismissReason.NotApplicable,\n label: 'This action item doesn’t make sense for my team.',\n },\n {\n reason: AlertDismissReason.Other,\n label: 'Other (please specify)',\n },\n];\n\n/** @public */\nexport type AlertSnoozeOption = {\n label: string;\n duration: Duration;\n};\n\n/** @public */\nexport const AlertSnoozeOptions: AlertSnoozeOption[] = [\n {\n duration: Duration.P7D,\n label: '1 Week',\n },\n {\n duration: Duration.P30D,\n label: '1 Month',\n },\n {\n duration: Duration.P90D,\n label: '1 Quarter',\n },\n];\n\n/** @public */\nexport interface AlertCost {\n id: string;\n aggregation: [number, number];\n}\n\n/** @public */\nexport interface ResourceData {\n previous: number;\n current: number;\n name: Maybe<string>;\n}\n\n/** @public */\nexport interface BarChartOptions {\n previousFill: string;\n currentFill: string;\n previousName: string;\n currentName: string;\n}\n\n/**\n * @public\n * @deprecated use BarChartOptions instead\n */\nexport interface BarChartData extends BarChartOptions {}\n\n/** @public */\nexport enum DataKey {\n Previous = 'previous',\n Current = 'current',\n Name = 'name',\n}\n\n/** @public */\nexport interface ProjectGrowthData {\n project: string;\n periodStart: string;\n periodEnd: string;\n aggregation: [number, number];\n change: ChangeStatistic;\n products: Array<AlertCost>;\n}\n\n/** @public */\nexport interface UnlabeledDataflowData {\n periodStart: string;\n periodEnd: string;\n projects: Array<UnlabeledDataflowAlertProject>;\n unlabeledCost: number;\n labeledCost: number;\n}\n\n/** @public */\nexport interface UnlabeledDataflowAlertProject {\n id: string;\n unlabeledCost: number;\n labeledCost: number;\n}\n"],"names":["AlertStatus","AlertDismissReason","DataKey"],"mappings":";;AA6FY,IAAA,WAAA,qBAAAA,YAAL,KAAA;AACL,EAAAA,aAAA,SAAU,CAAA,GAAA,SAAA,CAAA;AACV,EAAAA,aAAA,UAAW,CAAA,GAAA,UAAA,CAAA;AACX,EAAAA,aAAA,WAAY,CAAA,GAAA,WAAA,CAAA;AAHF,EAAAA,OAAAA,YAAAA,CAAAA;AAAA,CAAA,EAAA,WAAA,IAAA,EAAA,EAAA;AAoBA,IAAA,kBAAA,qBAAAC,mBAAL,KAAA;AACL,EAAAA,oBAAA,OAAQ,CAAA,GAAA,OAAA,CAAA;AACR,EAAAA,oBAAA,UAAW,CAAA,GAAA,UAAA,CAAA;AACX,EAAAA,oBAAA,UAAW,CAAA,GAAA,UAAA,CAAA;AACX,EAAAA,oBAAA,UAAW,CAAA,GAAA,UAAA,CAAA;AACX,EAAAA,oBAAA,WAAY,CAAA,GAAA,WAAA,CAAA;AACZ,EAAAA,oBAAA,eAAgB,CAAA,GAAA,gBAAA,CAAA;AANN,EAAAA,OAAAA,mBAAAA,CAAAA;AAAA,CAAA,EAAA,kBAAA,IAAA,EAAA,EAAA;AAUL,MAAM,mBAA4C,GAAA;AAAA,EACvD;AAAA,IACE,MAAQ,EAAA,UAAA;AAAA,IACR,KAAO,EAAA,mCAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,MAAQ,EAAA,UAAA;AAAA,IACR,KAAO,EAAA,oDAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,MAAQ,EAAA,WAAA;AAAA,IACR,KAAO,EAAA,+CAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,MAAQ,EAAA,UAAA;AAAA,IACR,KAAO,EAAA,iEAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,MAAQ,EAAA,gBAAA;AAAA,IACR,KAAO,EAAA,uDAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,MAAQ,EAAA,OAAA;AAAA,IACR,KAAO,EAAA,wBAAA;AAAA,GACT;AACF,EAAA;AASO,MAAM,kBAA0C,GAAA;AAAA,EACrD;AAAA,IACE,UAAU,QAAS,CAAA,GAAA;AAAA,IACnB,KAAO,EAAA,QAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,UAAU,QAAS,CAAA,IAAA;AAAA,IACnB,KAAO,EAAA,SAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,UAAU,QAAS,CAAA,IAAA;AAAA,IACnB,KAAO,EAAA,WAAA;AAAA,GACT;AACF,EAAA;AA8BY,IAAA,OAAA,qBAAAC,QAAL,KAAA;AACL,EAAAA,SAAA,UAAW,CAAA,GAAA,UAAA,CAAA;AACX,EAAAA,SAAA,SAAU,CAAA,GAAA,SAAA,CAAA;AACV,EAAAA,SAAA,MAAO,CAAA,GAAA,MAAA,CAAA;AAHG,EAAAA,OAAAA,QAAAA,CAAAA;AAAA,CAAA,EAAA,OAAA,IAAA,EAAA;;;;"}
@@ -0,0 +1,15 @@
1
+ const EngineerThreshold = 0.5;
2
+ var ChangeThreshold = /* @__PURE__ */ ((ChangeThreshold2) => {
3
+ ChangeThreshold2[ChangeThreshold2["upper"] = 0.05] = "upper";
4
+ ChangeThreshold2[ChangeThreshold2["lower"] = -0.05] = "lower";
5
+ return ChangeThreshold2;
6
+ })(ChangeThreshold || {});
7
+ var GrowthType = /* @__PURE__ */ ((GrowthType2) => {
8
+ GrowthType2[GrowthType2["Negligible"] = 0] = "Negligible";
9
+ GrowthType2[GrowthType2["Savings"] = 1] = "Savings";
10
+ GrowthType2[GrowthType2["Excess"] = 2] = "Excess";
11
+ return GrowthType2;
12
+ })(GrowthType || {});
13
+
14
+ export { ChangeThreshold, EngineerThreshold, GrowthType };
15
+ //# sourceMappingURL=ChangeStatistic.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChangeStatistic.esm.js","sources":["../../src/types/ChangeStatistic.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** @public */\nexport const EngineerThreshold = 0.5;\n\n/** @public */\nexport enum ChangeThreshold {\n upper = 0.05,\n lower = -0.05,\n}\n\n/** @public */\nexport enum GrowthType {\n Negligible,\n Savings,\n Excess,\n}\n"],"names":["ChangeThreshold","GrowthType"],"mappings":"AAiBO,MAAM,iBAAoB,GAAA,IAAA;AAGrB,IAAA,eAAA,qBAAAA,gBAAL,KAAA;AACL,EAAAA,gBAAAA,CAAAA,gBAAAA,CAAA,WAAQ,IAAR,CAAA,GAAA,OAAA,CAAA;AACA,EAAAA,gBAAAA,CAAAA,gBAAAA,CAAA,WAAQ,CAAR,IAAA,CAAA,GAAA,OAAA,CAAA;AAFU,EAAAA,OAAAA,gBAAAA,CAAAA;AAAA,CAAA,EAAA,eAAA,IAAA,EAAA,EAAA;AAMA,IAAA,UAAA,qBAAAC,WAAL,KAAA;AACL,EAAAA,WAAA,CAAA,WAAA,CAAA,YAAA,CAAA,GAAA,CAAA,CAAA,GAAA,YAAA,CAAA;AACA,EAAAA,WAAA,CAAA,WAAA,CAAA,SAAA,CAAA,GAAA,CAAA,CAAA,GAAA,SAAA,CAAA;AACA,EAAAA,WAAA,CAAA,WAAA,CAAA,QAAA,CAAA,GAAA,CAAA,CAAA,GAAA,QAAA,CAAA;AAHU,EAAAA,OAAAA,WAAAA,CAAAA;AAAA,CAAA,EAAA,UAAA,IAAA,EAAA;;;;"}
@@ -0,0 +1,10 @@
1
+ var CurrencyType = /* @__PURE__ */ ((CurrencyType2) => {
2
+ CurrencyType2["USD"] = "USD";
3
+ CurrencyType2["CarbonOffsetTons"] = "CARBON_OFFSET_TONS";
4
+ CurrencyType2["Beers"] = "BEERS";
5
+ CurrencyType2["IceCream"] = "PINTS_OF_ICE_CREAM";
6
+ return CurrencyType2;
7
+ })(CurrencyType || {});
8
+
9
+ export { CurrencyType };
10
+ //# sourceMappingURL=CurrencyType.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CurrencyType.esm.js","sources":["../../src/types/CurrencyType.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** @public */\nexport enum CurrencyType {\n USD = 'USD',\n CarbonOffsetTons = 'CARBON_OFFSET_TONS',\n Beers = 'BEERS',\n IceCream = 'PINTS_OF_ICE_CREAM',\n}\n"],"names":["CurrencyType"],"mappings":"AAiBY,IAAA,YAAA,qBAAAA,aAAL,KAAA;AACL,EAAAA,cAAA,KAAM,CAAA,GAAA,KAAA,CAAA;AACN,EAAAA,cAAA,kBAAmB,CAAA,GAAA,oBAAA,CAAA;AACnB,EAAAA,cAAA,OAAQ,CAAA,GAAA,OAAA,CAAA;AACR,EAAAA,cAAA,UAAW,CAAA,GAAA,oBAAA,CAAA;AAJD,EAAAA,OAAAA,aAAAA,CAAAA;AAAA,CAAA,EAAA,YAAA,IAAA,EAAA;;;;"}
@@ -0,0 +1,4 @@
1
+ const DEFAULT_DATE_FORMAT = "yyyy-LL-dd";
2
+
3
+ export { DEFAULT_DATE_FORMAT };
4
+ //# sourceMappingURL=DateFormat.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DateFormat.esm.js","sources":["../../src/types/DateFormat.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** @public */\nexport const DEFAULT_DATE_FORMAT = 'yyyy-LL-dd';\n"],"names":[],"mappings":"AAiBO,MAAM,mBAAsB,GAAA;;;;"}
@@ -0,0 +1,10 @@
1
+ var Duration = /* @__PURE__ */ ((Duration2) => {
2
+ Duration2["P7D"] = "P7D";
3
+ Duration2["P30D"] = "P30D";
4
+ Duration2["P90D"] = "P90D";
5
+ Duration2["P3M"] = "P3M";
6
+ return Duration2;
7
+ })(Duration || {});
8
+
9
+ export { Duration };
10
+ //# sourceMappingURL=Duration.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Duration.esm.js","sources":["../../src/types/Duration.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Time periods for cost comparison; slight abuse of ISO 8601 periods. We take P3M to mean\n * 'last completed quarter', and P30D/P90D to be '[month|quarter] relative to today'. So if\n * it's September 15, P3M represents costs for Q2 and P30D represents August 16 -\n * September 15.\n *\n * @public\n */\nexport enum Duration {\n P7D = 'P7D',\n P30D = 'P30D',\n P90D = 'P90D',\n P3M = 'P3M',\n}\n"],"names":["Duration"],"mappings":"AAwBY,IAAA,QAAA,qBAAAA,SAAL,KAAA;AACL,EAAAA,UAAA,KAAM,CAAA,GAAA,KAAA,CAAA;AACN,EAAAA,UAAA,MAAO,CAAA,GAAA,MAAA,CAAA;AACP,EAAAA,UAAA,MAAO,CAAA,GAAA,MAAA,CAAA;AACP,EAAAA,UAAA,KAAM,CAAA,GAAA,KAAA,CAAA;AAJI,EAAAA,OAAAA,SAAAA,CAAAA;AAAA,CAAA,EAAA,QAAA,IAAA,EAAA;;;;"}
@@ -0,0 +1,12 @@
1
+ var IconType = /* @__PURE__ */ ((IconType2) => {
2
+ IconType2["Compute"] = "compute";
3
+ IconType2["Data"] = "data";
4
+ IconType2["Database"] = "database";
5
+ IconType2["Storage"] = "storage";
6
+ IconType2["Search"] = "search";
7
+ IconType2["ML"] = "ml";
8
+ return IconType2;
9
+ })(IconType || {});
10
+
11
+ export { IconType };
12
+ //# sourceMappingURL=Icon.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Icon.esm.js","sources":["../../src/types/Icon.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** @public */\nexport type Icon = {\n kind: string;\n component: JSX.Element;\n};\n\n/** @public */\nexport enum IconType {\n Compute = 'compute',\n Data = 'data',\n Database = 'database',\n Storage = 'storage',\n Search = 'search',\n ML = 'ml',\n}\n"],"names":["IconType"],"mappings":"AAuBY,IAAA,QAAA,qBAAAA,SAAL,KAAA;AACL,EAAAA,UAAA,SAAU,CAAA,GAAA,SAAA,CAAA;AACV,EAAAA,UAAA,MAAO,CAAA,GAAA,MAAA,CAAA;AACP,EAAAA,UAAA,UAAW,CAAA,GAAA,UAAA,CAAA;AACX,EAAAA,UAAA,SAAU,CAAA,GAAA,SAAA,CAAA;AACV,EAAAA,UAAA,QAAS,CAAA,GAAA,QAAA,CAAA;AACT,EAAAA,UAAA,IAAK,CAAA,GAAA,IAAA,CAAA;AANK,EAAAA,OAAAA,SAAAA,CAAAA;AAAA,CAAA,EAAA,QAAA,IAAA,EAAA;;;;"}
@@ -0,0 +1,72 @@
1
+ import { AlertStatus } from '../types/Alert.esm.js';
2
+ import { AlertAcceptForm } from '../forms/AlertAcceptForm.esm.js';
3
+ import { AlertSnoozeForm } from '../forms/AlertSnoozeForm.esm.js';
4
+ import { AlertDismissForm } from '../forms/AlertDismissForm.esm.js';
5
+
6
+ const createAlertHandler = (status) => (alert) => alert.status === status;
7
+ const isAlertActive = (alert) => !hasProperty(alert, "status");
8
+ const isAlertSnoozed = createAlertHandler(AlertStatus.Snoozed);
9
+ const isAlertAccepted = createAlertHandler(AlertStatus.Accepted);
10
+ const isAlertDismissed = createAlertHandler(AlertStatus.Dismissed);
11
+ const createStatusHandler = (status) => (s) => s === status;
12
+ const isStatusSnoozed = createStatusHandler(AlertStatus.Snoozed);
13
+ const isStatusAccepted = createStatusHandler(AlertStatus.Accepted);
14
+ const isStatusDismissed = createStatusHandler(AlertStatus.Dismissed);
15
+ const createAlertEventHandler = (onEvent) => (alert) => hasProperty(alert, onEvent);
16
+ const isSnoozeEnabled = createAlertEventHandler("onSnoozed");
17
+ const isAcceptEnabled = createAlertEventHandler("onAccepted");
18
+ const isDismissEnabled = createAlertEventHandler("onDismissed");
19
+ const createFormEnabledHandler = (Form) => (alert) => {
20
+ if (!alert) return false;
21
+ if (alert[Form] === null) return false;
22
+ switch (Form) {
23
+ case "SnoozeForm":
24
+ return isSnoozeEnabled(alert);
25
+ case "AcceptForm":
26
+ return isAcceptEnabled(alert);
27
+ case "DismissForm":
28
+ return isDismissEnabled(alert);
29
+ default:
30
+ return false;
31
+ }
32
+ };
33
+ const isSnoozeFormEnabled = createFormEnabledHandler("SnoozeForm");
34
+ const isAcceptFormEnabled = createFormEnabledHandler("AcceptForm");
35
+ const isDismissFormEnabled = createFormEnabledHandler("DismissForm");
36
+ function formOf(alert, status) {
37
+ switch (status) {
38
+ case AlertStatus.Snoozed: {
39
+ const SnoozeForm = alert?.SnoozeForm ?? AlertSnoozeForm;
40
+ return isSnoozeFormEnabled(alert) ? SnoozeForm : null;
41
+ }
42
+ case AlertStatus.Accepted: {
43
+ const AcceptForm = alert?.AcceptForm ?? AlertAcceptForm;
44
+ return isAcceptFormEnabled(alert) ? AcceptForm : null;
45
+ }
46
+ case AlertStatus.Dismissed: {
47
+ const DismissForm = alert?.DismissForm ?? AlertDismissForm;
48
+ return isDismissFormEnabled(alert) ? DismissForm : null;
49
+ }
50
+ default:
51
+ return null;
52
+ }
53
+ }
54
+ function choose(status, values, none) {
55
+ switch (status) {
56
+ case AlertStatus.Snoozed:
57
+ return values[0];
58
+ case AlertStatus.Accepted:
59
+ return values[1];
60
+ case AlertStatus.Dismissed:
61
+ return values[2];
62
+ default:
63
+ return none;
64
+ }
65
+ }
66
+ function hasProperty(alert, prop) {
67
+ return prop in (alert ?? {});
68
+ }
69
+ const sumOfAllAlerts = (sum, alerts) => sum + alerts.length;
70
+
71
+ export { choose, formOf, hasProperty, isAcceptEnabled, isAcceptFormEnabled, isAlertAccepted, isAlertActive, isAlertDismissed, isAlertSnoozed, isDismissEnabled, isDismissFormEnabled, isSnoozeEnabled, isSnoozeFormEnabled, isStatusAccepted, isStatusDismissed, isStatusSnoozed, sumOfAllAlerts };
72
+ //# sourceMappingURL=alerts.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alerts.esm.js","sources":["../../src/utils/alerts.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Alert, AlertForm, AlertStatus } from '../types';\nimport { Maybe } from '@backstage-community/plugin-cost-insights-common';\nimport { AlertAcceptForm, AlertDismissForm, AlertSnoozeForm } from '../forms';\n\nconst createAlertHandler = (status?: AlertStatus) => (alert: Alert) =>\n alert.status === status;\nexport const isAlertActive = (alert: Alert) => !hasProperty(alert, 'status');\nexport const isAlertSnoozed = createAlertHandler(AlertStatus.Snoozed);\nexport const isAlertAccepted = createAlertHandler(AlertStatus.Accepted);\nexport const isAlertDismissed = createAlertHandler(AlertStatus.Dismissed);\n\nconst createStatusHandler = (status: AlertStatus) => (s: Maybe<AlertStatus>) =>\n s === status;\nexport const isStatusSnoozed = createStatusHandler(AlertStatus.Snoozed);\nexport const isStatusAccepted = createStatusHandler(AlertStatus.Accepted);\nexport const isStatusDismissed = createStatusHandler(AlertStatus.Dismissed);\n\nconst createAlertEventHandler =\n (onEvent: 'onSnoozed' | 'onAccepted' | 'onDismissed') =>\n (alert: Maybe<Alert>): boolean =>\n hasProperty(alert, onEvent);\nexport const isSnoozeEnabled = createAlertEventHandler('onSnoozed');\nexport const isAcceptEnabled = createAlertEventHandler('onAccepted');\nexport const isDismissEnabled = createAlertEventHandler('onDismissed');\n\nconst createFormEnabledHandler =\n (Form: 'SnoozeForm' | 'AcceptForm' | 'DismissForm') =>\n (alert: Maybe<Alert>): boolean => {\n if (!alert) return false;\n if (alert[Form] === null) return false;\n switch (Form) {\n case 'SnoozeForm':\n return isSnoozeEnabled(alert);\n case 'AcceptForm':\n return isAcceptEnabled(alert);\n case 'DismissForm':\n return isDismissEnabled(alert);\n default:\n return false;\n }\n };\nexport const isSnoozeFormEnabled = createFormEnabledHandler('SnoozeForm');\nexport const isAcceptFormEnabled = createFormEnabledHandler('AcceptForm');\nexport const isDismissFormEnabled = createFormEnabledHandler('DismissForm');\n\n/**\n * Utility for determining if a form is disabled.\n * When a form is disabled, the dialog button's type should convert from submit to button.\n * @param alert\n * @param status\n */\nexport const isFormDisabled = (\n alert: Maybe<Alert>,\n status: Maybe<AlertStatus>,\n): boolean => {\n switch (status) {\n case AlertStatus.Snoozed:\n return alert?.SnoozeForm === null;\n case AlertStatus.Accepted:\n return alert?.AcceptForm === null;\n case AlertStatus.Dismissed:\n return alert?.DismissForm === null;\n default:\n return false;\n }\n};\n\nexport function formOf(\n alert: Maybe<Alert>,\n status: Maybe<AlertStatus>,\n): Maybe<AlertForm> {\n switch (status) {\n case AlertStatus.Snoozed: {\n const SnoozeForm = alert?.SnoozeForm ?? AlertSnoozeForm;\n return isSnoozeFormEnabled(alert) ? SnoozeForm : null;\n }\n case AlertStatus.Accepted: {\n const AcceptForm = alert?.AcceptForm ?? AlertAcceptForm;\n return isAcceptFormEnabled(alert) ? AcceptForm : null;\n }\n case AlertStatus.Dismissed: {\n const DismissForm = alert?.DismissForm ?? AlertDismissForm;\n return isDismissFormEnabled(alert) ? DismissForm : null;\n }\n default:\n return null;\n }\n}\n\n/**\n * Utility for choosing from a fixed set of values for a given alert status.\n * @param status\n * @param values\n */\nexport function choose<T>(\n status: Maybe<AlertStatus>,\n values: [T, T, T],\n none: T,\n): T {\n switch (status) {\n case AlertStatus.Snoozed:\n return values[0];\n case AlertStatus.Accepted:\n return values[1];\n case AlertStatus.Dismissed:\n return values[2];\n default:\n return none;\n }\n}\n\nexport function hasProperty(alert: Maybe<Alert>, prop: keyof Alert): boolean {\n return prop in (alert ?? {});\n}\n\nexport const sumOfAllAlerts = (sum: number, alerts: Alert[]) =>\n sum + alerts.length;\n"],"names":[],"mappings":";;;;;AAoBA,MAAM,qBAAqB,CAAC,MAAA,KAAyB,CAAC,KAAA,KACpD,MAAM,MAAW,KAAA,MAAA,CAAA;AACZ,MAAM,gBAAgB,CAAC,KAAA,KAAiB,CAAC,WAAA,CAAY,OAAO,QAAQ,EAAA;AAC9D,MAAA,cAAA,GAAiB,kBAAmB,CAAA,WAAA,CAAY,OAAO,EAAA;AACvD,MAAA,eAAA,GAAkB,kBAAmB,CAAA,WAAA,CAAY,QAAQ,EAAA;AACzD,MAAA,gBAAA,GAAmB,kBAAmB,CAAA,WAAA,CAAY,SAAS,EAAA;AAExE,MAAM,mBAAsB,GAAA,CAAC,MAAwB,KAAA,CAAC,MACpD,CAAM,KAAA,MAAA,CAAA;AACK,MAAA,eAAA,GAAkB,mBAAoB,CAAA,WAAA,CAAY,OAAO,EAAA;AACzD,MAAA,gBAAA,GAAmB,mBAAoB,CAAA,WAAA,CAAY,QAAQ,EAAA;AAC3D,MAAA,iBAAA,GAAoB,mBAAoB,CAAA,WAAA,CAAY,SAAS,EAAA;AAE1E,MAAM,0BACJ,CAAC,OAAA,KACD,CAAC,KACC,KAAA,WAAA,CAAY,OAAO,OAAO,CAAA,CAAA;AACjB,MAAA,eAAA,GAAkB,wBAAwB,WAAW,EAAA;AACrD,MAAA,eAAA,GAAkB,wBAAwB,YAAY,EAAA;AACtD,MAAA,gBAAA,GAAmB,wBAAwB,aAAa,EAAA;AAErE,MAAM,wBACJ,GAAA,CAAC,IACD,KAAA,CAAC,KAAiC,KAAA;AAChC,EAAI,IAAA,CAAC,OAAc,OAAA,KAAA,CAAA;AACnB,EAAA,IAAI,KAAM,CAAA,IAAI,CAAM,KAAA,IAAA,EAAa,OAAA,KAAA,CAAA;AACjC,EAAA,QAAQ,IAAM;AAAA,IACZ,KAAK,YAAA;AACH,MAAA,OAAO,gBAAgB,KAAK,CAAA,CAAA;AAAA,IAC9B,KAAK,YAAA;AACH,MAAA,OAAO,gBAAgB,KAAK,CAAA,CAAA;AAAA,IAC9B,KAAK,aAAA;AACH,MAAA,OAAO,iBAAiB,KAAK,CAAA,CAAA;AAAA,IAC/B;AACE,MAAO,OAAA,KAAA,CAAA;AAAA,GACX;AACF,CAAA,CAAA;AACW,MAAA,mBAAA,GAAsB,yBAAyB,YAAY,EAAA;AAC3D,MAAA,mBAAA,GAAsB,yBAAyB,YAAY,EAAA;AAC3D,MAAA,oBAAA,GAAuB,yBAAyB,aAAa,EAAA;AAwB1D,SAAA,MAAA,CACd,OACA,MACkB,EAAA;AAClB,EAAA,QAAQ,MAAQ;AAAA,IACd,KAAK,YAAY,OAAS,EAAA;AACxB,MAAM,MAAA,UAAA,GAAa,OAAO,UAAc,IAAA,eAAA,CAAA;AACxC,MAAO,OAAA,mBAAA,CAAoB,KAAK,CAAA,GAAI,UAAa,GAAA,IAAA,CAAA;AAAA,KACnD;AAAA,IACA,KAAK,YAAY,QAAU,EAAA;AACzB,MAAM,MAAA,UAAA,GAAa,OAAO,UAAc,IAAA,eAAA,CAAA;AACxC,MAAO,OAAA,mBAAA,CAAoB,KAAK,CAAA,GAAI,UAAa,GAAA,IAAA,CAAA;AAAA,KACnD;AAAA,IACA,KAAK,YAAY,SAAW,EAAA;AAC1B,MAAM,MAAA,WAAA,GAAc,OAAO,WAAe,IAAA,gBAAA,CAAA;AAC1C,MAAO,OAAA,oBAAA,CAAqB,KAAK,CAAA,GAAI,WAAc,GAAA,IAAA,CAAA;AAAA,KACrD;AAAA,IACA;AACE,MAAO,OAAA,IAAA,CAAA;AAAA,GACX;AACF,CAAA;AAOgB,SAAA,MAAA,CACd,MACA,EAAA,MAAA,EACA,IACG,EAAA;AACH,EAAA,QAAQ,MAAQ;AAAA,IACd,KAAK,WAAY,CAAA,OAAA;AACf,MAAA,OAAO,OAAO,CAAC,CAAA,CAAA;AAAA,IACjB,KAAK,WAAY,CAAA,QAAA;AACf,MAAA,OAAO,OAAO,CAAC,CAAA,CAAA;AAAA,IACjB,KAAK,WAAY,CAAA,SAAA;AACf,MAAA,OAAO,OAAO,CAAC,CAAA,CAAA;AAAA,IACjB;AACE,MAAO,OAAA,IAAA,CAAA;AAAA,GACX;AACF,CAAA;AAEgB,SAAA,WAAA,CAAY,OAAqB,IAA4B,EAAA;AAC3E,EAAO,OAAA,IAAA,KAAS,SAAS,EAAC,CAAA,CAAA;AAC5B,CAAA;AAEO,MAAM,cAAiB,GAAA,CAAC,GAAa,EAAA,MAAA,KAC1C,MAAM,MAAO,CAAA;;;;"}
@@ -0,0 +1,29 @@
1
+ function notEmpty(value) {
2
+ return !isNull(value) && !isUndefined(value);
3
+ }
4
+ function isUndefined(value) {
5
+ return value === void 0;
6
+ }
7
+ function isNull(value) {
8
+ return value === null;
9
+ }
10
+ function assertNever(x) {
11
+ throw new Error(`Exhaustiveness check failed: ${x}`);
12
+ }
13
+ function assertAlways(argument) {
14
+ if (argument === void 0) {
15
+ throw new TypeError(
16
+ "Expected to always find a value but received undefined"
17
+ );
18
+ }
19
+ return argument;
20
+ }
21
+ function findAlways(collection, callback) {
22
+ return assertAlways(collection.find(callback));
23
+ }
24
+ function findAnyKey(record) {
25
+ return Object.keys(record ?? {}).find((_) => true);
26
+ }
27
+
28
+ export { assertAlways, assertNever, findAlways, findAnyKey, isNull, isUndefined, notEmpty };
29
+ //# sourceMappingURL=assert.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert.esm.js","sources":["../../src/utils/assert.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function notEmpty<TValue>(\n value: TValue | null | undefined,\n): value is TValue {\n return !isNull(value) && !isUndefined(value);\n}\n\nexport function isUndefined(value: any): value is undefined {\n return value === undefined;\n}\n\nexport function isNull(value: any): boolean {\n return value === null;\n}\n\n// Utility for exhaustiveness checking in switch statements\nexport function assertNever(x: never): never {\n throw new Error(`Exhaustiveness check failed: ${x}`);\n}\n\nexport function assertAlways<T>(argument: T | undefined): T {\n if (argument === undefined) {\n throw new TypeError(\n 'Expected to always find a value but received undefined',\n );\n }\n return argument;\n}\n\n// Utility for working with static lists; asserts a value will always be found or\n// throws an error\nexport function findAlways<T>(\n collection: T[],\n callback: (el: T) => boolean,\n): T {\n return assertAlways(collection.find(callback));\n}\n\nexport function findAnyKey<T>(\n record: Record<string, T> | undefined,\n): string | undefined {\n return Object.keys(record ?? {}).find(_ => true);\n}\n"],"names":[],"mappings":"AAgBO,SAAS,SACd,KACiB,EAAA;AACjB,EAAA,OAAO,CAAC,MAAO,CAAA,KAAK,CAAK,IAAA,CAAC,YAAY,KAAK,CAAA,CAAA;AAC7C,CAAA;AAEO,SAAS,YAAY,KAAgC,EAAA;AAC1D,EAAA,OAAO,KAAU,KAAA,KAAA,CAAA,CAAA;AACnB,CAAA;AAEO,SAAS,OAAO,KAAqB,EAAA;AAC1C,EAAA,OAAO,KAAU,KAAA,IAAA,CAAA;AACnB,CAAA;AAGO,SAAS,YAAY,CAAiB,EAAA;AAC3C,EAAA,MAAM,IAAI,KAAA,CAAM,CAAgC,6BAAA,EAAA,CAAC,CAAE,CAAA,CAAA,CAAA;AACrD,CAAA;AAEO,SAAS,aAAgB,QAA4B,EAAA;AAC1D,EAAA,IAAI,aAAa,KAAW,CAAA,EAAA;AAC1B,IAAA,MAAM,IAAI,SAAA;AAAA,MACR,wDAAA;AAAA,KACF,CAAA;AAAA,GACF;AACA,EAAO,OAAA,QAAA,CAAA;AACT,CAAA;AAIgB,SAAA,UAAA,CACd,YACA,QACG,EAAA;AACH,EAAA,OAAO,YAAa,CAAA,UAAA,CAAW,IAAK,CAAA,QAAQ,CAAC,CAAA,CAAA;AAC/C,CAAA;AAEO,SAAS,WACd,MACoB,EAAA;AACpB,EAAO,OAAA,MAAA,CAAO,KAAK,MAAU,IAAA,EAAE,CAAE,CAAA,IAAA,CAAK,OAAK,IAAI,CAAA,CAAA;AACjD;;;;"}
@@ -0,0 +1,58 @@
1
+ import '../types/Alert.esm.js';
2
+ import { ChangeThreshold, GrowthType } from '../types/ChangeStatistic.esm.js';
3
+ import { Duration, DateTime } from 'luxon';
4
+ import { inclusiveStartDateOf } from './duration.esm.js';
5
+ import { notEmpty } from './assert.esm.js';
6
+
7
+ function growthOf(change, engineerThreshold) {
8
+ const exceedsEngineerThreshold = Math.abs(change.amount) >= engineerThreshold;
9
+ if (notEmpty(change.ratio)) {
10
+ if (exceedsEngineerThreshold && change.ratio >= ChangeThreshold.upper) {
11
+ return GrowthType.Excess;
12
+ }
13
+ if (exceedsEngineerThreshold && change.ratio <= ChangeThreshold.lower) {
14
+ return GrowthType.Savings;
15
+ }
16
+ } else {
17
+ if (exceedsEngineerThreshold && change.amount > 0) {
18
+ return GrowthType.Excess;
19
+ }
20
+ if (exceedsEngineerThreshold && change.amount < 0) {
21
+ return GrowthType.Savings;
22
+ }
23
+ }
24
+ return GrowthType.Negligible;
25
+ }
26
+ function getComparedChange(dailyCost, metricData, duration, lastCompleteBillingDate) {
27
+ const dailyCostRatio = dailyCost.change?.ratio;
28
+ const metricDataRatio = metricData.change?.ratio;
29
+ const previousPeriodTotal = getPreviousPeriodTotalCost(
30
+ dailyCost.aggregation,
31
+ duration,
32
+ lastCompleteBillingDate
33
+ );
34
+ if (!notEmpty(dailyCostRatio) || !notEmpty(metricDataRatio)) {
35
+ return {
36
+ amount: previousPeriodTotal
37
+ };
38
+ }
39
+ return {
40
+ ratio: dailyCostRatio - metricDataRatio,
41
+ amount: previousPeriodTotal * (dailyCostRatio - metricDataRatio)
42
+ };
43
+ }
44
+ function getPreviousPeriodTotalCost(aggregation, duration, inclusiveEndDate) {
45
+ const luxonDuration = Duration.fromISO(duration);
46
+ const startDate = inclusiveStartDateOf(duration, inclusiveEndDate);
47
+ const nextPeriodStart = DateTime.fromISO(startDate).plus(luxonDuration);
48
+ return aggregation.reduce((acc, costByDate) => {
49
+ return DateTime.fromISO(costByDate.date) < nextPeriodStart ? acc + costByDate.amount : acc;
50
+ }, 0);
51
+ }
52
+ function choose([savings, excess], change) {
53
+ const isSavings = (change.ratio ?? change.amount) <= 0;
54
+ return isSavings ? savings : excess;
55
+ }
56
+
57
+ export { choose, getComparedChange, getPreviousPeriodTotalCost, growthOf };
58
+ //# sourceMappingURL=change.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change.esm.js","sources":["../../src/utils/change.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ChangeThreshold, GrowthType, Duration } from '../types';\nimport {\n Cost,\n ChangeStatistic,\n MetricData,\n DateAggregation,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { DateTime, Duration as LuxonDuration } from 'luxon';\nimport { inclusiveStartDateOf } from './duration';\nimport { notEmpty } from './assert';\n\n// Used for displaying status colors\nexport function growthOf(\n change: ChangeStatistic,\n engineerThreshold: number,\n): GrowthType {\n const exceedsEngineerThreshold = Math.abs(change.amount) >= engineerThreshold;\n\n if (notEmpty(change.ratio)) {\n if (exceedsEngineerThreshold && change.ratio >= ChangeThreshold.upper) {\n return GrowthType.Excess;\n }\n\n if (exceedsEngineerThreshold && change.ratio <= ChangeThreshold.lower) {\n return GrowthType.Savings;\n }\n } else {\n if (exceedsEngineerThreshold && change.amount > 0) {\n return GrowthType.Excess;\n }\n if (exceedsEngineerThreshold && change.amount < 0) {\n return GrowthType.Savings;\n }\n }\n\n return GrowthType.Negligible;\n}\n\n// Used by <CostOverviewCard /> for displaying engineer totals\nexport function getComparedChange(\n dailyCost: Cost,\n metricData: MetricData,\n duration: Duration,\n lastCompleteBillingDate: string, // YYYY-MM-DD,\n): ChangeStatistic {\n const dailyCostRatio = dailyCost.change?.ratio;\n const metricDataRatio = metricData.change?.ratio;\n const previousPeriodTotal = getPreviousPeriodTotalCost(\n dailyCost.aggregation,\n duration,\n lastCompleteBillingDate,\n );\n\n // if either ratio cannot be calculated, no compared ratio can be calculated\n if (!notEmpty(dailyCostRatio) || !notEmpty(metricDataRatio)) {\n return {\n amount: previousPeriodTotal,\n };\n }\n\n return {\n ratio: dailyCostRatio - metricDataRatio,\n amount: previousPeriodTotal * (dailyCostRatio - metricDataRatio),\n };\n}\n\nexport function getPreviousPeriodTotalCost(\n aggregation: DateAggregation[],\n duration: Duration,\n inclusiveEndDate: string,\n): number {\n const luxonDuration = LuxonDuration.fromISO(duration);\n const startDate = inclusiveStartDateOf(duration, inclusiveEndDate);\n const nextPeriodStart = DateTime.fromISO(startDate).plus(luxonDuration);\n // Add up costs that incurred before the start of the next period.\n return aggregation.reduce((acc, costByDate) => {\n return DateTime.fromISO(costByDate.date) < nextPeriodStart\n ? acc + costByDate.amount\n : acc;\n }, 0);\n}\n\nexport function choose<T>(\n [savings, excess]: [T, T],\n change: ChangeStatistic,\n): T {\n const isSavings = (change.ratio ?? change.amount) <= 0;\n return isSavings ? savings : excess;\n}\n"],"names":["LuxonDuration"],"mappings":";;;;;;AA4BgB,SAAA,QAAA,CACd,QACA,iBACY,EAAA;AACZ,EAAA,MAAM,wBAA2B,GAAA,IAAA,CAAK,GAAI,CAAA,MAAA,CAAO,MAAM,CAAK,IAAA,iBAAA,CAAA;AAE5D,EAAI,IAAA,QAAA,CAAS,MAAO,CAAA,KAAK,CAAG,EAAA;AAC1B,IAAA,IAAI,wBAA4B,IAAA,MAAA,CAAO,KAAS,IAAA,eAAA,CAAgB,KAAO,EAAA;AACrE,MAAA,OAAO,UAAW,CAAA,MAAA,CAAA;AAAA,KACpB;AAEA,IAAA,IAAI,wBAA4B,IAAA,MAAA,CAAO,KAAS,IAAA,eAAA,CAAgB,KAAO,EAAA;AACrE,MAAA,OAAO,UAAW,CAAA,OAAA,CAAA;AAAA,KACpB;AAAA,GACK,MAAA;AACL,IAAI,IAAA,wBAAA,IAA4B,MAAO,CAAA,MAAA,GAAS,CAAG,EAAA;AACjD,MAAA,OAAO,UAAW,CAAA,MAAA,CAAA;AAAA,KACpB;AACA,IAAI,IAAA,wBAAA,IAA4B,MAAO,CAAA,MAAA,GAAS,CAAG,EAAA;AACjD,MAAA,OAAO,UAAW,CAAA,OAAA,CAAA;AAAA,KACpB;AAAA,GACF;AAEA,EAAA,OAAO,UAAW,CAAA,UAAA,CAAA;AACpB,CAAA;AAGO,SAAS,iBACd,CAAA,SAAA,EACA,UACA,EAAA,QAAA,EACA,uBACiB,EAAA;AACjB,EAAM,MAAA,cAAA,GAAiB,UAAU,MAAQ,EAAA,KAAA,CAAA;AACzC,EAAM,MAAA,eAAA,GAAkB,WAAW,MAAQ,EAAA,KAAA,CAAA;AAC3C,EAAA,MAAM,mBAAsB,GAAA,0BAAA;AAAA,IAC1B,SAAU,CAAA,WAAA;AAAA,IACV,QAAA;AAAA,IACA,uBAAA;AAAA,GACF,CAAA;AAGA,EAAA,IAAI,CAAC,QAAS,CAAA,cAAc,KAAK,CAAC,QAAA,CAAS,eAAe,CAAG,EAAA;AAC3D,IAAO,OAAA;AAAA,MACL,MAAQ,EAAA,mBAAA;AAAA,KACV,CAAA;AAAA,GACF;AAEA,EAAO,OAAA;AAAA,IACL,OAAO,cAAiB,GAAA,eAAA;AAAA,IACxB,MAAA,EAAQ,uBAAuB,cAAiB,GAAA,eAAA,CAAA;AAAA,GAClD,CAAA;AACF,CAAA;AAEgB,SAAA,0BAAA,CACd,WACA,EAAA,QAAA,EACA,gBACQ,EAAA;AACR,EAAM,MAAA,aAAA,GAAgBA,QAAc,CAAA,OAAA,CAAQ,QAAQ,CAAA,CAAA;AACpD,EAAM,MAAA,SAAA,GAAY,oBAAqB,CAAA,QAAA,EAAU,gBAAgB,CAAA,CAAA;AACjE,EAAA,MAAM,kBAAkB,QAAS,CAAA,OAAA,CAAQ,SAAS,CAAA,CAAE,KAAK,aAAa,CAAA,CAAA;AAEtE,EAAA,OAAO,WAAY,CAAA,MAAA,CAAO,CAAC,GAAA,EAAK,UAAe,KAAA;AAC7C,IAAO,OAAA,QAAA,CAAS,QAAQ,UAAW,CAAA,IAAI,IAAI,eACvC,GAAA,GAAA,GAAM,WAAW,MACjB,GAAA,GAAA,CAAA;AAAA,KACH,CAAC,CAAA,CAAA;AACN,CAAA;AAEO,SAAS,MACd,CAAA,CAAC,OAAS,EAAA,MAAM,GAChB,MACG,EAAA;AACH,EAAA,MAAM,SAAa,GAAA,CAAA,MAAA,CAAO,KAAS,IAAA,MAAA,CAAO,MAAW,KAAA,CAAA,CAAA;AACrD,EAAA,OAAO,YAAY,OAAU,GAAA,MAAA,CAAA;AAC/B;;;;"}
@@ -0,0 +1,9 @@
1
+ function trendFrom(trendline, date) {
2
+ return trendline.slope * (date / 1e3) + trendline.intercept;
3
+ }
4
+ function groupByDate(acc, entry) {
5
+ return { ...acc, [entry.date]: entry.amount };
6
+ }
7
+
8
+ export { groupByDate, trendFrom };
9
+ //# sourceMappingURL=charts.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"charts.esm.js","sources":["../../src/utils/charts.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DateAggregation,\n Trendline,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { ChartData } from '../types';\n\nexport function trendFrom(trendline: Trendline, date: number): number {\n return trendline.slope * (date / 1000) + trendline.intercept;\n}\n\nexport function groupByDate(\n acc: Record<string, number>,\n entry: DateAggregation,\n): Record<string, number> {\n return { ...acc, [entry.date]: entry.amount };\n}\n\nexport function toMaxCost(acc: ChartData, entry: ChartData): ChartData {\n return acc.dailyCost > entry.dailyCost ? acc : entry;\n}\n\nexport function toDataMax(metric: string, data: ChartData[]): number {\n return (\n (data.reduce(toMaxCost).dailyCost / Math.abs(data[0].trend)) *\n data[0][metric]\n );\n}\n"],"names":[],"mappings":"AAsBgB,SAAA,SAAA,CAAU,WAAsB,IAAsB,EAAA;AACpE,EAAA,OAAO,SAAU,CAAA,KAAA,IAAS,IAAO,GAAA,GAAA,CAAA,GAAQ,SAAU,CAAA,SAAA,CAAA;AACrD,CAAA;AAEgB,SAAA,WAAA,CACd,KACA,KACwB,EAAA;AACxB,EAAO,OAAA,EAAE,GAAG,GAAK,EAAA,CAAC,MAAM,IAAI,GAAG,MAAM,MAAO,EAAA,CAAA;AAC9C;;;;"}
@@ -0,0 +1,19 @@
1
+ function validateMetrics(metrics) {
2
+ const defaults = metrics.filter((metric) => metric.default);
3
+ if (defaults.length > 1) {
4
+ throw new Error(
5
+ `Only one default metric can be set at a time. Found ${defaults.length}`
6
+ );
7
+ }
8
+ }
9
+ function validateCurrencies(currencies) {
10
+ const withoutKinds = currencies.filter((currency) => currency.kind === null);
11
+ if (withoutKinds.length > 1) {
12
+ throw new Error(
13
+ `Only one currency can be without kind. Found ${withoutKinds.length}`
14
+ );
15
+ }
16
+ }
17
+
18
+ export { validateCurrencies, validateMetrics };
19
+ //# sourceMappingURL=config.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.esm.js","sources":["../../src/utils/config.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Currency } from '../types';\nimport { Metric } from '@backstage-community/plugin-cost-insights-common';\n\nexport function validateMetrics(metrics: Metric[]) {\n const defaults = metrics.filter(metric => metric.default);\n if (defaults.length > 1) {\n throw new Error(\n `Only one default metric can be set at a time. Found ${defaults.length}`,\n );\n }\n}\n\nexport function validateCurrencies(currencies: Currency[]) {\n const withoutKinds = currencies.filter(currency => currency.kind === null);\n if (withoutKinds.length > 1) {\n throw new Error(\n `Only one currency can be without kind. Found ${withoutKinds.length}`,\n );\n }\n}\n"],"names":[],"mappings":"AAmBO,SAAS,gBAAgB,OAAmB,EAAA;AACjD,EAAA,MAAM,QAAW,GAAA,OAAA,CAAQ,MAAO,CAAA,CAAA,MAAA,KAAU,OAAO,OAAO,CAAA,CAAA;AACxD,EAAI,IAAA,QAAA,CAAS,SAAS,CAAG,EAAA;AACvB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,oDAAA,EAAuD,SAAS,MAAM,CAAA,CAAA;AAAA,KACxE,CAAA;AAAA,GACF;AACF,CAAA;AAEO,SAAS,mBAAmB,UAAwB,EAAA;AACzD,EAAA,MAAM,eAAe,UAAW,CAAA,MAAA,CAAO,CAAY,QAAA,KAAA,QAAA,CAAS,SAAS,IAAI,CAAA,CAAA;AACzE,EAAI,IAAA,YAAA,CAAa,SAAS,CAAG,EAAA;AAC3B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,6CAAA,EAAgD,aAAa,MAAM,CAAA,CAAA;AAAA,KACrE,CAAA;AAAA,GACF;AACF;;;;"}
@@ -0,0 +1,56 @@
1
+ import '../types/Alert.esm.js';
2
+ import { CurrencyType } from '../types/CurrencyType.esm.js';
3
+ import { Duration } from '../types/Duration.esm.js';
4
+ import { assertNever } from './assert.esm.js';
5
+
6
+ const rateOf = (cost, duration) => {
7
+ switch (duration) {
8
+ case Duration.P30D:
9
+ return cost / 12;
10
+ case Duration.P7D:
11
+ case Duration.P90D:
12
+ case Duration.P3M:
13
+ return cost / 4;
14
+ default:
15
+ return assertNever(duration);
16
+ }
17
+ };
18
+ const defaultCurrencies = [
19
+ {
20
+ kind: null,
21
+ label: "Engineers \u{1F6E0}",
22
+ unit: "engineer"
23
+ },
24
+ {
25
+ kind: CurrencyType.USD,
26
+ label: "US Dollars \u{1F4B5}",
27
+ unit: "dollar",
28
+ prefix: "$",
29
+ rate: 1
30
+ },
31
+ {
32
+ kind: CurrencyType.CarbonOffsetTons,
33
+ label: "Carbon Offset Tons \u267B\uFE0F\u2696\uFE0Fs",
34
+ unit: "carbon offset ton",
35
+ rate: 3.5
36
+ },
37
+ {
38
+ kind: CurrencyType.Beers,
39
+ label: "Beers \u{1F37A}",
40
+ unit: "beer",
41
+ rate: 4.5
42
+ },
43
+ {
44
+ kind: CurrencyType.IceCream,
45
+ label: "Pints of Ice Cream \u{1F366}",
46
+ unit: "ice cream pint",
47
+ rate: 5.5
48
+ }
49
+ ];
50
+ const createCurrencyFormat = (currency = "USD", locale = "en-US") => new Intl.NumberFormat(locale, {
51
+ currency,
52
+ style: "currency"
53
+ });
54
+
55
+ export { createCurrencyFormat, defaultCurrencies, rateOf };
56
+ //# sourceMappingURL=currency.esm.js.map