@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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @backstage-community/plugin-cost-insights
2
2
 
3
+ ## 0.12.26
4
+
5
+ ### Patch Changes
6
+
7
+ - 22de2f8: Backstage version bump to v1.29.2
8
+ - Updated dependencies [22de2f8]
9
+ - @backstage-community/plugin-cost-insights-common@0.1.4
10
+
11
+ ## 0.12.25
12
+
13
+ ### Patch Changes
14
+
15
+ - aff1a3c: Fix broken links in README.md
16
+
3
17
  ## 0.12.24
4
18
 
5
19
  ### Patch Changes
package/README.md CHANGED
@@ -24,7 +24,7 @@ yarn --cwd packages/app add @backstage-community/plugin-cost-insights
24
24
 
25
25
  1. Configure `app-config.yaml`. See [Configuration](#configuration).
26
26
 
27
- 2. Create a CostInsights client. Clients must implement the [CostInsightsApi](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/api/CostInsightsApi.ts) interface. Create your own or [use a template](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/example/templates/CostInsightsClient.ts) to get started.
27
+ 2. Create a CostInsights client. Clients must implement the [CostInsightsApi](https://github.com/backstage/community-plugins/blob/main/workspaces/cost-insights/plugins/cost-insights/src/api/CostInsightsApi.ts) interface. Create your own or [use a template](https://github.com/backstage/community-plugins/blob/main/workspaces/cost-insights/plugins/cost-insights/src/example/templates/CostInsightsClient.ts) to get started.
28
28
 
29
29
  Tip: You can also use the `ExampleCostInsightsClient` from `@backstage-community/plugin-cost-insights` to see how the plugin looks with some mock data.
30
30
 
@@ -35,7 +35,7 @@ import { CostInsightsApi } from '@backstage-community/plugin-cost-insights';
35
35
  export class CostInsightsClient implements CostInsightsApi { ... }
36
36
  ```
37
37
 
38
- **Note:** We've briefly explored using the AWS Cost Explorer API to implement a Cost Insights client. Learn more about our findings [here](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/contrib/aws-cost-explorer-api.md).
38
+ **Note:** We've briefly explored using the AWS Cost Explorer API to implement a Cost Insights client. Learn more about our findings [here](https://github.com/backstage/community-plugins/blob/main/workspaces/cost-insights/plugins/cost-insights/contrib/aws-cost-explorer-api.md).
39
39
 
40
40
  3. Import the client and the Cost Insights plugin API to your Backstage instance.
41
41
 
@@ -134,7 +134,7 @@ costInsights:
134
134
 
135
135
  For showing cost breakdowns you can define a map of cloud products. They must be defined as keys on the `products` field. A user-friendly name is **required**.
136
136
 
137
- You can optionally supply a product `icon` to display in Cost Insights navigation. See the [type file](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/types/Icon.ts) for supported types and Material UI icon [mappings](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/utils/navigation.tsx).
137
+ You can optionally supply a product `icon` to display in Cost Insights navigation. See the [type file](https://github.com/backstage/community-plugins/blob/main/workspaces/cost-insights/plugins/cost-insights/src/types/Icon.ts) for supported types and Material UI icon [mappings](https://github.com/backstage/community-plugins/blob/main/workspaces/cost-insights/plugins/cost-insights/src/utils/navigation.tsx).
138
138
 
139
139
  **Note:** Product keys should be unique and on `camelCase` form. Backstage does not support underscores in configuration keys.
140
140
 
@@ -237,8 +237,8 @@ costInsights:
237
237
 
238
238
  ## Alerts
239
239
 
240
- The CostInsightsApi `getAlerts` method may return any type of alert or recommendation (called collectively "Action Items" in Cost Insights) that implements the [Alert type](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/types/Alert.ts). This allows you to deliver any alerts or recommendations specific to your infrastructure or company migrations.
240
+ The CostInsightsApi `getAlerts` method may return any type of alert or recommendation (called collectively "Action Items" in Cost Insights) that implements the [Alert type](https://github.com/backstage/community-plugins/blob/main/workspaces/cost-insights/plugins/cost-insights/src/types/Alert.ts). This allows you to deliver any alerts or recommendations specific to your infrastructure or company migrations.
241
241
 
242
- To learn more about using Cost Insights' ready-to-use alerts, see the alerts [README](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/alerts/README.md).
242
+ To learn more about using Cost Insights' ready-to-use alerts, see the alerts [README](https://github.com/backstage/community-plugins/blob/main/workspaces/cost-insights/plugins/cost-insights/src/alerts/README.md).
243
243
 
244
- Example implementations of custom alerts, forms and components can be found in the [examples](https://github.com/backstage/backstage/tree/master/plugins/cost-insights/src/example) directory.
244
+ Example implementations of custom alerts, forms and components can be found in the [examples](https://github.com/backstage/community-plugins/tree/main/workspaces/cost-insights/plugins/cost-insights/src/example) directory.
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import { ProjectGrowthAlertCard } from '../components/ProjectGrowthAlertCard/ProjectGrowthAlertCard.esm.js';
3
+
4
+ class ProjectGrowthAlert {
5
+ data;
6
+ constructor(data) {
7
+ this.data = data;
8
+ }
9
+ get url() {
10
+ return "/cost-insights/investigating-growth";
11
+ }
12
+ get title() {
13
+ return `Investigate cost growth in project ${this.data.project}`;
14
+ }
15
+ get subtitle() {
16
+ return "Cost growth outpacing business growth is unsustainable long-term.";
17
+ }
18
+ get element() {
19
+ return /* @__PURE__ */ React.createElement(ProjectGrowthAlertCard, { alert: this.data });
20
+ }
21
+ }
22
+
23
+ export { ProjectGrowthAlert };
24
+ //# sourceMappingURL=ProjectGrowthAlert.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectGrowthAlert.esm.js","sources":["../../src/alerts/ProjectGrowthAlert.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 React from 'react';\nimport { ProjectGrowthAlertCard } from '../components/ProjectGrowthAlertCard';\nimport { Alert, ProjectGrowthData } from '../types';\n\n/**\n * The alert below is an example of an Alert implementation; the CostInsightsApi permits returning\n * any implementation of the Alert type, so adopters can create their own. The CostInsightsApi\n * fetches alert data from the backend, then creates Alert classes with the data.\n *\n * @public\n */\nexport class ProjectGrowthAlert implements Alert {\n data: ProjectGrowthData;\n\n constructor(data: ProjectGrowthData) {\n this.data = data;\n }\n\n get url() {\n return '/cost-insights/investigating-growth';\n }\n\n get title() {\n return `Investigate cost growth in project ${this.data.project}`;\n }\n\n get subtitle() {\n return 'Cost growth outpacing business growth is unsustainable long-term.';\n }\n\n get element() {\n return <ProjectGrowthAlertCard alert={this.data} />;\n }\n}\n"],"names":[],"mappings":";;;AA2BO,MAAM,kBAAoC,CAAA;AAAA,EAC/C,IAAA,CAAA;AAAA,EAEA,YAAY,IAAyB,EAAA;AACnC,IAAA,IAAA,CAAK,IAAO,GAAA,IAAA,CAAA;AAAA,GACd;AAAA,EAEA,IAAI,GAAM,GAAA;AACR,IAAO,OAAA,qCAAA,CAAA;AAAA,GACT;AAAA,EAEA,IAAI,KAAQ,GAAA;AACV,IAAO,OAAA,CAAA,mCAAA,EAAsC,IAAK,CAAA,IAAA,CAAK,OAAO,CAAA,CAAA,CAAA;AAAA,GAChE;AAAA,EAEA,IAAI,QAAW,GAAA;AACb,IAAO,OAAA,mEAAA,CAAA;AAAA,GACT;AAAA,EAEA,IAAI,OAAU,GAAA;AACZ,IAAA,uBAAQ,KAAA,CAAA,aAAA,CAAA,sBAAA,EAAA,EAAuB,KAAO,EAAA,IAAA,CAAK,IAAM,EAAA,CAAA,CAAA;AAAA,GACnD;AACF;;;;"}
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { UnlabeledDataflowAlertCard } from '../components/UnlabeledDataflowAlertCard/UnlabeledDataflowAlertCard.esm.js';
3
+
4
+ class UnlabeledDataflowAlert {
5
+ data;
6
+ status;
7
+ constructor(data) {
8
+ this.data = data;
9
+ }
10
+ get url() {
11
+ return "/cost-insights/labeling-jobs";
12
+ }
13
+ get title() {
14
+ return "Add labels to workflows";
15
+ }
16
+ get subtitle() {
17
+ return "Labels show in billing data, enabling cost insights for each workflow.";
18
+ }
19
+ get element() {
20
+ return /* @__PURE__ */ React.createElement(UnlabeledDataflowAlertCard, { alert: this.data });
21
+ }
22
+ }
23
+
24
+ export { UnlabeledDataflowAlert };
25
+ //# sourceMappingURL=UnlabeledDataflowAlert.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnlabeledDataflowAlert.esm.js","sources":["../../src/alerts/UnlabeledDataflowAlert.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 React from 'react';\nimport { UnlabeledDataflowAlertCard } from '../components/UnlabeledDataflowAlertCard';\nimport { Alert, AlertStatus, UnlabeledDataflowData } from '../types';\n\n/**\n * The alert below is an example of an Alert implementation; the CostInsightsApi permits returning\n * any implementation of the Alert type, so adopters can create their own. The CostInsightsApi\n * fetches alert data from the backend, then creates Alert classes with the data.\n *\n * @public\n */\nexport class UnlabeledDataflowAlert implements Alert {\n data: UnlabeledDataflowData;\n status?: AlertStatus;\n\n constructor(data: UnlabeledDataflowData) {\n this.data = data;\n }\n\n get url() {\n return '/cost-insights/labeling-jobs';\n }\n\n get title() {\n return 'Add labels to workflows';\n }\n\n get subtitle() {\n return 'Labels show in billing data, enabling cost insights for each workflow.';\n }\n\n get element() {\n return <UnlabeledDataflowAlertCard alert={this.data} />;\n }\n}\n"],"names":[],"mappings":";;;AA2BO,MAAM,sBAAwC,CAAA;AAAA,EACnD,IAAA,CAAA;AAAA,EACA,MAAA,CAAA;AAAA,EAEA,YAAY,IAA6B,EAAA;AACvC,IAAA,IAAA,CAAK,IAAO,GAAA,IAAA,CAAA;AAAA,GACd;AAAA,EAEA,IAAI,GAAM,GAAA;AACR,IAAO,OAAA,8BAAA,CAAA;AAAA,GACT;AAAA,EAEA,IAAI,KAAQ,GAAA;AACV,IAAO,OAAA,yBAAA,CAAA;AAAA,GACT;AAAA,EAEA,IAAI,QAAW,GAAA;AACb,IAAO,OAAA,wEAAA,CAAA;AAAA,GACT;AAAA,EAEA,IAAI,OAAU,GAAA;AACZ,IAAA,uBAAQ,KAAA,CAAA,aAAA,CAAA,0BAAA,EAAA,EAA2B,KAAO,EAAA,IAAA,CAAK,IAAM,EAAA,CAAA,CAAA;AAAA,GACvD;AACF;;;;"}
@@ -0,0 +1,8 @@
1
+ import { createApiRef } from '@backstage/core-plugin-api';
2
+
3
+ const costInsightsApiRef = createApiRef({
4
+ id: "plugin.costinsights.service"
5
+ });
6
+
7
+ export { costInsightsApiRef };
8
+ //# sourceMappingURL=CostInsightsApi.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CostInsightsApi.esm.js","sources":["../../src/api/CostInsightsApi.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 Cost,\n Entity,\n Group,\n Project,\n Maybe,\n MetricData,\n} from '@backstage-community/plugin-cost-insights-common';\n\nimport { Alert } from '../types';\nimport { createApiRef } from '@backstage/core-plugin-api';\n\n/** @public */\nexport type ProductInsightsOptions = {\n /**\n * The product from the cost-insights configuration in app-config.yaml\n */\n product: string;\n\n /**\n * The group id from getUserGroups or query parameters\n */\n group: string;\n\n /**\n * An ISO 8601 repeating interval string, such as R2/P3M/2020-09-01\n */\n intervals: string;\n\n /**\n * (optional) The project id from getGroupProjects or query parameters\n */\n project: Maybe<string>;\n};\n\n/** @public */\nexport type CostInsightsApi = {\n /**\n * Get the most current date for which billing data is complete, in YYYY-MM-DD format. This helps\n * define the intervals used in other API methods to avoid showing incomplete cost. The costs for\n * today, for example, will not be complete. This ideally comes from the cloud provider.\n */\n getLastCompleteBillingDate(): Promise<string>;\n\n /**\n * Get a list of groups the given user belongs to. These may be LDAP groups or similar\n * organizational groups. Cost Insights is designed to show costs based on group membership;\n * if a user has multiple groups, they are able to switch between groups to see costs for each.\n *\n * This method should be removed once the Backstage identity plugin provides the same concept.\n *\n * @param userId - The login id for the current user\n */\n getUserGroups(userId: string): Promise<Group[]>;\n\n /**\n * Get a list of cloud billing entities that belong to this group (projects in GCP, AWS has a\n * similar concept in billing accounts). These act as filters for the displayed costs, users can\n * choose whether they see all costs for a group, or those from a particular owned project.\n *\n * @param group - The group id from getUserGroups or query parameters\n */\n getGroupProjects(group: string): Promise<Project[]>;\n\n /**\n * Get daily cost aggregations for a given catalog entity and interval time frame.\n *\n * The return type includes an array of daily cost aggregations as well as statistics about the\n * change in cost over the intervals. Calculating these statistics requires us to bucket costs\n * into two or more time periods, hence a repeating interval format rather than just a start and\n * end date.\n *\n * The rate of change in this comparison allows teams to reason about their cost growth (or\n * reduction) and compare it to metrics important to the business.\n *\n * Note: implementing this is only required when using the `EntityCostInsightsContent` extension.\n *\n * @param catalogEntityRef - A reference to the catalog entity, as described in\n * https://backstage.io/docs/features/software-catalog/references\n * @param intervals - An ISO 8601 repeating interval string, such as R2/P30D/2020-09-01\n * https://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals\n */\n getCatalogEntityDailyCost?(\n catalogEntityRef: string,\n intervals: string,\n ): Promise<Cost>;\n\n /**\n * Get daily cost aggregations for a given group and interval time frame.\n *\n * The return type includes an array of daily cost aggregations as well as statistics about the\n * change in cost over the intervals. Calculating these statistics requires us to bucket costs\n * into two or more time periods, hence a repeating interval format rather than just a start and\n * end date.\n *\n * The rate of change in this comparison allows teams to reason about their cost growth (or\n * reduction) and compare it to metrics important to the business.\n *\n * @param group - The group id from getUserGroups or query parameters\n * @param intervals - An ISO 8601 repeating interval string, such as R2/P30D/2020-09-01\n * https://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals\n */\n getGroupDailyCost(group: string, intervals: string): Promise<Cost>;\n\n /**\n * Get daily cost aggregations for a given billing entity (project in GCP, AWS has a similar\n * concept in billing accounts) and interval time frame.\n *\n * The return type includes an array of daily cost aggregations as well as statistics about the\n * change in cost over the intervals. Calculating these statistics requires us to bucket costs\n * into two or more time periods, hence a repeating interval format rather than just a start and\n * end date.\n *\n * The rate of change in this comparison allows teams to reason about the project's cost growth\n * (or reduction) and compare it to metrics important to the business.\n *\n * @param project - The project id from getGroupProjects or query parameters\n * @param intervals - An ISO 8601 repeating interval string, such as R2/P30D/2020-09-01\n * https://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals\n */\n getProjectDailyCost(project: string, intervals: string): Promise<Cost>;\n\n /**\n * Get aggregations for a particular metric and interval time frame. Teams\n * can see metrics important to their business in comparison to the growth\n * (or reduction) of a project or group's daily costs.\n *\n * @param metric - A metric from the cost-insights configuration in app-config.yaml.\n * @param intervals - An ISO 8601 repeating interval string, such as R2/P30D/2020-09-01\n * https://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals\n */\n getDailyMetricData(metric: string, intervals: string): Promise<MetricData>;\n\n /**\n * Get cost aggregations for a particular cloud product and interval time frame. This includes\n * total cost for the product, as well as a breakdown of particular entities that incurred cost\n * in this product. The type of entity depends on the product - it may be deployed services,\n * storage buckets, managed database instances, etc.\n *\n * If project is supplied, this should only return product costs for the given billing entity\n * (project in GCP).\n *\n * The time period is supplied as a Duration rather than intervals, since this is always expected\n * to return data for two bucketed time period (e.g. month vs month, or quarter vs quarter).\n *\n * @param options - Options to use when fetching insights for a particular cloud product and\n * interval time frame.\n */\n getProductInsights(options: ProductInsightsOptions): Promise<Entity>;\n\n /**\n * Get current cost alerts for a given group. These show up as Action Items for the group on the\n * Cost Insights page. Alerts may include cost-saving recommendations, such as infrastructure\n * migrations, or cost-related warnings, such as an unexpected billing anomaly.\n */\n getAlerts(group: string): Promise<Alert[]>;\n};\n\n/** @public */\nexport const costInsightsApiRef = createApiRef<CostInsightsApi>({\n id: 'plugin.costinsights.service',\n});\n"],"names":[],"mappings":";;AA+KO,MAAM,qBAAqB,YAA8B,CAAA;AAAA,EAC9D,EAAI,EAAA,6BAAA;AACN,CAAC;;;;"}
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import classnames from 'classnames';
3
+ import Card from '@material-ui/core/Card';
4
+ import CardHeader from '@material-ui/core/CardHeader';
5
+ import '../../hooks/useConfig.esm.js';
6
+ import '../../hooks/useCurrency.esm.js';
7
+ import '../../hooks/useFilters.esm.js';
8
+ import '../../hooks/useGroups.esm.js';
9
+ import '../../hooks/useLoading.esm.js';
10
+ import { useScroll } from '../../hooks/useScroll.esm.js';
11
+ import '../../hooks/useLastCompleteBillingDate.esm.js';
12
+ import { useActionItemCardStyles } from '../../utils/styles.esm.js';
13
+
14
+ const ActionItemCard = ({
15
+ alert,
16
+ avatar,
17
+ number,
18
+ disableScroll = false
19
+ }) => {
20
+ const classes = useActionItemCardStyles();
21
+ const rootClasses = classnames(classes.root, {
22
+ [classes.activeRoot]: !disableScroll
23
+ });
24
+ const [, setScroll] = useScroll();
25
+ const onActionItemClick = () => {
26
+ if (!disableScroll && number) {
27
+ setScroll(`alert-${number}`);
28
+ }
29
+ };
30
+ return /* @__PURE__ */ React.createElement(Card, { className: classes.card, raised: false, onClick: onActionItemClick }, /* @__PURE__ */ React.createElement(
31
+ CardHeader,
32
+ {
33
+ classes: {
34
+ root: rootClasses,
35
+ action: classes.action,
36
+ title: classes.title
37
+ },
38
+ title: alert.title,
39
+ subheader: alert.subtitle,
40
+ avatar
41
+ }
42
+ ));
43
+ };
44
+
45
+ export { ActionItemCard };
46
+ //# sourceMappingURL=ActionItemCard.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActionItemCard.esm.js","sources":["../../../src/components/ActionItems/ActionItemCard.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 */\nimport React, { MouseEventHandler } from 'react';\nimport classnames from 'classnames';\nimport Card from '@material-ui/core/Card';\nimport CardHeader from '@material-ui/core/CardHeader';\nimport { useScroll } from '../../hooks';\nimport { Alert } from '../../types';\nimport { useActionItemCardStyles as useStyles } from '../../utils/styles';\n\ntype ActionItemCardProps = {\n alert: Alert;\n number?: number;\n avatar?: JSX.Element;\n disableScroll?: boolean;\n};\n\nexport const ActionItemCard = ({\n alert,\n avatar,\n number,\n disableScroll = false,\n}: ActionItemCardProps) => {\n const classes = useStyles();\n const rootClasses = classnames(classes.root, {\n [classes.activeRoot]: !disableScroll,\n });\n const [, setScroll] = useScroll();\n\n const onActionItemClick: MouseEventHandler = () => {\n if (!disableScroll && number) {\n setScroll(`alert-${number}`);\n }\n };\n\n return (\n <Card className={classes.card} raised={false} onClick={onActionItemClick}>\n <CardHeader\n classes={{\n root: rootClasses,\n action: classes.action,\n title: classes.title,\n }}\n title={alert.title}\n subheader={alert.subtitle}\n avatar={avatar}\n />\n </Card>\n );\n};\n"],"names":["useStyles"],"mappings":";;;;;;;;;;;;;AA8BO,MAAM,iBAAiB,CAAC;AAAA,EAC7B,KAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,aAAgB,GAAA,KAAA;AAClB,CAA2B,KAAA;AACzB,EAAA,MAAM,UAAUA,uBAAU,EAAA,CAAA;AAC1B,EAAM,MAAA,WAAA,GAAc,UAAW,CAAA,OAAA,CAAQ,IAAM,EAAA;AAAA,IAC3C,CAAC,OAAA,CAAQ,UAAU,GAAG,CAAC,aAAA;AAAA,GACxB,CAAA,CAAA;AACD,EAAA,MAAM,GAAG,SAAS,CAAA,GAAI,SAAU,EAAA,CAAA;AAEhC,EAAA,MAAM,oBAAuC,MAAM;AACjD,IAAI,IAAA,CAAC,iBAAiB,MAAQ,EAAA;AAC5B,MAAU,SAAA,CAAA,CAAA,MAAA,EAAS,MAAM,CAAE,CAAA,CAAA,CAAA;AAAA,KAC7B;AAAA,GACF,CAAA;AAEA,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,SAAW,EAAA,OAAA,CAAQ,MAAM,MAAQ,EAAA,KAAA,EAAO,SAAS,iBACrD,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,OAAS,EAAA;AAAA,QACP,IAAM,EAAA,WAAA;AAAA,QACN,QAAQ,OAAQ,CAAA,MAAA;AAAA,QAChB,OAAO,OAAQ,CAAA,KAAA;AAAA,OACjB;AAAA,MACA,OAAO,KAAM,CAAA,KAAA;AAAA,MACb,WAAW,KAAM,CAAA,QAAA;AAAA,MACjB,MAAA;AAAA,KAAA;AAAA,GAEJ,CAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1,90 @@
1
+ import React, { Fragment } from 'react';
2
+ import Avatar from '@material-ui/core/Avatar';
3
+ import Tooltip from '@material-ui/core/Tooltip';
4
+ import IconButton from '@material-ui/core/IconButton';
5
+ import Badge from '@material-ui/core/Badge';
6
+ import Box from '@material-ui/core/Box';
7
+ import Paper from '@material-ui/core/Paper';
8
+ import Divider from '@material-ui/core/Divider';
9
+ import SnoozeIcon from '@material-ui/icons/AccessTime';
10
+ import AcceptIcon from '@material-ui/icons/Check';
11
+ import DismissIcon from '@material-ui/icons/Delete';
12
+ import { ActionItemCard } from './ActionItemCard.esm.js';
13
+ import { AlertStatus } from '../../types/Alert.esm.js';
14
+ import '../../hooks/useConfig.esm.js';
15
+ import '../../hooks/useCurrency.esm.js';
16
+ import '../../hooks/useFilters.esm.js';
17
+ import '../../hooks/useGroups.esm.js';
18
+ import '../../hooks/useLoading.esm.js';
19
+ import { useScroll, ScrollType } from '../../hooks/useScroll.esm.js';
20
+ import '../../hooks/useLastCompleteBillingDate.esm.js';
21
+ import { useActionItemCardStyles } from '../../utils/styles.esm.js';
22
+
23
+ const AlertStatusButton = ({
24
+ title,
25
+ amount,
26
+ icon,
27
+ onClick,
28
+ ...buttonProps
29
+ }) => /* @__PURE__ */ React.createElement(Tooltip, { title }, /* @__PURE__ */ React.createElement(
30
+ IconButton,
31
+ {
32
+ onClick,
33
+ role: "button",
34
+ "aria-hidden": false,
35
+ ...buttonProps
36
+ },
37
+ /* @__PURE__ */ React.createElement(Badge, { badgeContent: amount }, icon)
38
+ ));
39
+ const ActionItems = ({
40
+ active,
41
+ snoozed,
42
+ accepted,
43
+ dismissed
44
+ }) => {
45
+ const classes = useActionItemCardStyles();
46
+ const [, setScroll] = useScroll();
47
+ const isSnoozedButtonDisplayed = !!snoozed.length;
48
+ const isAcceptedButtonDisplayed = !!accepted.length;
49
+ const isDismissedButtonDisplayed = !!dismissed.length;
50
+ const isStatusButtonGroupDisplayed = !!active.length;
51
+ const onStatusButtonClick = () => setScroll(ScrollType.AlertSummary);
52
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Paper, null, active.map((alert, index) => /* @__PURE__ */ React.createElement(Fragment, { key: `alert-${index}` }, /* @__PURE__ */ React.createElement(
53
+ ActionItemCard,
54
+ {
55
+ alert,
56
+ number: index + 1,
57
+ avatar: /* @__PURE__ */ React.createElement(Avatar, { className: classes.avatar }, index + 1)
58
+ }
59
+ ), index < active.length - 1 && /* @__PURE__ */ React.createElement(Divider, null)))), isStatusButtonGroupDisplayed && /* @__PURE__ */ React.createElement(Box, { display: "flex", justifyContent: "flex-end", mt: 2 }, isAcceptedButtonDisplayed && /* @__PURE__ */ React.createElement(
60
+ AlertStatusButton,
61
+ {
62
+ title: "Accepted",
63
+ "aria-label": AlertStatus.Accepted,
64
+ icon: /* @__PURE__ */ React.createElement(AcceptIcon, null),
65
+ amount: accepted.length,
66
+ onClick: onStatusButtonClick
67
+ }
68
+ ), isSnoozedButtonDisplayed && /* @__PURE__ */ React.createElement(
69
+ AlertStatusButton,
70
+ {
71
+ title: "Snoozed",
72
+ "aria-label": AlertStatus.Snoozed,
73
+ amount: snoozed.length,
74
+ icon: /* @__PURE__ */ React.createElement(SnoozeIcon, null),
75
+ onClick: onStatusButtonClick
76
+ }
77
+ ), isDismissedButtonDisplayed && /* @__PURE__ */ React.createElement(
78
+ AlertStatusButton,
79
+ {
80
+ title: "Dismissed",
81
+ "aria-label": AlertStatus.Dismissed,
82
+ icon: /* @__PURE__ */ React.createElement(DismissIcon, null),
83
+ amount: dismissed.length,
84
+ onClick: onStatusButtonClick
85
+ }
86
+ )));
87
+ };
88
+
89
+ export { ActionItems };
90
+ //# sourceMappingURL=ActionItems.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActionItems.esm.js","sources":["../../../src/components/ActionItems/ActionItems.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 */\nimport React, { Fragment, MouseEventHandler } from 'react';\nimport Avatar from '@material-ui/core/Avatar';\nimport { IconButtonProps } from '@material-ui/core/IconButton';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport IconButton from '@material-ui/core/IconButton';\nimport Badge from '@material-ui/core/Badge';\nimport Box from '@material-ui/core/Box';\nimport Paper from '@material-ui/core/Paper';\nimport Divider from '@material-ui/core/Divider';\nimport { default as SnoozeIcon } from '@material-ui/icons/AccessTime';\nimport { default as AcceptIcon } from '@material-ui/icons/Check';\nimport { default as DismissIcon } from '@material-ui/icons/Delete';\nimport { ActionItemCard } from './ActionItemCard';\nimport { Alert, AlertStatus } from '../../types';\nimport { useScroll, ScrollType } from '../../hooks';\nimport { useActionItemCardStyles as useStyles } from '../../utils/styles';\n\ntype AlertStatusButtonProps = {\n title: string;\n amount: number;\n icon: JSX.Element;\n onClick: MouseEventHandler;\n} & IconButtonProps;\n\nconst AlertStatusButton = ({\n title,\n amount,\n icon,\n onClick,\n ...buttonProps\n}: AlertStatusButtonProps) => (\n <Tooltip title={title}>\n <IconButton\n onClick={onClick}\n role=\"button\"\n aria-hidden={false}\n {...buttonProps}\n >\n <Badge badgeContent={amount}>{icon}</Badge>\n </IconButton>\n </Tooltip>\n);\n\ntype ActionItemsProps = {\n active: Alert[];\n snoozed: Alert[];\n accepted: Alert[];\n dismissed: Alert[];\n};\n\nexport const ActionItems = ({\n active,\n snoozed,\n accepted,\n dismissed,\n}: ActionItemsProps) => {\n const classes = useStyles();\n const [, setScroll] = useScroll();\n\n const isSnoozedButtonDisplayed = !!snoozed.length;\n const isAcceptedButtonDisplayed = !!accepted.length;\n const isDismissedButtonDisplayed = !!dismissed.length;\n const isStatusButtonGroupDisplayed = !!active.length;\n\n const onStatusButtonClick: MouseEventHandler = () =>\n setScroll(ScrollType.AlertSummary);\n\n return (\n <>\n <Paper>\n {active.map((alert, index) => (\n <Fragment key={`alert-${index}`}>\n <ActionItemCard\n alert={alert}\n number={index + 1}\n avatar={<Avatar className={classes.avatar}>{index + 1}</Avatar>}\n />\n {index < active.length - 1 && <Divider />}\n </Fragment>\n ))}\n </Paper>\n {isStatusButtonGroupDisplayed && (\n <Box display=\"flex\" justifyContent=\"flex-end\" mt={2}>\n {isAcceptedButtonDisplayed && (\n <AlertStatusButton\n title=\"Accepted\"\n aria-label={AlertStatus.Accepted}\n icon={<AcceptIcon />}\n amount={accepted.length}\n onClick={onStatusButtonClick}\n />\n )}\n {isSnoozedButtonDisplayed && (\n <AlertStatusButton\n title=\"Snoozed\"\n aria-label={AlertStatus.Snoozed}\n amount={snoozed.length}\n icon={<SnoozeIcon />}\n onClick={onStatusButtonClick}\n />\n )}\n {isDismissedButtonDisplayed && (\n <AlertStatusButton\n title=\"Dismissed\"\n aria-label={AlertStatus.Dismissed}\n icon={<DismissIcon />}\n amount={dismissed.length}\n onClick={onStatusButtonClick}\n />\n )}\n </Box>\n )}\n </>\n );\n};\n"],"names":["useStyles"],"mappings":"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"}
@@ -0,0 +1,123 @@
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import { capitalize } from '@material-ui/core/utils';
3
+ import Box from '@material-ui/core/Box';
4
+ import Button from '@material-ui/core/Button';
5
+ import Divider from '@material-ui/core/Divider';
6
+ import Dialog from '@material-ui/core/Dialog';
7
+ import DialogActions from '@material-ui/core/DialogActions';
8
+ import IconButton from '@material-ui/core/IconButton';
9
+ import DialogContent from '@material-ui/core/DialogContent';
10
+ import Typography from '@material-ui/core/Typography';
11
+ import CloseIcon from '@material-ui/icons/Close';
12
+ import { useAlertDialogStyles } from '../../utils/styles.esm.js';
13
+ import { choose, formOf } from '../../utils/alerts.esm.js';
14
+
15
+ const DEFAULT_FORM_ID = "alert-form";
16
+ const AlertDialog = ({
17
+ open,
18
+ group,
19
+ alert,
20
+ status,
21
+ onClose,
22
+ onSubmit
23
+ }) => {
24
+ const classes = useAlertDialogStyles();
25
+ const [isSubmitDisabled, setSubmitDisabled] = useState(true);
26
+ const formRef = useRef(null);
27
+ useEffect(() => {
28
+ setSubmitDisabled(open);
29
+ }, [open]);
30
+ function disableSubmit(isDisabled) {
31
+ setSubmitDisabled(isDisabled);
32
+ }
33
+ function onDialogClose() {
34
+ onClose();
35
+ setSubmitDisabled(true);
36
+ }
37
+ const [action, actioned] = choose(
38
+ status,
39
+ [
40
+ ["snooze", "snoozed"],
41
+ ["accept", "accepted"],
42
+ ["dismiss", "dismissed"]
43
+ ],
44
+ ["", ""]
45
+ );
46
+ const TransitionProps = {
47
+ mountOnEnter: true,
48
+ unmountOnExit: true,
49
+ onEntered() {
50
+ if (formRef.current) {
51
+ formRef.current.id = DEFAULT_FORM_ID;
52
+ }
53
+ }
54
+ };
55
+ const Form = formOf(alert, status);
56
+ return /* @__PURE__ */ React.createElement(
57
+ Dialog,
58
+ {
59
+ open,
60
+ onClose: onDialogClose,
61
+ scroll: "body",
62
+ maxWidth: "lg",
63
+ TransitionProps
64
+ },
65
+ /* @__PURE__ */ React.createElement(Box, { display: "flex", justifyContent: "flex-end" }, /* @__PURE__ */ React.createElement(
66
+ IconButton,
67
+ {
68
+ className: classes.icon,
69
+ disableRipple: true,
70
+ "aria-label": "Close",
71
+ onClick: onDialogClose
72
+ },
73
+ /* @__PURE__ */ React.createElement(CloseIcon, null)
74
+ )),
75
+ /* @__PURE__ */ React.createElement(DialogContent, { className: classes.content }, /* @__PURE__ */ React.createElement(Box, { mb: 1.5 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, /* @__PURE__ */ React.createElement("b", null, capitalize(action), " this action item?")), /* @__PURE__ */ React.createElement(Typography, { variant: "h6", color: "textSecondary" }, /* @__PURE__ */ React.createElement("b", null, "This action item will be ", actioned, " for all of ", group, "."))), /* @__PURE__ */ React.createElement(
76
+ Box,
77
+ {
78
+ display: "flex",
79
+ flexDirection: "column",
80
+ bgcolor: "alertBackground",
81
+ p: 2,
82
+ mb: 1.5,
83
+ borderRadius: 4
84
+ },
85
+ /* @__PURE__ */ React.createElement(Typography, null, /* @__PURE__ */ React.createElement("b", null, alert?.title)),
86
+ /* @__PURE__ */ React.createElement(Typography, { color: "textSecondary" }, alert?.subtitle)
87
+ ), Form && /* @__PURE__ */ React.createElement(
88
+ Form,
89
+ {
90
+ ref: formRef,
91
+ alert,
92
+ onSubmit,
93
+ disableSubmit
94
+ }
95
+ )),
96
+ /* @__PURE__ */ React.createElement(Divider, null),
97
+ /* @__PURE__ */ React.createElement(DialogActions, { className: classes.actions, disableSpacing: true }, Form ? /* @__PURE__ */ React.createElement(
98
+ Button,
99
+ {
100
+ type: "submit",
101
+ color: "primary",
102
+ variant: "contained",
103
+ "aria-label": action,
104
+ form: DEFAULT_FORM_ID,
105
+ disabled: isSubmitDisabled
106
+ },
107
+ capitalize(action)
108
+ ) : /* @__PURE__ */ React.createElement(
109
+ Button,
110
+ {
111
+ type: "button",
112
+ color: "primary",
113
+ variant: "contained",
114
+ "aria-label": action,
115
+ onClick: () => onSubmit(null)
116
+ },
117
+ capitalize(action)
118
+ ))
119
+ );
120
+ };
121
+
122
+ export { AlertDialog };
123
+ //# sourceMappingURL=AlertDialog.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AlertDialog.esm.js","sources":["../../../src/components/AlertInsights/AlertDialog.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 React, { useEffect, useRef, useState } from 'react';\nimport { capitalize } from '@material-ui/core/utils';\nimport Box from '@material-ui/core/Box';\nimport Button from '@material-ui/core/Button';\nimport Divider from '@material-ui/core/Divider';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport IconButton from '@material-ui/core/IconButton';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport Typography from '@material-ui/core/Typography';\nimport { default as CloseIcon } from '@material-ui/icons/Close';\nimport { useAlertDialogStyles as useStyles } from '../../utils/styles';\nimport { Alert, AlertStatus } from '../../types';\nimport { Maybe } from '@backstage-community/plugin-cost-insights-common';\nimport { choose, formOf } from '../../utils/alerts';\n\nconst DEFAULT_FORM_ID = 'alert-form';\n\ntype AlertDialogProps = {\n open: boolean;\n group: string;\n alert: Maybe<Alert>;\n status: Maybe<AlertStatus>;\n onClose: () => void;\n onSubmit: (data: any) => void;\n};\n\nexport const AlertDialog = ({\n open,\n group,\n alert,\n status,\n onClose,\n onSubmit,\n}: AlertDialogProps) => {\n const classes = useStyles();\n const [isSubmitDisabled, setSubmitDisabled] = useState(true);\n const formRef = useRef<Maybe<HTMLFormElement>>(null);\n\n useEffect(() => {\n setSubmitDisabled(open);\n }, [open]);\n\n function disableSubmit(isDisabled: boolean) {\n setSubmitDisabled(isDisabled);\n }\n\n function onDialogClose() {\n onClose();\n setSubmitDisabled(true);\n }\n\n const [action, actioned] = choose(\n status,\n [\n ['snooze', 'snoozed'],\n ['accept', 'accepted'],\n ['dismiss', 'dismissed'],\n ],\n ['', ''],\n );\n\n const TransitionProps = {\n mountOnEnter: true,\n unmountOnExit: true,\n onEntered() {\n if (formRef.current) {\n formRef.current.id = DEFAULT_FORM_ID;\n }\n },\n };\n\n const Form = formOf(alert, status);\n\n return (\n <Dialog\n open={open}\n onClose={onDialogClose}\n scroll=\"body\"\n maxWidth=\"lg\"\n TransitionProps={TransitionProps}\n >\n <Box display=\"flex\" justifyContent=\"flex-end\">\n <IconButton\n className={classes.icon}\n disableRipple\n aria-label=\"Close\"\n onClick={onDialogClose}\n >\n <CloseIcon />\n </IconButton>\n </Box>\n <DialogContent className={classes.content}>\n <Box mb={1.5}>\n <Typography variant=\"h5\">\n <b>{capitalize(action)} this action item?</b>\n </Typography>\n <Typography variant=\"h6\" color=\"textSecondary\">\n <b>\n This action item will be {actioned} for all of {group}.\n </b>\n </Typography>\n </Box>\n <Box\n display=\"flex\"\n flexDirection=\"column\"\n bgcolor=\"alertBackground\"\n p={2}\n mb={1.5}\n borderRadius={4}\n >\n <Typography>\n <b>{alert?.title}</b>\n </Typography>\n <Typography color=\"textSecondary\">{alert?.subtitle}</Typography>\n </Box>\n {Form && (\n <Form\n ref={formRef}\n alert={alert}\n onSubmit={onSubmit}\n disableSubmit={disableSubmit}\n />\n )}\n </DialogContent>\n <Divider />\n <DialogActions className={classes.actions} disableSpacing>\n {Form ? (\n <Button\n type=\"submit\"\n color=\"primary\"\n variant=\"contained\"\n aria-label={action}\n form={DEFAULT_FORM_ID}\n disabled={isSubmitDisabled}\n >\n {capitalize(action)}\n </Button>\n ) : (\n <Button\n type=\"button\"\n color=\"primary\"\n variant=\"contained\"\n aria-label={action}\n onClick={() => onSubmit(null)}\n >\n {capitalize(action)}\n </Button>\n )}\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":["useStyles"],"mappings":";;;;;;;;;;;;;;AAgCA,MAAM,eAAkB,GAAA,YAAA,CAAA;AAWjB,MAAM,cAAc,CAAC;AAAA,EAC1B,IAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AACF,CAAwB,KAAA;AACtB,EAAA,MAAM,UAAUA,oBAAU,EAAA,CAAA;AAC1B,EAAA,MAAM,CAAC,gBAAA,EAAkB,iBAAiB,CAAA,GAAI,SAAS,IAAI,CAAA,CAAA;AAC3D,EAAM,MAAA,OAAA,GAAU,OAA+B,IAAI,CAAA,CAAA;AAEnD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,iBAAA,CAAkB,IAAI,CAAA,CAAA;AAAA,GACxB,EAAG,CAAC,IAAI,CAAC,CAAA,CAAA;AAET,EAAA,SAAS,cAAc,UAAqB,EAAA;AAC1C,IAAA,iBAAA,CAAkB,UAAU,CAAA,CAAA;AAAA,GAC9B;AAEA,EAAA,SAAS,aAAgB,GAAA;AACvB,IAAQ,OAAA,EAAA,CAAA;AACR,IAAA,iBAAA,CAAkB,IAAI,CAAA,CAAA;AAAA,GACxB;AAEA,EAAM,MAAA,CAAC,MAAQ,EAAA,QAAQ,CAAI,GAAA,MAAA;AAAA,IACzB,MAAA;AAAA,IACA;AAAA,MACE,CAAC,UAAU,SAAS,CAAA;AAAA,MACpB,CAAC,UAAU,UAAU,CAAA;AAAA,MACrB,CAAC,WAAW,WAAW,CAAA;AAAA,KACzB;AAAA,IACA,CAAC,IAAI,EAAE,CAAA;AAAA,GACT,CAAA;AAEA,EAAA,MAAM,eAAkB,GAAA;AAAA,IACtB,YAAc,EAAA,IAAA;AAAA,IACd,aAAe,EAAA,IAAA;AAAA,IACf,SAAY,GAAA;AACV,MAAA,IAAI,QAAQ,OAAS,EAAA;AACnB,QAAA,OAAA,CAAQ,QAAQ,EAAK,GAAA,eAAA,CAAA;AAAA,OACvB;AAAA,KACF;AAAA,GACF,CAAA;AAEA,EAAM,MAAA,IAAA,GAAO,MAAO,CAAA,KAAA,EAAO,MAAM,CAAA,CAAA;AAEjC,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,IAAA;AAAA,MACA,OAAS,EAAA,aAAA;AAAA,MACT,MAAO,EAAA,MAAA;AAAA,MACP,QAAS,EAAA,IAAA;AAAA,MACT,eAAA;AAAA,KAAA;AAAA,oBAEC,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,OAAQ,EAAA,MAAA,EAAO,gBAAe,UACjC,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,WAAW,OAAQ,CAAA,IAAA;AAAA,QACnB,aAAa,EAAA,IAAA;AAAA,QACb,YAAW,EAAA,OAAA;AAAA,QACX,OAAS,EAAA,aAAA;AAAA,OAAA;AAAA,0CAER,SAAU,EAAA,IAAA,CAAA;AAAA,KAEf,CAAA;AAAA,wCACC,aAAc,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,OAAA,EAAA,sCAC/B,GAAI,EAAA,EAAA,EAAA,EAAI,GACP,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAW,OAAQ,EAAA,IAAA,EAAA,kBACjB,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,IAAA,EAAG,WAAW,MAAM,CAAA,EAAE,oBAAkB,CAC3C,mBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,IAAA,EAAK,OAAM,eAC7B,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAE,EAAA,IAAA,EAAA,2BAAA,EACyB,UAAS,cAAa,EAAA,KAAA,EAAM,GACxD,CACF,CACF,CACA,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,OAAQ,EAAA,MAAA;AAAA,QACR,aAAc,EAAA,QAAA;AAAA,QACd,OAAQ,EAAA,iBAAA;AAAA,QACR,CAAG,EAAA,CAAA;AAAA,QACH,EAAI,EAAA,GAAA;AAAA,QACJ,YAAc,EAAA,CAAA;AAAA,OAAA;AAAA,0CAEb,UACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAG,EAAA,IAAA,EAAA,KAAA,EAAO,KAAM,CACnB,CAAA;AAAA,sBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,KAAM,EAAA,eAAA,EAAA,EAAiB,OAAO,QAAS,CAAA;AAAA,OAEpD,IACC,oBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACC,GAAK,EAAA,OAAA;AAAA,QACL,KAAA;AAAA,QACA,QAAA;AAAA,QACA,aAAA;AAAA,OAAA;AAAA,KAGN,CAAA;AAAA,wCACC,OAAQ,EAAA,IAAA,CAAA;AAAA,wCACR,aAAc,EAAA,EAAA,SAAA,EAAW,QAAQ,OAAS,EAAA,cAAA,EAAc,QACtD,IACC,mBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,IAAK,EAAA,QAAA;AAAA,QACL,KAAM,EAAA,SAAA;AAAA,QACN,OAAQ,EAAA,WAAA;AAAA,QACR,YAAY,EAAA,MAAA;AAAA,QACZ,IAAM,EAAA,eAAA;AAAA,QACN,QAAU,EAAA,gBAAA;AAAA,OAAA;AAAA,MAET,WAAW,MAAM,CAAA;AAAA,KAGpB,mBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,IAAK,EAAA,QAAA;AAAA,QACL,KAAM,EAAA,SAAA;AAAA,QACN,OAAQ,EAAA,WAAA;AAAA,QACR,YAAY,EAAA,MAAA;AAAA,QACZ,OAAA,EAAS,MAAM,QAAA,CAAS,IAAI,CAAA;AAAA,OAAA;AAAA,MAE3B,WAAW,MAAM,CAAA;AAAA,KAGxB,CAAA;AAAA,GACF,CAAA;AAEJ;;;;"}
@@ -0,0 +1,157 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import pluralize from 'pluralize';
3
+ import Box from '@material-ui/core/Box';
4
+ import Grid from '@material-ui/core/Grid';
5
+ import Snackbar from '@material-ui/core/Snackbar';
6
+ import Alert from '@material-ui/lab/Alert';
7
+ import { AlertDialog } from './AlertDialog.esm.js';
8
+ import { AlertStatusSummary } from './AlertStatusSummary.esm.js';
9
+ import { AlertStatusSummaryButton } from './AlertStatusSummaryButton.esm.js';
10
+ import { AlertInsightsHeader } from './AlertInsightsHeader.esm.js';
11
+ import { AlertInsightsSection } from './AlertInsightsSection.esm.js';
12
+ import '../../hooks/useConfig.esm.js';
13
+ import '../../hooks/useCurrency.esm.js';
14
+ import '../../hooks/useFilters.esm.js';
15
+ import '../../hooks/useGroups.esm.js';
16
+ import { useLoading } from '../../hooks/useLoading.esm.js';
17
+ import { useScroll, ScrollType } from '../../hooks/useScroll.esm.js';
18
+ import '../../hooks/useLastCompleteBillingDate.esm.js';
19
+ import { DefaultLoadingAction } from '../../utils/loading.esm.js';
20
+ import { AlertStatus } from '../../types/Alert.esm.js';
21
+ import { isStatusSnoozed, isStatusAccepted, isStatusDismissed, sumOfAllAlerts } from '../../utils/alerts.esm.js';
22
+ import { ScrollAnchor } from '../../utils/scroll.esm.js';
23
+
24
+ const mapLoadingToAlerts = ({ dispatch }) => (isLoading) => dispatch({ [DefaultLoadingAction.CostInsightsAlerts]: isLoading });
25
+ const AlertInsights = ({
26
+ group,
27
+ active,
28
+ snoozed,
29
+ accepted,
30
+ dismissed,
31
+ onChange
32
+ }) => {
33
+ const [scroll] = useScroll();
34
+ const [alert, setAlert] = useState(null);
35
+ const dispatchLoadingAlerts = useLoading(mapLoadingToAlerts);
36
+ const [status, setStatus] = useState(null);
37
+ const [data, setData] = useState(void 0);
38
+ const [error, setError] = useState(null);
39
+ const [isDialogOpen, setDialogOpen] = useState(false);
40
+ const [isSummaryOpen, setSummaryOpen] = useState(false);
41
+ const [isSnackbarOpen, setSnackbarOpen] = useState(false);
42
+ useEffect(() => {
43
+ async function callAlertHook(options2, callback) {
44
+ setAlert(null);
45
+ setStatus(null);
46
+ setData(void 0);
47
+ setDialogOpen(false);
48
+ dispatchLoadingAlerts(true);
49
+ try {
50
+ const alerts = await callback(options2);
51
+ onChange(alerts);
52
+ } catch (e) {
53
+ setError(e);
54
+ } finally {
55
+ dispatchLoadingAlerts(false);
56
+ }
57
+ }
58
+ const options = { data, group };
59
+ const onSnoozed = alert?.onSnoozed?.bind(alert);
60
+ const onAccepted = alert?.onAccepted?.bind(alert);
61
+ const onDismissed = alert?.onDismissed?.bind(alert);
62
+ if (data !== void 0) {
63
+ if (isStatusSnoozed(status) && onSnoozed) {
64
+ callAlertHook(options, onSnoozed);
65
+ } else if (isStatusAccepted(status) && onAccepted) {
66
+ callAlertHook(options, onAccepted);
67
+ } else if (isStatusDismissed(status) && onDismissed) {
68
+ callAlertHook(options, onDismissed);
69
+ }
70
+ }
71
+ }, [group, data, alert, status, onChange, dispatchLoadingAlerts]);
72
+ useEffect(() => {
73
+ if (scroll === ScrollType.AlertSummary) {
74
+ setSummaryOpen(true);
75
+ }
76
+ }, [scroll]);
77
+ useEffect(() => {
78
+ setDialogOpen(!!status);
79
+ }, [status]);
80
+ useEffect(() => {
81
+ setSnackbarOpen(!!error);
82
+ }, [error]);
83
+ function onSnooze(alertToSnooze) {
84
+ setAlert(alertToSnooze);
85
+ setStatus(AlertStatus.Snoozed);
86
+ }
87
+ function onAccept(alertToAccept) {
88
+ setAlert(alertToAccept);
89
+ setStatus(AlertStatus.Accepted);
90
+ }
91
+ function onDismiss(alertToDismiss) {
92
+ setAlert(alertToDismiss);
93
+ setStatus(AlertStatus.Dismissed);
94
+ }
95
+ function onSnackbarClose() {
96
+ setError(null);
97
+ }
98
+ function onDialogClose() {
99
+ setAlert(null);
100
+ setStatus(null);
101
+ }
102
+ function onDialogFormSubmit(formData) {
103
+ setData(formData);
104
+ }
105
+ function onSummaryButtonClick() {
106
+ setSummaryOpen((prevOpen) => !prevOpen);
107
+ }
108
+ const total = [accepted, snoozed, dismissed].reduce(sumOfAllAlerts, 0);
109
+ const isAlertStatusSummaryDisplayed = !!total;
110
+ const isAlertInsightSectionDisplayed = !!active.length;
111
+ return /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "column", spacing: 2 }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(
112
+ AlertInsightsHeader,
113
+ {
114
+ title: "Your team's action items",
115
+ subtitle: isAlertInsightSectionDisplayed ? "This section outlines suggested action items your team can address to improve cloud costs." : "All of your team's action items are hidden. Maybe it's time to give them another look?"
116
+ }
117
+ )), isAlertInsightSectionDisplayed && /* @__PURE__ */ React.createElement(Grid, { item: true, container: true, direction: "column", spacing: 4 }, active.map((activeAlert, index) => /* @__PURE__ */ React.createElement(Grid, { item: true, key: `alert-insights-section-${index}` }, /* @__PURE__ */ React.createElement(
118
+ AlertInsightsSection,
119
+ {
120
+ alert: activeAlert,
121
+ number: index + 1,
122
+ onSnooze,
123
+ onAccept,
124
+ onDismiss
125
+ }
126
+ )))), isAlertStatusSummaryDisplayed && /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Box, { position: "relative", display: "flex", justifyContent: "flex-end" }, /* @__PURE__ */ React.createElement(ScrollAnchor, { id: ScrollType.AlertSummary }), /* @__PURE__ */ React.createElement(AlertStatusSummaryButton, { onClick: onSummaryButtonClick }, pluralize("Hidden Action Item", total))), /* @__PURE__ */ React.createElement(
127
+ AlertStatusSummary,
128
+ {
129
+ open: isSummaryOpen,
130
+ snoozed,
131
+ accepted,
132
+ dismissed
133
+ }
134
+ )), /* @__PURE__ */ React.createElement(
135
+ AlertDialog,
136
+ {
137
+ group,
138
+ open: isDialogOpen,
139
+ alert,
140
+ status,
141
+ onClose: onDialogClose,
142
+ onSubmit: onDialogFormSubmit
143
+ }
144
+ ), /* @__PURE__ */ React.createElement(
145
+ Snackbar,
146
+ {
147
+ open: isSnackbarOpen,
148
+ autoHideDuration: 6e3,
149
+ anchorOrigin: { vertical: "top", horizontal: "center" },
150
+ onClose: onSnackbarClose
151
+ },
152
+ /* @__PURE__ */ React.createElement(Alert, { onClose: onSnackbarClose, severity: "error" }, error?.message)
153
+ ));
154
+ };
155
+
156
+ export { AlertInsights };
157
+ //# sourceMappingURL=AlertInsights.esm.js.map