@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 @@
1
+ {"version":3,"file":"AlertAcceptForm.esm.js","sources":["../../src/forms/AlertAcceptForm.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, {\n useState,\n forwardRef,\n ChangeEvent,\n FormEventHandler,\n} from 'react';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport { Alert, AlertFormProps } from '../types';\n\nexport type AlertAcceptFormProps = AlertFormProps<Alert, null>;\n\nexport const AlertAcceptForm = forwardRef<\n HTMLFormElement,\n AlertAcceptFormProps\n>(({ onSubmit, disableSubmit }, ref) => {\n const [checked, setChecked] = useState(false);\n\n const onFormSubmit: FormEventHandler = e => {\n e.preventDefault();\n onSubmit(null);\n };\n\n const onChecked = (_: ChangeEvent<HTMLInputElement>, isChecked: boolean) => {\n setChecked(isChecked);\n disableSubmit(!isChecked);\n };\n\n return (\n <form ref={ref} onSubmit={onFormSubmit}>\n <FormControl component=\"fieldset\" fullWidth>\n <FormControlLabel\n label=\"My team can commit to making this change soon, or has already.\"\n value={checked}\n control={\n <Checkbox color=\"primary\" checked={checked} onChange={onChecked} />\n }\n />\n </FormControl>\n </form>\n );\n});\n"],"names":[],"mappings":";;;;;AA6BO,MAAM,kBAAkB,UAG7B,CAAA,CAAC,EAAE,QAAU,EAAA,aAAA,IAAiB,GAAQ,KAAA;AACtC,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA,CAAA;AAE5C,EAAA,MAAM,eAAiC,CAAK,CAAA,KAAA;AAC1C,IAAA,CAAA,CAAE,cAAe,EAAA,CAAA;AACjB,IAAA,QAAA,CAAS,IAAI,CAAA,CAAA;AAAA,GACf,CAAA;AAEA,EAAM,MAAA,SAAA,GAAY,CAAC,CAAA,EAAkC,SAAuB,KAAA;AAC1E,IAAA,UAAA,CAAW,SAAS,CAAA,CAAA;AACpB,IAAA,aAAA,CAAc,CAAC,SAAS,CAAA,CAAA;AAAA,GAC1B,CAAA;AAEA,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,MAAK,EAAA,EAAA,GAAA,EAAU,QAAU,EAAA,YAAA,EAAA,sCACvB,WAAY,EAAA,EAAA,SAAA,EAAU,UAAW,EAAA,SAAA,EAAS,IACzC,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,gBAAA;AAAA,IAAA;AAAA,MACC,KAAM,EAAA,gEAAA;AAAA,MACN,KAAO,EAAA,OAAA;AAAA,MACP,yBACG,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,OAAM,SAAU,EAAA,OAAA,EAAkB,UAAU,SAAW,EAAA,CAAA;AAAA,KAAA;AAAA,GAGvE,CACF,CAAA,CAAA;AAEJ,CAAC;;;;"}
@@ -0,0 +1,100 @@
1
+ import React, { forwardRef, useState, useEffect } from 'react';
2
+ import Box from '@material-ui/core/Box';
3
+ import Collapse from '@material-ui/core/Collapse';
4
+ import FormControl from '@material-ui/core/FormControl';
5
+ import FormControlLabel from '@material-ui/core/FormControlLabel';
6
+ import TextField from '@material-ui/core/TextField';
7
+ import Typography from '@material-ui/core/Typography';
8
+ import Radio from '@material-ui/core/Radio';
9
+ import RadioGroup from '@material-ui/core/RadioGroup';
10
+ import { AlertDismissReason, AlertDismissOptions } from '../types/Alert.esm.js';
11
+ import { useAlertDialogStyles } from '../utils/styles.esm.js';
12
+
13
+ const AlertDismissForm = forwardRef(({ onSubmit, disableSubmit }, ref) => {
14
+ const classes = useAlertDialogStyles();
15
+ const [other, setOther] = useState(null);
16
+ const [feedback, setFeedback] = useState(null);
17
+ const [reason, setReason] = useState(
18
+ AlertDismissReason.Resolved
19
+ );
20
+ const onFormSubmit = (e) => {
21
+ e.preventDefault();
22
+ if (reason) {
23
+ onSubmit({
24
+ other,
25
+ reason,
26
+ feedback
27
+ });
28
+ }
29
+ };
30
+ const onReasonChange = (_, value) => {
31
+ if (other) {
32
+ setOther(null);
33
+ }
34
+ setReason(value);
35
+ };
36
+ const onOtherChange = (e) => {
37
+ return e.target.value ? setOther(e.target.value) : setOther(null);
38
+ };
39
+ const onFeedbackChange = (e) => {
40
+ return e.target.value ? setFeedback(e.target.value) : setFeedback(null);
41
+ };
42
+ useEffect(() => {
43
+ function validateDismissForm() {
44
+ if (reason === AlertDismissReason.Other) {
45
+ if (other) {
46
+ disableSubmit(false);
47
+ } else {
48
+ disableSubmit(true);
49
+ }
50
+ } else if (reason) {
51
+ disableSubmit(false);
52
+ } else {
53
+ disableSubmit(true);
54
+ }
55
+ }
56
+ validateDismissForm();
57
+ }, [reason, other, disableSubmit]);
58
+ return /* @__PURE__ */ React.createElement("form", { ref, onSubmit: onFormSubmit }, /* @__PURE__ */ React.createElement(FormControl, { component: "fieldset", fullWidth: true }, /* @__PURE__ */ React.createElement(Typography, { color: "textPrimary" }, /* @__PURE__ */ React.createElement("b", null, "Reason for dismissing?")), /* @__PURE__ */ React.createElement(Box, { mb: 1 }, /* @__PURE__ */ React.createElement(
59
+ RadioGroup,
60
+ {
61
+ name: "dismiss-alert-reasons",
62
+ value: reason,
63
+ onChange: onReasonChange
64
+ },
65
+ AlertDismissOptions.map((option) => /* @__PURE__ */ React.createElement(
66
+ FormControlLabel,
67
+ {
68
+ key: `dismiss-alert-option-${option.reason}`,
69
+ label: option.label,
70
+ value: option.reason,
71
+ control: /* @__PURE__ */ React.createElement(Radio, { className: classes.radio })
72
+ }
73
+ ))
74
+ ), /* @__PURE__ */ React.createElement(Collapse, { in: reason === AlertDismissReason.Other }, /* @__PURE__ */ React.createElement(Box, { ml: 4 }, /* @__PURE__ */ React.createElement(
75
+ TextField,
76
+ {
77
+ id: "dismiss-alert-option-other",
78
+ variant: "outlined",
79
+ multiline: true,
80
+ fullWidth: true,
81
+ rows: 4,
82
+ value: other ?? "",
83
+ onChange: onOtherChange
84
+ }
85
+ )))), /* @__PURE__ */ React.createElement(Typography, { gutterBottom: true }, /* @__PURE__ */ React.createElement("b", null, "Any other feedback you can provide?")), /* @__PURE__ */ React.createElement(
86
+ TextField,
87
+ {
88
+ id: "dismiss-alert-feedback",
89
+ variant: "outlined",
90
+ multiline: true,
91
+ rows: 4,
92
+ fullWidth: true,
93
+ value: feedback ?? "",
94
+ onChange: onFeedbackChange
95
+ }
96
+ )));
97
+ });
98
+
99
+ export { AlertDismissForm };
100
+ //# sourceMappingURL=AlertDismissForm.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AlertDismissForm.esm.js","sources":["../../src/forms/AlertDismissForm.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, {\n ChangeEvent,\n useEffect,\n useState,\n forwardRef,\n FormEventHandler,\n} from 'react';\nimport Box from '@material-ui/core/Box';\nimport Collapse from '@material-ui/core/Collapse';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport TextField from '@material-ui/core/TextField';\nimport Typography from '@material-ui/core/Typography';\nimport Radio from '@material-ui/core/Radio';\nimport RadioGroup from '@material-ui/core/RadioGroup';\nimport {\n Alert,\n AlertFormProps,\n AlertDismissReason,\n AlertDismissOptions,\n AlertDismissFormData,\n} from '../types';\nimport { Maybe } from '@backstage-community/plugin-cost-insights-common';\nimport { useAlertDialogStyles as useStyles } from '../utils/styles';\n\nexport type AlertDismissFormProps = AlertFormProps<Alert, AlertDismissFormData>;\n\nexport const AlertDismissForm = forwardRef<\n HTMLFormElement,\n AlertDismissFormProps\n>(({ onSubmit, disableSubmit }, ref) => {\n const classes = useStyles();\n const [other, setOther] = useState<Maybe<string>>(null);\n const [feedback, setFeedback] = useState<Maybe<string>>(null);\n const [reason, setReason] = useState<AlertDismissReason>(\n AlertDismissReason.Resolved,\n );\n\n const onFormSubmit: FormEventHandler = e => {\n e.preventDefault();\n if (reason) {\n onSubmit({\n other: other,\n reason: reason,\n feedback: feedback,\n });\n }\n };\n\n const onReasonChange = (_: ChangeEvent<HTMLInputElement>, value: string) => {\n if (other) {\n setOther(null);\n }\n setReason(value as AlertDismissReason);\n };\n\n const onOtherChange = (e: ChangeEvent<HTMLInputElement>) => {\n return e.target.value\n ? setOther(e.target.value as AlertDismissReason)\n : setOther(null);\n };\n\n const onFeedbackChange = (e: ChangeEvent<HTMLInputElement>) => {\n return e.target.value\n ? setFeedback(e.target.value as AlertDismissReason)\n : setFeedback(null);\n };\n\n useEffect(() => {\n function validateDismissForm() {\n if (reason === AlertDismissReason.Other) {\n if (other) {\n disableSubmit(false);\n } else {\n disableSubmit(true);\n }\n } else if (reason) {\n disableSubmit(false);\n } else {\n disableSubmit(true);\n }\n }\n\n validateDismissForm();\n }, [reason, other, disableSubmit]);\n\n return (\n <form ref={ref} onSubmit={onFormSubmit}>\n <FormControl component=\"fieldset\" fullWidth>\n <Typography color=\"textPrimary\">\n <b>Reason for dismissing?</b>\n </Typography>\n <Box mb={1}>\n <RadioGroup\n name=\"dismiss-alert-reasons\"\n value={reason}\n onChange={onReasonChange}\n >\n {AlertDismissOptions.map(option => (\n <FormControlLabel\n key={`dismiss-alert-option-${option.reason}`}\n label={option.label}\n value={option.reason}\n control={<Radio className={classes.radio} />}\n />\n ))}\n </RadioGroup>\n <Collapse in={reason === AlertDismissReason.Other}>\n <Box ml={4}>\n <TextField\n id=\"dismiss-alert-option-other\"\n variant=\"outlined\"\n multiline\n fullWidth\n rows={4}\n value={other ?? ''}\n onChange={onOtherChange}\n />\n </Box>\n </Collapse>\n </Box>\n <Typography gutterBottom>\n <b>Any other feedback you can provide?</b>\n </Typography>\n <TextField\n id=\"dismiss-alert-feedback\"\n variant=\"outlined\"\n multiline\n rows={4}\n fullWidth\n value={feedback ?? ''}\n onChange={onFeedbackChange}\n />\n </FormControl>\n </form>\n );\n});\n"],"names":["useStyles"],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import React, { forwardRef, useState, useEffect } from 'react';
2
+ import { DateTime } from 'luxon';
3
+ import Box from '@material-ui/core/Box';
4
+ import FormControl from '@material-ui/core/FormControl';
5
+ import FormControlLabel from '@material-ui/core/FormControlLabel';
6
+ import RadioGroup from '@material-ui/core/RadioGroup';
7
+ import Radio from '@material-ui/core/Radio';
8
+ import Typography from '@material-ui/core/Typography';
9
+ import { AlertSnoozeOptions } from '../types/Alert.esm.js';
10
+ import { DEFAULT_DATE_FORMAT } from '../types/DateFormat.esm.js';
11
+ import { Duration } from '../types/Duration.esm.js';
12
+ import { useAlertDialogStyles } from '../utils/styles.esm.js';
13
+ import { intervalsOf } from '../utils/duration.esm.js';
14
+
15
+ const AlertSnoozeForm = forwardRef(({ onSubmit, disableSubmit }, ref) => {
16
+ const classes = useAlertDialogStyles();
17
+ const [duration, setDuration] = useState(Duration.P7D);
18
+ useEffect(() => disableSubmit(false), [disableSubmit]);
19
+ const onFormSubmit = (e) => {
20
+ e.preventDefault();
21
+ if (duration) {
22
+ const repeatInterval = 1;
23
+ const today = DateTime.now().toFormat(DEFAULT_DATE_FORMAT);
24
+ onSubmit({
25
+ intervals: intervalsOf(duration, today, repeatInterval)
26
+ });
27
+ }
28
+ };
29
+ const onSnoozeDurationChange = (_, value) => {
30
+ setDuration(value);
31
+ };
32
+ return /* @__PURE__ */ React.createElement("form", { ref, onSubmit: onFormSubmit }, /* @__PURE__ */ React.createElement(FormControl, { component: "fieldset", fullWidth: true }, /* @__PURE__ */ React.createElement(Typography, { color: "textPrimary" }, /* @__PURE__ */ React.createElement("b", null, "For how long?")), /* @__PURE__ */ React.createElement(Box, { mb: 1 }, /* @__PURE__ */ React.createElement(
33
+ RadioGroup,
34
+ {
35
+ name: "snooze-alert-options",
36
+ value: duration,
37
+ onChange: onSnoozeDurationChange
38
+ },
39
+ AlertSnoozeOptions.map((option) => /* @__PURE__ */ React.createElement(
40
+ FormControlLabel,
41
+ {
42
+ key: `snooze-alert-option-${option.duration}`,
43
+ label: option.label,
44
+ value: option.duration,
45
+ control: /* @__PURE__ */ React.createElement(Radio, { className: classes.radio })
46
+ }
47
+ ))
48
+ ))));
49
+ });
50
+
51
+ export { AlertSnoozeForm };
52
+ //# sourceMappingURL=AlertSnoozeForm.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AlertSnoozeForm.esm.js","sources":["../../src/forms/AlertSnoozeForm.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, {\n ChangeEvent,\n useEffect,\n useState,\n forwardRef,\n FormEventHandler,\n} from 'react';\nimport { DateTime } from 'luxon';\nimport Box from '@material-ui/core/Box';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport RadioGroup from '@material-ui/core/RadioGroup';\nimport Radio from '@material-ui/core/Radio';\nimport Typography from '@material-ui/core/Typography';\nimport {\n Alert,\n AlertFormProps,\n Duration,\n DEFAULT_DATE_FORMAT,\n AlertSnoozeFormData,\n AlertSnoozeOptions,\n} from '../types';\nimport { Maybe } from '@backstage-community/plugin-cost-insights-common';\nimport { useAlertDialogStyles as useStyles } from '../utils/styles';\nimport { intervalsOf } from '../utils/duration';\n\nexport type AlertSnoozeFormProps = AlertFormProps<Alert, AlertSnoozeFormData>;\n\nexport const AlertSnoozeForm = forwardRef<\n HTMLFormElement,\n AlertSnoozeFormProps\n>(({ onSubmit, disableSubmit }, ref) => {\n const classes = useStyles();\n const [duration, setDuration] = useState<Maybe<Duration>>(Duration.P7D);\n\n useEffect(() => disableSubmit(false), [disableSubmit]);\n\n const onFormSubmit: FormEventHandler = e => {\n e.preventDefault();\n if (duration) {\n const repeatInterval = 1;\n const today = DateTime.now().toFormat(DEFAULT_DATE_FORMAT);\n onSubmit({\n intervals: intervalsOf(duration, today, repeatInterval),\n });\n }\n };\n\n const onSnoozeDurationChange = (\n _: ChangeEvent<HTMLInputElement>,\n value: string,\n ) => {\n setDuration(value as Duration);\n };\n\n return (\n <form ref={ref} onSubmit={onFormSubmit}>\n <FormControl component=\"fieldset\" fullWidth>\n <Typography color=\"textPrimary\">\n <b>For how long?</b>\n </Typography>\n <Box mb={1}>\n <RadioGroup\n name=\"snooze-alert-options\"\n value={duration}\n onChange={onSnoozeDurationChange}\n >\n {AlertSnoozeOptions.map(option => (\n <FormControlLabel\n key={`snooze-alert-option-${option.duration}`}\n label={option.label}\n value={option.duration}\n control={<Radio className={classes.radio} />}\n />\n ))}\n </RadioGroup>\n </Box>\n </FormControl>\n </form>\n );\n});\n"],"names":["useStyles"],"mappings":";;;;;;;;;;;;;;AA4CO,MAAM,kBAAkB,UAG7B,CAAA,CAAC,EAAE,QAAU,EAAA,aAAA,IAAiB,GAAQ,KAAA;AACtC,EAAA,MAAM,UAAUA,oBAAU,EAAA,CAAA;AAC1B,EAAA,MAAM,CAAC,QAAU,EAAA,WAAW,CAAI,GAAA,QAAA,CAA0B,SAAS,GAAG,CAAA,CAAA;AAEtE,EAAA,SAAA,CAAU,MAAM,aAAc,CAAA,KAAK,CAAG,EAAA,CAAC,aAAa,CAAC,CAAA,CAAA;AAErD,EAAA,MAAM,eAAiC,CAAK,CAAA,KAAA;AAC1C,IAAA,CAAA,CAAE,cAAe,EAAA,CAAA;AACjB,IAAA,IAAI,QAAU,EAAA;AACZ,MAAA,MAAM,cAAiB,GAAA,CAAA,CAAA;AACvB,MAAA,MAAM,KAAQ,GAAA,QAAA,CAAS,GAAI,EAAA,CAAE,SAAS,mBAAmB,CAAA,CAAA;AACzD,MAAS,QAAA,CAAA;AAAA,QACP,SAAW,EAAA,WAAA,CAAY,QAAU,EAAA,KAAA,EAAO,cAAc,CAAA;AAAA,OACvD,CAAA,CAAA;AAAA,KACH;AAAA,GACF,CAAA;AAEA,EAAM,MAAA,sBAAA,GAAyB,CAC7B,CAAA,EACA,KACG,KAAA;AACH,IAAA,WAAA,CAAY,KAAiB,CAAA,CAAA;AAAA,GAC/B,CAAA;AAEA,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,UAAK,GAAU,EAAA,QAAA,EAAU,gCACvB,KAAA,CAAA,aAAA,CAAA,WAAA,EAAA,EAAY,SAAU,EAAA,UAAA,EAAW,SAAS,EAAA,IAAA,EAAA,sCACxC,UAAW,EAAA,EAAA,KAAA,EAAM,aAChB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAE,EAAA,IAAA,EAAA,eAAa,CAClB,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,EAAA,EAAI,CACP,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,IAAK,EAAA,sBAAA;AAAA,MACL,KAAO,EAAA,QAAA;AAAA,MACP,QAAU,EAAA,sBAAA;AAAA,KAAA;AAAA,IAET,kBAAA,CAAmB,IAAI,CACtB,MAAA,qBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,gBAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,CAAuB,oBAAA,EAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AAAA,QAC3C,OAAO,MAAO,CAAA,KAAA;AAAA,QACd,OAAO,MAAO,CAAA,QAAA;AAAA,QACd,OAAS,kBAAA,KAAA,CAAA,aAAA,CAAC,KAAM,EAAA,EAAA,SAAA,EAAW,QAAQ,KAAO,EAAA,CAAA;AAAA,OAAA;AAAA,KAE7C,CAAA;AAAA,GAEL,CACF,CACF,CAAA,CAAA;AAEJ,CAAC;;;;"}
@@ -0,0 +1,153 @@
1
+ import React, { createContext, useState, useEffect, useContext } from 'react';
2
+ import '../types/Alert.esm.js';
3
+ import { EngineerThreshold } from '../types/ChangeStatistic.esm.js';
4
+ import { getIcon } from '../utils/navigation.esm.js';
5
+ import { validateMetrics, validateCurrencies } from '../utils/config.esm.js';
6
+ import { createCurrencyFormat, defaultCurrencies } from '../utils/currency.esm.js';
7
+ import { useApi, configApiRef } from '@backstage/core-plugin-api';
8
+
9
+ const ConfigContext = createContext(
10
+ void 0
11
+ );
12
+ const defaultState = {
13
+ baseCurrency: createCurrencyFormat(),
14
+ metrics: [],
15
+ products: [],
16
+ icons: [],
17
+ engineerCost: 0,
18
+ engineerThreshold: EngineerThreshold,
19
+ hideTrendLine: false,
20
+ currencies: defaultCurrencies
21
+ };
22
+ const ConfigProvider = ({ children }) => {
23
+ const c = useApi(configApiRef);
24
+ const [config, setConfig] = useState(defaultState);
25
+ const [loading, setLoading] = useState(true);
26
+ useEffect(() => {
27
+ function getProducts() {
28
+ const products = c.getOptionalConfig("costInsights.products");
29
+ if (products) {
30
+ return products.keys().map((key) => ({
31
+ kind: key,
32
+ name: products.getString(`${key}.name`),
33
+ aggregation: [0, 0]
34
+ }));
35
+ }
36
+ return [];
37
+ }
38
+ function getMetrics() {
39
+ const metrics = c.getOptionalConfig("costInsights.metrics");
40
+ if (metrics) {
41
+ return metrics.keys().map((key) => ({
42
+ kind: key,
43
+ name: metrics.getString(`${key}.name`),
44
+ default: metrics.getOptionalBoolean(`${key}.default`) ?? false
45
+ }));
46
+ }
47
+ return [];
48
+ }
49
+ function getBaseCurrency() {
50
+ const baseCurrency = c.getOptionalConfig("costInsights.baseCurrency");
51
+ if (baseCurrency) {
52
+ const options = baseCurrency.getOptionalConfig("options");
53
+ return new Intl.NumberFormat(
54
+ baseCurrency.getOptionalString("locale"),
55
+ options ? {
56
+ localeMatcher: options.getOptionalString("localeMatcher"),
57
+ style: "currency",
58
+ currency: options.getOptionalString("currency"),
59
+ currencySign: options.getOptionalString("currencySign"),
60
+ useGrouping: options.getOptionalBoolean("useGrouping"),
61
+ minimumIntegerDigits: options.getOptionalNumber(
62
+ "minimumIntegerDigits"
63
+ ),
64
+ minimumFractionDigits: options.getOptionalNumber(
65
+ "minimumFractionDigits"
66
+ ),
67
+ maximumFractionDigits: options.getOptionalNumber(
68
+ "maximumFractionDigits"
69
+ ),
70
+ minimumSignificantDigits: options.getOptionalNumber(
71
+ "minimumSignificantDigits"
72
+ ),
73
+ maximumSignificantDigits: options.getOptionalNumber(
74
+ "maximumSignificantDigits"
75
+ )
76
+ } : void 0
77
+ );
78
+ }
79
+ return defaultState.baseCurrency;
80
+ }
81
+ function getCurrencies() {
82
+ const currencies = c.getOptionalConfig("costInsights.currencies");
83
+ if (currencies) {
84
+ return currencies.keys().map((key) => ({
85
+ label: currencies.getString(`${key}.label`),
86
+ unit: currencies.getString(`${key}.unit`),
87
+ kind: currencies.getOptionalString(`${key}.kind`) || null,
88
+ prefix: currencies.getOptionalString(`${key}.prefix`),
89
+ rate: currencies.getOptionalNumber(`${key}.rate`)
90
+ }));
91
+ }
92
+ return defaultCurrencies;
93
+ }
94
+ function getIcons() {
95
+ const products = c.getOptionalConfig("costInsights.products");
96
+ if (products) {
97
+ return products.keys().map((k) => ({
98
+ kind: k,
99
+ component: getIcon(products.getOptionalString(`${k}.icon`))
100
+ }));
101
+ }
102
+ return [];
103
+ }
104
+ function getEngineerCost() {
105
+ return c.getNumber("costInsights.engineerCost");
106
+ }
107
+ function getEngineerThreshold() {
108
+ return c.getOptionalNumber("costInsights.engineerThreshold") ?? defaultState.engineerThreshold;
109
+ }
110
+ function getHideTrendLine() {
111
+ return c.getOptionalBoolean("costInsights.hideTrendLine") ?? defaultState.hideTrendLine;
112
+ }
113
+ function getConfig() {
114
+ const baseCurrency = getBaseCurrency();
115
+ const products = getProducts();
116
+ const metrics = getMetrics();
117
+ const engineerCost = getEngineerCost();
118
+ const engineerThreshold = getEngineerThreshold();
119
+ const hideTrendLine = getHideTrendLine();
120
+ const icons = getIcons();
121
+ const currencies = getCurrencies();
122
+ validateMetrics(metrics);
123
+ validateCurrencies(currencies);
124
+ setConfig((prevState) => ({
125
+ ...prevState,
126
+ baseCurrency,
127
+ metrics,
128
+ products,
129
+ engineerCost,
130
+ engineerThreshold,
131
+ hideTrendLine,
132
+ icons,
133
+ currencies
134
+ }));
135
+ setLoading(false);
136
+ }
137
+ getConfig();
138
+ }, []);
139
+ if (loading) {
140
+ return null;
141
+ }
142
+ return /* @__PURE__ */ React.createElement(ConfigContext.Provider, { value: config }, children);
143
+ };
144
+ function useConfig() {
145
+ const config = useContext(ConfigContext);
146
+ return config ? config : assertNever();
147
+ }
148
+ function assertNever() {
149
+ throw new Error("Cannot use useConfig outside of ConfigProvider");
150
+ }
151
+
152
+ export { ConfigContext, ConfigProvider, useConfig };
153
+ //# sourceMappingURL=useConfig.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConfig.esm.js","sources":["../../src/hooks/useConfig.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, {\n createContext,\n PropsWithChildren,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport { Config as BackstageConfig } from '@backstage/config';\nimport { Currency, EngineerThreshold, Icon } from '../types';\nimport {\n Metric,\n Product,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { getIcon } from '../utils/navigation';\nimport { validateCurrencies, validateMetrics } from '../utils/config';\nimport { createCurrencyFormat, defaultCurrencies } from '../utils/currency';\nimport { configApiRef, useApi } from '@backstage/core-plugin-api';\n\n/*\n * Config schema 2021-08-05\n *\n * costInsights:\n * engineerCost: 200000\n * products:\n * productA:\n * name: Product A\n * icon: storage\n * productB:\n * name: Product B\n * icon: data\n * metrics:\n * metricA:\n * name: Metric A\n * default: true\n * metricB:\n * name: Metric B\n * baseCurrency:\n * locale: nl-NL\n * options:\n * currency: EUR\n * minimumFractionDigits: 3\n * currencies:\n * currencyA:\n * label: Currency A\n * unit: Unit A\n * currencyB:\n * label: Currency B\n * kind: CURRENCY_B\n * unit: Unit B\n * prefix: B\n * rate: 3.5\n */\n\n/** @public */\nexport type ConfigContextProps = {\n baseCurrency: Intl.NumberFormat;\n metrics: Metric[];\n products: Product[];\n icons: Icon[];\n engineerCost: number;\n engineerThreshold: number;\n hideTrendLine: boolean;\n currencies: Currency[];\n};\n\nexport const ConfigContext = createContext<ConfigContextProps | undefined>(\n undefined,\n);\n\nconst defaultState: ConfigContextProps = {\n baseCurrency: createCurrencyFormat(),\n metrics: [],\n products: [],\n icons: [],\n engineerCost: 0,\n engineerThreshold: EngineerThreshold,\n hideTrendLine: false,\n currencies: defaultCurrencies,\n};\n\nexport const ConfigProvider = ({ children }: PropsWithChildren<{}>) => {\n const c: BackstageConfig = useApi(configApiRef);\n const [config, setConfig] = useState(defaultState);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n function getProducts(): Product[] {\n const products = c.getOptionalConfig('costInsights.products');\n if (products) {\n return products.keys().map(key => ({\n kind: key,\n name: products.getString(`${key}.name`),\n aggregation: [0, 0],\n }));\n }\n return [];\n }\n\n function getMetrics(): Metric[] {\n const metrics = c.getOptionalConfig('costInsights.metrics');\n if (metrics) {\n return metrics.keys().map(key => ({\n kind: key,\n name: metrics.getString(`${key}.name`),\n default: metrics.getOptionalBoolean(`${key}.default`) ?? false,\n }));\n }\n\n return [];\n }\n\n function getBaseCurrency(): Intl.NumberFormat {\n const baseCurrency = c.getOptionalConfig('costInsights.baseCurrency');\n if (baseCurrency) {\n const options = baseCurrency.getOptionalConfig('options');\n return new Intl.NumberFormat(\n baseCurrency.getOptionalString('locale'),\n options\n ? {\n localeMatcher: options.getOptionalString('localeMatcher'),\n style: 'currency',\n currency: options.getOptionalString('currency'),\n currencySign: options.getOptionalString('currencySign'),\n useGrouping: options.getOptionalBoolean('useGrouping'),\n minimumIntegerDigits: options.getOptionalNumber(\n 'minimumIntegerDigits',\n ),\n minimumFractionDigits: options.getOptionalNumber(\n 'minimumFractionDigits',\n ),\n maximumFractionDigits: options.getOptionalNumber(\n 'maximumFractionDigits',\n ),\n minimumSignificantDigits: options.getOptionalNumber(\n 'minimumSignificantDigits',\n ),\n maximumSignificantDigits: options.getOptionalNumber(\n 'maximumSignificantDigits',\n ),\n }\n : undefined,\n );\n }\n\n return defaultState.baseCurrency;\n }\n\n function getCurrencies(): Currency[] {\n const currencies = c.getOptionalConfig('costInsights.currencies');\n if (currencies) {\n return currencies.keys().map(key => ({\n label: currencies.getString(`${key}.label`),\n unit: currencies.getString(`${key}.unit`),\n kind: currencies.getOptionalString(`${key}.kind`) || null,\n prefix: currencies.getOptionalString(`${key}.prefix`),\n rate: currencies.getOptionalNumber(`${key}.rate`),\n }));\n }\n\n return defaultCurrencies;\n }\n\n function getIcons(): Icon[] {\n const products = c.getOptionalConfig('costInsights.products');\n if (products) {\n return products.keys().map(k => ({\n kind: k,\n component: getIcon(products.getOptionalString(`${k}.icon`)),\n }));\n }\n return [];\n }\n\n function getEngineerCost(): number {\n return c.getNumber('costInsights.engineerCost');\n }\n\n function getEngineerThreshold(): number {\n return (\n c.getOptionalNumber('costInsights.engineerThreshold') ??\n defaultState.engineerThreshold\n );\n }\n\n function getHideTrendLine(): boolean {\n return (\n c.getOptionalBoolean('costInsights.hideTrendLine') ??\n defaultState.hideTrendLine\n );\n }\n\n function getConfig() {\n const baseCurrency = getBaseCurrency();\n const products = getProducts();\n const metrics = getMetrics();\n const engineerCost = getEngineerCost();\n const engineerThreshold = getEngineerThreshold();\n const hideTrendLine = getHideTrendLine();\n const icons = getIcons();\n const currencies = getCurrencies();\n\n validateMetrics(metrics);\n validateCurrencies(currencies);\n\n setConfig(prevState => ({\n ...prevState,\n baseCurrency,\n metrics,\n products,\n engineerCost,\n engineerThreshold,\n hideTrendLine,\n icons,\n currencies,\n }));\n\n setLoading(false);\n }\n\n getConfig();\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n if (loading) {\n return null;\n }\n\n return (\n <ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>\n );\n};\n\nexport function useConfig(): ConfigContextProps {\n const config = useContext(ConfigContext);\n return config ? config : assertNever();\n}\n\nfunction assertNever(): never {\n throw new Error('Cannot use useConfig outside of ConfigProvider');\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import React, { useState, useContext } from 'react';
2
+ import { useConfig } from './useConfig.esm.js';
3
+
4
+ const CurrencyContext = React.createContext(void 0);
5
+ const CurrencyProvider = ({ children }) => {
6
+ const config = useConfig();
7
+ const currencies = config.currencies;
8
+ const engineers = currencies.find((currency2) => currency2.kind === null);
9
+ const [currency, setCurrency] = useState(
10
+ engineers || currencies[0]
11
+ );
12
+ return /* @__PURE__ */ React.createElement(CurrencyContext.Provider, { value: { currency, setCurrency } }, children);
13
+ };
14
+ function useCurrency() {
15
+ const context = useContext(CurrencyContext);
16
+ if (!context) {
17
+ assertNever();
18
+ }
19
+ return [context.currency, context.setCurrency];
20
+ }
21
+ function assertNever() {
22
+ throw Error("Cannot use useCurrency outside of CurrencyProvider");
23
+ }
24
+
25
+ export { CurrencyContext, CurrencyProvider, useCurrency };
26
+ //# sourceMappingURL=useCurrency.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCurrency.esm.js","sources":["../../src/hooks/useCurrency.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, {\n Dispatch,\n SetStateAction,\n useState,\n useContext,\n PropsWithChildren,\n} from 'react';\nimport { Currency } from '../types';\nimport { useConfig } from './useConfig';\n\n/** @public */\nexport type CurrencyContextProps = {\n currency: Currency;\n setCurrency: Dispatch<SetStateAction<Currency>>;\n};\n\nexport const CurrencyContext = React.createContext<\n CurrencyContextProps | undefined\n>(undefined);\n\nexport const CurrencyProvider = ({ children }: PropsWithChildren<{}>) => {\n const config = useConfig();\n const currencies = config.currencies;\n const engineers = currencies.find(currency => currency.kind === null);\n const [currency, setCurrency] = useState<Currency>(\n engineers || currencies[0],\n );\n return (\n <CurrencyContext.Provider value={{ currency, setCurrency }}>\n {children}\n </CurrencyContext.Provider>\n );\n};\n\nexport function useCurrency(): [Currency, Dispatch<SetStateAction<Currency>>] {\n const context = useContext(CurrencyContext);\n\n if (!context) {\n assertNever();\n }\n\n return [context.currency, context.setCurrency];\n}\n\nfunction assertNever(): never {\n throw Error('Cannot use useCurrency outside of CurrencyProvider');\n}\n"],"names":["currency"],"mappings":";;;AA+Ba,MAAA,eAAA,GAAkB,KAAM,CAAA,aAAA,CAEnC,KAAS,CAAA,EAAA;AAEJ,MAAM,gBAAmB,GAAA,CAAC,EAAE,QAAA,EAAsC,KAAA;AACvE,EAAA,MAAM,SAAS,SAAU,EAAA,CAAA;AACzB,EAAA,MAAM,aAAa,MAAO,CAAA,UAAA,CAAA;AAC1B,EAAA,MAAM,YAAY,UAAW,CAAA,IAAA,CAAK,CAAAA,SAAYA,KAAAA,SAAAA,CAAS,SAAS,IAAI,CAAA,CAAA;AACpE,EAAM,MAAA,CAAC,QAAU,EAAA,WAAW,CAAI,GAAA,QAAA;AAAA,IAC9B,SAAA,IAAa,WAAW,CAAC,CAAA;AAAA,GAC3B,CAAA;AACA,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,gBAAgB,QAAhB,EAAA,EAAyB,OAAO,EAAE,QAAA,EAAU,WAAY,EAAA,EAAA,EACtD,QACH,CAAA,CAAA;AAEJ,EAAA;AAEO,SAAS,WAA8D,GAAA;AAC5E,EAAM,MAAA,OAAA,GAAU,WAAW,eAAe,CAAA,CAAA;AAE1C,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAY,WAAA,EAAA,CAAA;AAAA,GACd;AAEA,EAAA,OAAO,CAAC,OAAA,CAAQ,QAAU,EAAA,OAAA,CAAQ,WAAW,CAAA,CAAA;AAC/C,CAAA;AAEA,SAAS,WAAqB,GAAA;AAC5B,EAAA,MAAM,MAAM,oDAAoD,CAAA,CAAA;AAClE;;;;"}
@@ -0,0 +1,67 @@
1
+ import React, { useState, useEffect, useContext } from 'react';
2
+ import Alert from '@material-ui/lab/Alert';
3
+ import { useNavigate, useLocation } from 'react-router-dom';
4
+ import { validate, getInitialPageState, getInitialProductState, stringify } from '../utils/history.esm.js';
5
+ import { useGroups } from './useGroups.esm.js';
6
+ import { useConfig } from './useConfig.esm.js';
7
+
8
+ const FilterContext = React.createContext(void 0);
9
+ const FilterProvider = ({ children }) => {
10
+ const config = useConfig();
11
+ const navigate = useNavigate();
12
+ const location = useLocation();
13
+ const groups = useGroups();
14
+ const [error, setError] = useState(null);
15
+ const [pageFilters, setPageFilters] = useState(null);
16
+ const [productFilters, setProductFilters] = useState(null);
17
+ useEffect(() => {
18
+ async function setPageFiltersFromLocation() {
19
+ try {
20
+ const queryParams = await validate(location.search);
21
+ const defaultMetric = config.metrics.find((m) => m.default)?.kind ?? null;
22
+ const initialPageState = getInitialPageState(groups, queryParams);
23
+ const initialProductState = getInitialProductState(config);
24
+ setProductFilters(initialProductState);
25
+ setPageFilters({ ...initialPageState, metric: defaultMetric });
26
+ } catch (e) {
27
+ setError(e);
28
+ }
29
+ }
30
+ setPageFiltersFromLocation();
31
+ }, [groups]);
32
+ useEffect(() => {
33
+ function setLocationFromPageFilters(filters) {
34
+ const queryString = stringify({
35
+ group: filters.group,
36
+ ...filters.project ? { project: filters.project } : {}
37
+ });
38
+ navigate({ ...location, search: `?${queryString}` });
39
+ }
40
+ if (pageFilters) {
41
+ setLocationFromPageFilters(pageFilters);
42
+ }
43
+ }, [pageFilters]);
44
+ if (error) {
45
+ return /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, error.message);
46
+ }
47
+ if (!pageFilters || !productFilters) {
48
+ return null;
49
+ }
50
+ return /* @__PURE__ */ React.createElement(
51
+ FilterContext.Provider,
52
+ {
53
+ value: { pageFilters, productFilters, setPageFilters, setProductFilters }
54
+ },
55
+ children
56
+ );
57
+ };
58
+ function useFilters(mapFiltersToProps) {
59
+ const context = useContext(FilterContext);
60
+ return context ? mapFiltersToProps(context) : assertNever();
61
+ }
62
+ function assertNever() {
63
+ throw Error("Cannot use useFilters outside of FilterProvider");
64
+ }
65
+
66
+ export { FilterContext, FilterProvider, useFilters };
67
+ //# sourceMappingURL=useFilters.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFilters.esm.js","sources":["../../src/hooks/useFilters.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, {\n Dispatch,\n PropsWithChildren,\n SetStateAction,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport Alert from '@material-ui/lab/Alert';\nimport { PageFilters, ProductFilters } from '../types';\nimport { Maybe } from '@backstage-community/plugin-cost-insights-common';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport {\n stringify,\n validate,\n getInitialPageState,\n getInitialProductState,\n} from '../utils/history';\nimport { useGroups } from './useGroups';\nimport { useConfig } from './useConfig';\n\nexport type FilterContextProps = {\n pageFilters: PageFilters;\n productFilters: ProductFilters;\n setPageFilters: Dispatch<SetStateAction<Maybe<PageFilters>>>;\n setProductFilters: Dispatch<SetStateAction<Maybe<ProductFilters>>>;\n};\n\nexport type MapFiltersToProps<T> = (props: FilterContextProps) => T;\n\nexport const FilterContext = React.createContext<\n FilterContextProps | undefined\n>(undefined);\n\nexport const FilterProvider = ({ children }: PropsWithChildren<{}>) => {\n const config = useConfig();\n const navigate = useNavigate();\n const location = useLocation();\n const groups = useGroups();\n const [error, setError] = useState<Maybe<Error>>(null);\n const [pageFilters, setPageFilters] = useState<Maybe<PageFilters>>(null);\n const [productFilters, setProductFilters] =\n useState<Maybe<ProductFilters>>(null);\n\n useEffect(() => {\n async function setPageFiltersFromLocation() {\n try {\n // strip extraneous parameters, validate and transform\n const queryParams = await validate(location.search);\n const defaultMetric = config.metrics.find(m => m.default)?.kind ?? null;\n\n // Group or project parameters should override defaults\n const initialPageState = getInitialPageState(groups, queryParams);\n const initialProductState = getInitialProductState(config);\n\n setProductFilters(initialProductState);\n setPageFilters({ ...initialPageState, metric: defaultMetric });\n } catch (e) {\n setError(e);\n }\n }\n\n setPageFiltersFromLocation();\n }, [groups]); // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n function setLocationFromPageFilters(filters: PageFilters) {\n const queryString = stringify({\n group: filters.group,\n ...(filters.project ? { project: filters.project } : {}),\n });\n // TODO Remove workaround once issue is resolved in react-router\n // (https://github.com/ReactTraining/react-router/issues/7496)\n // navigate({ ...location, search: queryString });\n navigate({ ...location, search: `?${queryString}` });\n }\n\n if (pageFilters) {\n setLocationFromPageFilters(pageFilters);\n }\n }, [pageFilters]); // eslint-disable-line react-hooks/exhaustive-deps\n\n if (error) {\n return <Alert severity=\"error\">{error.message}</Alert>;\n }\n\n // Wait for filters to load\n if (!pageFilters || !productFilters) {\n return null;\n }\n\n return (\n <FilterContext.Provider\n value={{ pageFilters, productFilters, setPageFilters, setProductFilters }}\n >\n {children}\n </FilterContext.Provider>\n );\n};\n\nexport function useFilters<T>(mapFiltersToProps: MapFiltersToProps<T>): T {\n const context = useContext(FilterContext);\n return context ? mapFiltersToProps(context) : assertNever();\n}\n\nfunction assertNever(): never {\n throw Error('Cannot use useFilters outside of FilterProvider');\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import React, { useState, useEffect, useContext } from 'react';
2
+ import Alert from '@material-ui/lab/Alert';
3
+ import { costInsightsApiRef } from '../api/CostInsightsApi.esm.js';
4
+ import { useLoading } from './useLoading.esm.js';
5
+ import { DefaultLoadingAction } from '../utils/loading.esm.js';
6
+ import { useApi, identityApiRef } from '@backstage/core-plugin-api';
7
+ import { parseEntityRef, DEFAULT_NAMESPACE } from '@backstage/catalog-model';
8
+
9
+ const mapLoadingToProps = ({
10
+ dispatch
11
+ }) => ({
12
+ dispatchLoadingGroups: (isLoading) => dispatch({ [DefaultLoadingAction.UserGroups]: isLoading })
13
+ });
14
+ const GroupsContext = React.createContext(void 0);
15
+ const GroupsProvider = ({ children }) => {
16
+ const identityApi = useApi(identityApiRef);
17
+ const client = useApi(costInsightsApiRef);
18
+ const [error, setError] = useState(null);
19
+ const { dispatchLoadingGroups } = useLoading(mapLoadingToProps);
20
+ const [groups, setGroups] = useState(null);
21
+ useEffect(() => {
22
+ dispatchLoadingGroups(true);
23
+ async function getUserGroups() {
24
+ try {
25
+ const { userEntityRef } = await identityApi.getBackstageIdentity();
26
+ const { name: userId } = parseEntityRef(userEntityRef, {
27
+ defaultKind: "User",
28
+ defaultNamespace: DEFAULT_NAMESPACE
29
+ });
30
+ const g = await client.getUserGroups(userId);
31
+ setGroups(g);
32
+ } catch (e) {
33
+ setError(e);
34
+ } finally {
35
+ dispatchLoadingGroups(false);
36
+ }
37
+ }
38
+ getUserGroups();
39
+ }, [client]);
40
+ if (error) {
41
+ return /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, error.message);
42
+ }
43
+ if (!groups) return null;
44
+ return /* @__PURE__ */ React.createElement(GroupsContext.Provider, { value: { groups } }, children);
45
+ };
46
+ function useGroups() {
47
+ const context = useContext(GroupsContext);
48
+ return context ? context.groups : assertNever();
49
+ }
50
+ function assertNever() {
51
+ throw Error("Cannot use useGroups outside of GroupsProvider");
52
+ }
53
+
54
+ export { GroupsContext, GroupsProvider, useGroups };
55
+ //# sourceMappingURL=useGroups.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGroups.esm.js","sources":["../../src/hooks/useGroups.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, {\n PropsWithChildren,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport Alert from '@material-ui/lab/Alert';\nimport { costInsightsApiRef } from '../api';\nimport { MapLoadingToProps, useLoading } from './useLoading';\nimport { Group, Maybe } from '@backstage-community/plugin-cost-insights-common';\nimport { DefaultLoadingAction } from '../utils/loading';\nimport { useApi, identityApiRef } from '@backstage/core-plugin-api';\nimport { DEFAULT_NAMESPACE, parseEntityRef } from '@backstage/catalog-model';\n\ntype GroupsProviderLoadingProps = {\n dispatchLoadingGroups: (isLoading: boolean) => void;\n};\n\nconst mapLoadingToProps: MapLoadingToProps<GroupsProviderLoadingProps> = ({\n dispatch,\n}) => ({\n dispatchLoadingGroups: (isLoading: boolean) =>\n dispatch({ [DefaultLoadingAction.UserGroups]: isLoading }),\n});\n\nexport type GroupsContextProps = {\n groups: Group[];\n};\n\nexport const GroupsContext = React.createContext<\n GroupsContextProps | undefined\n>(undefined);\n\nexport const GroupsProvider = ({ children }: PropsWithChildren<{}>) => {\n const identityApi = useApi(identityApiRef);\n const client = useApi(costInsightsApiRef);\n const [error, setError] = useState<Maybe<Error>>(null);\n const { dispatchLoadingGroups } = useLoading(mapLoadingToProps);\n\n const [groups, setGroups] = useState<Maybe<Group[]>>(null);\n\n useEffect(() => {\n dispatchLoadingGroups(true);\n\n async function getUserGroups() {\n try {\n const { userEntityRef } = await identityApi.getBackstageIdentity();\n const { name: userId } = parseEntityRef(userEntityRef, {\n defaultKind: 'User',\n defaultNamespace: DEFAULT_NAMESPACE,\n });\n const g = await client.getUserGroups(userId);\n setGroups(g);\n } catch (e) {\n setError(e);\n } finally {\n dispatchLoadingGroups(false);\n }\n }\n\n getUserGroups();\n }, [client]); // eslint-disable-line react-hooks/exhaustive-deps\n\n if (error) {\n return <Alert severity=\"error\">{error.message}</Alert>;\n }\n\n if (!groups) return null;\n\n return (\n <GroupsContext.Provider value={{ groups: groups }}>\n {children}\n </GroupsContext.Provider>\n );\n};\n\nexport function useGroups(): Group[] {\n const context = useContext(GroupsContext);\n return context ? context.groups : assertNever();\n}\n\nfunction assertNever(): never {\n throw Error('Cannot use useGroups outside of GroupsProvider');\n}\n"],"names":[],"mappings":";;;;;;;;AAkCA,MAAM,oBAAmE,CAAC;AAAA,EACxE,QAAA;AACF,CAAO,MAAA;AAAA,EACL,qBAAA,EAAuB,CAAC,SAAA,KACtB,QAAS,CAAA,EAAE,CAAC,oBAAqB,CAAA,UAAU,GAAG,SAAA,EAAW,CAAA;AAC7D,CAAA,CAAA,CAAA;AAMa,MAAA,aAAA,GAAgB,KAAM,CAAA,aAAA,CAEjC,KAAS,CAAA,EAAA;AAEJ,MAAM,cAAiB,GAAA,CAAC,EAAE,QAAA,EAAsC,KAAA;AACrE,EAAM,MAAA,WAAA,GAAc,OAAO,cAAc,CAAA,CAAA;AACzC,EAAM,MAAA,MAAA,GAAS,OAAO,kBAAkB,CAAA,CAAA;AACxC,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAuB,IAAI,CAAA,CAAA;AACrD,EAAA,MAAM,EAAE,qBAAA,EAA0B,GAAA,UAAA,CAAW,iBAAiB,CAAA,CAAA;AAE9D,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAyB,IAAI,CAAA,CAAA;AAEzD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,qBAAA,CAAsB,IAAI,CAAA,CAAA;AAE1B,IAAA,eAAe,aAAgB,GAAA;AAC7B,MAAI,IAAA;AACF,QAAA,MAAM,EAAE,aAAA,EAAkB,GAAA,MAAM,YAAY,oBAAqB,EAAA,CAAA;AACjE,QAAA,MAAM,EAAE,IAAA,EAAM,MAAO,EAAA,GAAI,eAAe,aAAe,EAAA;AAAA,UACrD,WAAa,EAAA,MAAA;AAAA,UACb,gBAAkB,EAAA,iBAAA;AAAA,SACnB,CAAA,CAAA;AACD,QAAA,MAAM,CAAI,GAAA,MAAM,MAAO,CAAA,aAAA,CAAc,MAAM,CAAA,CAAA;AAC3C,QAAA,SAAA,CAAU,CAAC,CAAA,CAAA;AAAA,eACJ,CAAG,EAAA;AACV,QAAA,QAAA,CAAS,CAAC,CAAA,CAAA;AAAA,OACV,SAAA;AACA,QAAA,qBAAA,CAAsB,KAAK,CAAA,CAAA;AAAA,OAC7B;AAAA,KACF;AAEA,IAAc,aAAA,EAAA,CAAA;AAAA,GAChB,EAAG,CAAC,MAAM,CAAC,CAAA,CAAA;AAEX,EAAA,IAAI,KAAO,EAAA;AACT,IAAA,uBAAQ,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAM,QAAS,EAAA,OAAA,EAAA,EAAS,MAAM,OAAQ,CAAA,CAAA;AAAA,GAChD;AAEA,EAAI,IAAA,CAAC,QAAe,OAAA,IAAA,CAAA;AAEpB,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,cAAc,QAAd,EAAA,EAAuB,OAAO,EAAE,MAAA,MAC9B,QACH,CAAA,CAAA;AAEJ,EAAA;AAEO,SAAS,SAAqB,GAAA;AACnC,EAAM,MAAA,OAAA,GAAU,WAAW,aAAa,CAAA,CAAA;AACxC,EAAO,OAAA,OAAA,GAAU,OAAQ,CAAA,MAAA,GAAS,WAAY,EAAA,CAAA;AAChD,CAAA;AAEA,SAAS,WAAqB,GAAA;AAC5B,EAAA,MAAM,MAAM,gDAAgD,CAAA,CAAA;AAC9D;;;;"}
@@ -0,0 +1,65 @@
1
+ import React, { useState, useEffect, useContext } from 'react';
2
+ import * as yup from 'yup';
3
+ import Alert from '@material-ui/lab/Alert';
4
+ import { costInsightsApiRef } from '../api/CostInsightsApi.esm.js';
5
+ import { useLoading } from './useLoading.esm.js';
6
+ import { DefaultLoadingAction } from '../utils/loading.esm.js';
7
+ import { useApi } from '@backstage/core-plugin-api';
8
+
9
+ const mapLoadingToProps = ({
10
+ dispatch
11
+ }) => ({
12
+ dispatchLoadingBillingDate: (isLoading) => dispatch({ [DefaultLoadingAction.LastCompleteBillingDate]: isLoading })
13
+ });
14
+ const BillingDateContext = React.createContext(void 0);
15
+ const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
16
+ const dateFormatSchema = yup.string().matches(dateRegex, {
17
+ message: "Unsupported billing date format: ${value}. Date should be in YYYY-MM-DD format.",
18
+ excludeEmptyString: true
19
+ });
20
+ const BillingDateProvider = ({ children }) => {
21
+ const client = useApi(costInsightsApiRef);
22
+ const [error, setError] = useState(null);
23
+ const { dispatchLoadingBillingDate } = useLoading(mapLoadingToProps);
24
+ const [lastCompleteBillingDate, setLastCompeteBillingDate] = useState(null);
25
+ useEffect(() => {
26
+ dispatchLoadingBillingDate(true);
27
+ async function getLastCompleteBillingDate() {
28
+ try {
29
+ const d = await client.getLastCompleteBillingDate();
30
+ const validDate = await dateFormatSchema.validate(d);
31
+ if (validDate) setLastCompeteBillingDate(validDate);
32
+ } catch (e) {
33
+ setError(e);
34
+ } finally {
35
+ dispatchLoadingBillingDate(false);
36
+ }
37
+ }
38
+ getLastCompleteBillingDate();
39
+ }, [client]);
40
+ if (error) {
41
+ return /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, error.message);
42
+ }
43
+ if (!lastCompleteBillingDate) return null;
44
+ return /* @__PURE__ */ React.createElement(
45
+ BillingDateContext.Provider,
46
+ {
47
+ value: {
48
+ lastCompleteBillingDate
49
+ }
50
+ },
51
+ children
52
+ );
53
+ };
54
+ function useLastCompleteBillingDate() {
55
+ const context = useContext(BillingDateContext);
56
+ return context ? context.lastCompleteBillingDate : assertNever();
57
+ }
58
+ function assertNever() {
59
+ throw Error(
60
+ "Cannot use useLastCompleteBillingDate outside of BillingDateProvider"
61
+ );
62
+ }
63
+
64
+ export { BillingDateContext, BillingDateProvider, dateRegex, useLastCompleteBillingDate };
65
+ //# sourceMappingURL=useLastCompleteBillingDate.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLastCompleteBillingDate.esm.js","sources":["../../src/hooks/useLastCompleteBillingDate.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, {\n PropsWithChildren,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport * as yup from 'yup';\nimport Alert from '@material-ui/lab/Alert';\nimport { costInsightsApiRef } from '../api';\nimport { MapLoadingToProps, useLoading } from './useLoading';\nimport { DefaultLoadingAction } from '../utils/loading';\nimport { Maybe } from '@backstage-community/plugin-cost-insights-common';\nimport { useApi } from '@backstage/core-plugin-api';\n\ntype BillingDateProviderLoadingProps = {\n dispatchLoadingBillingDate: (isLoading: boolean) => void;\n};\n\nconst mapLoadingToProps: MapLoadingToProps<BillingDateProviderLoadingProps> = ({\n dispatch,\n}) => ({\n dispatchLoadingBillingDate: (isLoading: boolean) =>\n dispatch({ [DefaultLoadingAction.LastCompleteBillingDate]: isLoading }),\n});\n\nexport type BillingDateContextProps = {\n lastCompleteBillingDate: string; // YYYY-MM-DD\n};\n\nexport const BillingDateContext = React.createContext<\n BillingDateContextProps | undefined\n>(undefined);\n\nexport const dateRegex: RegExp = /^\\d{4}-\\d{2}-\\d{2}$/;\nconst dateFormatSchema = yup.string().matches(dateRegex, {\n message:\n 'Unsupported billing date format: ${value}. Date should be in YYYY-MM-DD format.',\n excludeEmptyString: true,\n});\n\nexport const BillingDateProvider = ({ children }: PropsWithChildren<{}>) => {\n const client = useApi(costInsightsApiRef);\n const [error, setError] = useState<Maybe<Error>>(null);\n const { dispatchLoadingBillingDate } = useLoading(mapLoadingToProps);\n\n const [lastCompleteBillingDate, setLastCompeteBillingDate] =\n useState<Maybe<string>>(null);\n\n useEffect(() => {\n dispatchLoadingBillingDate(true);\n\n async function getLastCompleteBillingDate() {\n try {\n const d = await client.getLastCompleteBillingDate();\n const validDate = await dateFormatSchema.validate(d);\n if (validDate) setLastCompeteBillingDate(validDate);\n } catch (e) {\n setError(e);\n } finally {\n dispatchLoadingBillingDate(false);\n }\n }\n\n getLastCompleteBillingDate();\n }, [client]); // eslint-disable-line react-hooks/exhaustive-deps\n\n if (error) {\n return <Alert severity=\"error\">{error.message}</Alert>;\n }\n\n if (!lastCompleteBillingDate) return null;\n\n return (\n <BillingDateContext.Provider\n value={\n {\n lastCompleteBillingDate: lastCompleteBillingDate,\n } as BillingDateContextProps\n }\n >\n {children}\n </BillingDateContext.Provider>\n );\n};\n\nexport function useLastCompleteBillingDate(): string {\n const context = useContext(BillingDateContext);\n return context ? context.lastCompleteBillingDate : assertNever();\n}\n\nfunction assertNever(): never {\n throw Error(\n 'Cannot use useLastCompleteBillingDate outside of BillingDateProvider',\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAkCA,MAAM,oBAAwE,CAAC;AAAA,EAC7E,QAAA;AACF,CAAO,MAAA;AAAA,EACL,0BAAA,EAA4B,CAAC,SAAA,KAC3B,QAAS,CAAA,EAAE,CAAC,oBAAqB,CAAA,uBAAuB,GAAG,SAAA,EAAW,CAAA;AAC1E,CAAA,CAAA,CAAA;AAMa,MAAA,kBAAA,GAAqB,KAAM,CAAA,aAAA,CAEtC,KAAS,CAAA,EAAA;AAEJ,MAAM,SAAoB,GAAA,sBAAA;AACjC,MAAM,gBAAmB,GAAA,GAAA,CAAI,MAAO,EAAA,CAAE,QAAQ,SAAW,EAAA;AAAA,EACvD,OACE,EAAA,iFAAA;AAAA,EACF,kBAAoB,EAAA,IAAA;AACtB,CAAC,CAAA,CAAA;AAEM,MAAM,mBAAsB,GAAA,CAAC,EAAE,QAAA,EAAsC,KAAA;AAC1E,EAAM,MAAA,MAAA,GAAS,OAAO,kBAAkB,CAAA,CAAA;AACxC,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAuB,IAAI,CAAA,CAAA;AACrD,EAAA,MAAM,EAAE,0BAAA,EAA+B,GAAA,UAAA,CAAW,iBAAiB,CAAA,CAAA;AAEnE,EAAA,MAAM,CAAC,uBAAA,EAAyB,yBAAyB,CAAA,GACvD,SAAwB,IAAI,CAAA,CAAA;AAE9B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,0BAAA,CAA2B,IAAI,CAAA,CAAA;AAE/B,IAAA,eAAe,0BAA6B,GAAA;AAC1C,MAAI,IAAA;AACF,QAAM,MAAA,CAAA,GAAI,MAAM,MAAA,CAAO,0BAA2B,EAAA,CAAA;AAClD,QAAA,MAAM,SAAY,GAAA,MAAM,gBAAiB,CAAA,QAAA,CAAS,CAAC,CAAA,CAAA;AACnD,QAAI,IAAA,SAAA,4BAAqC,SAAS,CAAA,CAAA;AAAA,eAC3C,CAAG,EAAA;AACV,QAAA,QAAA,CAAS,CAAC,CAAA,CAAA;AAAA,OACV,SAAA;AACA,QAAA,0BAAA,CAA2B,KAAK,CAAA,CAAA;AAAA,OAClC;AAAA,KACF;AAEA,IAA2B,0BAAA,EAAA,CAAA;AAAA,GAC7B,EAAG,CAAC,MAAM,CAAC,CAAA,CAAA;AAEX,EAAA,IAAI,KAAO,EAAA;AACT,IAAA,uBAAQ,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAM,QAAS,EAAA,OAAA,EAAA,EAAS,MAAM,OAAQ,CAAA,CAAA;AAAA,GAChD;AAEA,EAAI,IAAA,CAAC,yBAAgC,OAAA,IAAA,CAAA;AAErC,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,kBAAmB,CAAA,QAAA;AAAA,IAAnB;AAAA,MACC,KACE,EAAA;AAAA,QACE,uBAAA;AAAA,OACF;AAAA,KAAA;AAAA,IAGD,QAAA;AAAA,GACH,CAAA;AAEJ,EAAA;AAEO,SAAS,0BAAqC,GAAA;AACnD,EAAM,MAAA,OAAA,GAAU,WAAW,kBAAkB,CAAA,CAAA;AAC7C,EAAO,OAAA,OAAA,GAAU,OAAQ,CAAA,uBAAA,GAA0B,WAAY,EAAA,CAAA;AACjE,CAAA;AAEA,SAAS,WAAqB,GAAA;AAC5B,EAAM,MAAA,KAAA;AAAA,IACJ,sEAAA;AAAA,GACF,CAAA;AACF;;;;"}