@backstage-community/plugin-cost-insights 0.15.2 → 0.16.0

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 (150) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/alerts/ProjectGrowthAlert.esm.js +2 -2
  3. package/dist/alerts/ProjectGrowthAlert.esm.js.map +1 -1
  4. package/dist/alerts/UnlabeledDataflowAlert.esm.js +2 -2
  5. package/dist/alerts/UnlabeledDataflowAlert.esm.js.map +1 -1
  6. package/dist/components/ActionItems/ActionItemCard.esm.js +3 -3
  7. package/dist/components/ActionItems/ActionItemCard.esm.js.map +1 -1
  8. package/dist/components/ActionItems/ActionItems.esm.js +52 -41
  9. package/dist/components/ActionItems/ActionItems.esm.js.map +1 -1
  10. package/dist/components/AlertInsights/AlertDialog.esm.js +79 -58
  11. package/dist/components/AlertInsights/AlertDialog.esm.js.map +1 -1
  12. package/dist/components/AlertInsights/AlertInsights.esm.js +57 -44
  13. package/dist/components/AlertInsights/AlertInsights.esm.js.map +1 -1
  14. package/dist/components/AlertInsights/AlertInsightsHeader.esm.js +10 -2
  15. package/dist/components/AlertInsights/AlertInsightsHeader.esm.js.map +1 -1
  16. package/dist/components/AlertInsights/AlertInsightsSection.esm.js +42 -34
  17. package/dist/components/AlertInsights/AlertInsightsSection.esm.js.map +1 -1
  18. package/dist/components/AlertInsights/AlertInsightsSectionHeader.esm.js +23 -12
  19. package/dist/components/AlertInsights/AlertInsightsSectionHeader.esm.js.map +1 -1
  20. package/dist/components/AlertInsights/AlertStatusSummary.esm.js +63 -55
  21. package/dist/components/AlertInsights/AlertStatusSummary.esm.js.map +1 -1
  22. package/dist/components/AlertInsights/AlertStatusSummaryButton.esm.js +7 -6
  23. package/dist/components/AlertInsights/AlertStatusSummaryButton.esm.js.map +1 -1
  24. package/dist/components/AlertInstructionsLayout/AlertInstructionsLayout.esm.js +23 -17
  25. package/dist/components/AlertInstructionsLayout/AlertInstructionsLayout.esm.js.map +1 -1
  26. package/dist/components/BarChart/BarChart.esm.js +83 -78
  27. package/dist/components/BarChart/BarChart.esm.js.map +1 -1
  28. package/dist/components/BarChart/BarChartLabel.esm.js +8 -5
  29. package/dist/components/BarChart/BarChartLabel.esm.js.map +1 -1
  30. package/dist/components/BarChart/BarChartLegend.esm.js +20 -16
  31. package/dist/components/BarChart/BarChartLegend.esm.js.map +1 -1
  32. package/dist/components/BarChart/BarChartStepper.esm.js +51 -48
  33. package/dist/components/BarChart/BarChartStepper.esm.js.map +1 -1
  34. package/dist/components/BarChart/BarChartStepperButton.esm.js +6 -5
  35. package/dist/components/BarChart/BarChartStepperButton.esm.js.map +1 -1
  36. package/dist/components/BarChart/BarChartSteps.esm.js +3 -3
  37. package/dist/components/BarChart/BarChartSteps.esm.js.map +1 -1
  38. package/dist/components/BarChart/BarChartTick.esm.js +5 -5
  39. package/dist/components/BarChart/BarChartTick.esm.js.map +1 -1
  40. package/dist/components/BarChart/BarChartTooltip.esm.js +27 -14
  41. package/dist/components/BarChart/BarChartTooltip.esm.js.map +1 -1
  42. package/dist/components/BarChart/BarChartTooltipItem.esm.js +11 -6
  43. package/dist/components/BarChart/BarChartTooltipItem.esm.js.map +1 -1
  44. package/dist/components/CopyUrlToClipboard/CopyUrlToClipboard.esm.js +3 -2
  45. package/dist/components/CopyUrlToClipboard/CopyUrlToClipboard.esm.js.map +1 -1
  46. package/dist/components/CostGrowth/CostGrowth.esm.js +26 -7
  47. package/dist/components/CostGrowth/CostGrowth.esm.js.map +1 -1
  48. package/dist/components/CostGrowth/CostGrowthIndicator.esm.js +6 -2
  49. package/dist/components/CostGrowth/CostGrowthIndicator.esm.js.map +1 -1
  50. package/dist/components/CostInsightsHeader/CostInsightsHeader.esm.js +77 -8
  51. package/dist/components/CostInsightsHeader/CostInsightsHeader.esm.js.map +1 -1
  52. package/dist/components/CostInsightsLayout/CostInsightsLayout.esm.js +16 -10
  53. package/dist/components/CostInsightsLayout/CostInsightsLayout.esm.js.map +1 -1
  54. package/dist/components/CostInsightsNavigation/CostInsightsNavigation.esm.js +41 -35
  55. package/dist/components/CostInsightsNavigation/CostInsightsNavigation.esm.js.map +1 -1
  56. package/dist/components/CostInsightsPage/CostInsightsPage.esm.js +116 -79
  57. package/dist/components/CostInsightsPage/CostInsightsPage.esm.js.map +1 -1
  58. package/dist/components/CostInsightsPage/CostInsightsPageRoot.esm.js +2 -2
  59. package/dist/components/CostInsightsPage/CostInsightsPageRoot.esm.js.map +1 -1
  60. package/dist/components/CostInsightsPage/CostInsightsThemeProvider.esm.js +5 -5
  61. package/dist/components/CostInsightsPage/CostInsightsThemeProvider.esm.js.map +1 -1
  62. package/dist/components/CostInsightsTabs/CostInsightsTabs.esm.js +58 -51
  63. package/dist/components/CostInsightsTabs/CostInsightsTabs.esm.js.map +1 -1
  64. package/dist/components/CostOverviewCard/CostOverviewBreakdownChart.esm.js +74 -59
  65. package/dist/components/CostOverviewCard/CostOverviewBreakdownChart.esm.js.map +1 -1
  66. package/dist/components/CostOverviewCard/CostOverviewCard.esm.js +45 -35
  67. package/dist/components/CostOverviewCard/CostOverviewCard.esm.js.map +1 -1
  68. package/dist/components/CostOverviewCard/CostOverviewChart.esm.js +86 -73
  69. package/dist/components/CostOverviewCard/CostOverviewChart.esm.js.map +1 -1
  70. package/dist/components/CostOverviewCard/CostOverviewHeader.esm.js +11 -6
  71. package/dist/components/CostOverviewCard/CostOverviewHeader.esm.js.map +1 -1
  72. package/dist/components/CostOverviewCard/CostOverviewLegend.esm.js +21 -15
  73. package/dist/components/CostOverviewCard/CostOverviewLegend.esm.js.map +1 -1
  74. package/dist/components/CurrencySelect/CurrencySelect.esm.js +24 -21
  75. package/dist/components/CurrencySelect/CurrencySelect.esm.js.map +1 -1
  76. package/dist/components/EntityCosts/EntityCosts.esm.js +8 -7
  77. package/dist/components/EntityCosts/EntityCosts.esm.js.map +1 -1
  78. package/dist/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.esm.js +65 -20
  79. package/dist/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.esm.js.map +1 -1
  80. package/dist/components/LegendItem/LegendItem.esm.js +34 -29
  81. package/dist/components/LegendItem/LegendItem.esm.js.map +1 -1
  82. package/dist/components/MetricSelect/MetricSelect.esm.js +19 -14
  83. package/dist/components/MetricSelect/MetricSelect.esm.js.map +1 -1
  84. package/dist/components/PeriodSelect/PeriodSelect.esm.js +15 -15
  85. package/dist/components/PeriodSelect/PeriodSelect.esm.js.map +1 -1
  86. package/dist/components/ProductInsights/ProductInsights.esm.js +12 -8
  87. package/dist/components/ProductInsights/ProductInsights.esm.js.map +1 -1
  88. package/dist/components/ProductInsightsCard/ProductEntityDialog.esm.js +20 -15
  89. package/dist/components/ProductInsightsCard/ProductEntityDialog.esm.js.map +1 -1
  90. package/dist/components/ProductInsightsCard/ProductEntityTable.esm.js +9 -9
  91. package/dist/components/ProductInsightsCard/ProductEntityTable.esm.js.map +1 -1
  92. package/dist/components/ProductInsightsCard/ProductInsightsCard.esm.js +25 -15
  93. package/dist/components/ProductInsightsCard/ProductInsightsCard.esm.js.map +1 -1
  94. package/dist/components/ProductInsightsCard/ProductInsightsCardList.esm.js +14 -14
  95. package/dist/components/ProductInsightsCard/ProductInsightsCardList.esm.js.map +1 -1
  96. package/dist/components/ProductInsightsCard/ProductInsightsChart.esm.js +43 -35
  97. package/dist/components/ProductInsightsCard/ProductInsightsChart.esm.js.map +1 -1
  98. package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertCard.esm.js +5 -5
  99. package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertCard.esm.js.map +1 -1
  100. package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertChart.esm.js +5 -2
  101. package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertChart.esm.js.map +1 -1
  102. package/dist/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.esm.js +55 -9
  103. package/dist/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.esm.js.map +1 -1
  104. package/dist/components/ProjectSelect/ProjectSelect.esm.js +15 -15
  105. package/dist/components/ProjectSelect/ProjectSelect.esm.js.map +1 -1
  106. package/dist/components/UnlabeledDataflowAlertCard/UnlabeledDataflowAlertCard.esm.js +12 -9
  107. package/dist/components/UnlabeledDataflowAlertCard/UnlabeledDataflowAlertCard.esm.js.map +1 -1
  108. package/dist/components/WhyCostsMatter/WhyCostsMatter.esm.js +40 -10
  109. package/dist/components/WhyCostsMatter/WhyCostsMatter.esm.js.map +1 -1
  110. package/dist/example/alerts/KubernetesMigrationAlert.esm.js +10 -3
  111. package/dist/example/alerts/KubernetesMigrationAlert.esm.js.map +1 -1
  112. package/dist/example/client.esm.js +1 -1
  113. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationAlertCard.esm.js +20 -17
  114. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationAlertCard.esm.js.map +1 -1
  115. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChart.esm.js +3 -2
  116. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChart.esm.js.map +1 -1
  117. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChartLegend.esm.js +14 -9
  118. package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChartLegend.esm.js.map +1 -1
  119. package/dist/example/forms/KubernetesMigrationDismissForm.esm.js +21 -17
  120. package/dist/example/forms/KubernetesMigrationDismissForm.esm.js.map +1 -1
  121. package/dist/forms/AlertAcceptForm.esm.js +5 -4
  122. package/dist/forms/AlertAcceptForm.esm.js.map +1 -1
  123. package/dist/forms/AlertDismissForm.esm.js +47 -38
  124. package/dist/forms/AlertDismissForm.esm.js.map +1 -1
  125. package/dist/forms/AlertSnoozeForm.esm.js +20 -16
  126. package/dist/forms/AlertSnoozeForm.esm.js.map +1 -1
  127. package/dist/hooks/useConfig.esm.js +3 -2
  128. package/dist/hooks/useConfig.esm.js.map +1 -1
  129. package/dist/hooks/useCurrency.esm.js +6 -3
  130. package/dist/hooks/useCurrency.esm.js.map +1 -1
  131. package/dist/hooks/useFilters.esm.js +10 -7
  132. package/dist/hooks/useFilters.esm.js.map +1 -1
  133. package/dist/hooks/useGroups.esm.js +7 -4
  134. package/dist/hooks/useGroups.esm.js.map +1 -1
  135. package/dist/hooks/useLastCompleteBillingDate.esm.js +8 -7
  136. package/dist/hooks/useLastCompleteBillingDate.esm.js.map +1 -1
  137. package/dist/hooks/useLoading.esm.js +6 -2
  138. package/dist/hooks/useLoading.esm.js.map +1 -1
  139. package/dist/hooks/useScroll.esm.js +6 -3
  140. package/dist/hooks/useScroll.esm.js.map +1 -1
  141. package/dist/index.d.ts +17 -17
  142. package/dist/index.esm.js +2 -1
  143. package/dist/index.esm.js.map +1 -1
  144. package/dist/testUtils/providers.esm.js +3 -3
  145. package/dist/testUtils/providers.esm.js.map +1 -1
  146. package/dist/utils/navigation.esm.js +10 -10
  147. package/dist/utils/navigation.esm.js.map +1 -1
  148. package/dist/utils/scroll.esm.js +3 -2
  149. package/dist/utils/scroll.esm.js.map +1 -1
  150. package/package.json +18 -11
@@ -1,4 +1,5 @@
1
- import React, { useState } from 'react';
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { useState } from 'react';
2
3
  import Menu from '@material-ui/core/Menu';
3
4
  import MenuItem from '@material-ui/core/MenuItem';
4
5
  import Tab from '@material-ui/core/Tab';
@@ -28,61 +29,67 @@ const CostInsightsTabs = ({ groups }) => {
28
29
  closeGroupMenu();
29
30
  setGroup(g);
30
31
  };
31
- const renderTabLabel = () => /* @__PURE__ */ React.createElement("div", { className: classes.tabLabel }, /* @__PURE__ */ React.createElement(Typography, { className: classes.tabLabelText, variant: "overline" }, `${groups.length} teams`), /* @__PURE__ */ React.createElement(ExpandMoreIcon, { fontSize: "small" }));
32
+ const renderTabLabel = () => /* @__PURE__ */ jsxs("div", { className: classes.tabLabel, children: [
33
+ /* @__PURE__ */ jsx(Typography, { className: classes.tabLabelText, variant: "overline", children: `${groups.length} teams` }),
34
+ /* @__PURE__ */ jsx(ExpandMoreIcon, { fontSize: "small" })
35
+ ] });
32
36
  const hasAtLeastTwoGroups = groups.length >= 2;
33
37
  if (!hasAtLeastTwoGroups) return null;
34
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
35
- Tabs,
36
- {
37
- className: `cost-insights-tabs ${classes.tabs}`,
38
- "data-testid": "cost-insights-tabs",
39
- classes: { indicator: classes.indicator },
40
- value: index
41
- },
42
- /* @__PURE__ */ React.createElement(
43
- Tab,
38
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
39
+ /* @__PURE__ */ jsx(
40
+ Tabs,
44
41
  {
45
- className: classes.tab,
46
- "data-testid": "cost-insights-groups-tab",
47
- key: "cost-insights-groups-tab",
48
- label: renderTabLabel(),
49
- onClick: openGroupMenu,
50
- component: "button"
42
+ className: `cost-insights-tabs ${classes.tabs}`,
43
+ "data-testid": "cost-insights-tabs",
44
+ classes: { indicator: classes.indicator },
45
+ value: index,
46
+ children: /* @__PURE__ */ jsx(
47
+ Tab,
48
+ {
49
+ className: classes.tab,
50
+ "data-testid": "cost-insights-groups-tab",
51
+ label: renderTabLabel(),
52
+ onClick: openGroupMenu,
53
+ component: "button"
54
+ },
55
+ "cost-insights-groups-tab"
56
+ )
51
57
  }
52
- )
53
- ), /* @__PURE__ */ React.createElement(
54
- Menu,
55
- {
56
- id: "group-menu",
57
- "data-testid": "group-menu",
58
- className: classes.menu,
59
- getContentAnchorEl: null,
60
- anchorEl: groupMenuEl,
61
- keepMounted: true,
62
- open: Boolean(groupMenuEl),
63
- onClose: closeGroupMenu,
64
- anchorOrigin: {
65
- vertical: "bottom",
66
- horizontal: "left"
67
- },
68
- transformOrigin: {
69
- vertical: "top",
70
- horizontal: "left"
71
- }
72
- },
73
- groups.map((g) => /* @__PURE__ */ React.createElement(
74
- MenuItem,
58
+ ),
59
+ /* @__PURE__ */ jsx(
60
+ Menu,
75
61
  {
76
- className: classes.menuItem,
77
- classes: { selected: classes.menuItemSelected },
78
- selected: g.id === group,
79
- key: g.id,
80
- "data-testid": g.id,
81
- onClick: updateGroupFilterAndCloseMenu(g)
82
- },
83
- g.name ?? g.id
84
- ))
85
- ));
62
+ id: "group-menu",
63
+ "data-testid": "group-menu",
64
+ className: classes.menu,
65
+ getContentAnchorEl: null,
66
+ anchorEl: groupMenuEl,
67
+ keepMounted: true,
68
+ open: Boolean(groupMenuEl),
69
+ onClose: closeGroupMenu,
70
+ anchorOrigin: {
71
+ vertical: "bottom",
72
+ horizontal: "left"
73
+ },
74
+ transformOrigin: {
75
+ vertical: "top",
76
+ horizontal: "left"
77
+ },
78
+ children: groups.map((g) => /* @__PURE__ */ jsx(
79
+ MenuItem,
80
+ {
81
+ className: classes.menuItem,
82
+ classes: { selected: classes.menuItemSelected },
83
+ selected: g.id === group,
84
+ "data-testid": g.id,
85
+ onClick: updateGroupFilterAndCloseMenu(g),
86
+ children: g.name ?? g.id
87
+ },
88
+ g.id
89
+ ))
90
+ }
91
+ )
92
+ ] });
86
93
  };
87
94
 
88
95
  export { CostInsightsTabs };
@@ -1 +1 @@
1
- {"version":3,"file":"CostInsightsTabs.esm.js","sources":["../../../src/components/CostInsightsTabs/CostInsightsTabs.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, { useState } from 'react';\nimport Menu from '@material-ui/core/Menu';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Tab from '@material-ui/core/Tab';\nimport Tabs from '@material-ui/core/Tabs';\nimport Typography from '@material-ui/core/Typography';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport { mapLoadingToProps, mapFiltersToProps } from './selector';\nimport { Group } from '@backstage-community/plugin-cost-insights-common';\nimport { useFilters, useLoading } from '../../hooks';\nimport { useCostInsightsTabsStyles as useStyles } from '../../utils/styles';\n\nexport type CostInsightsTabsProps = {\n groups: Group[];\n};\n\nexport const CostInsightsTabs = ({ groups }: CostInsightsTabsProps) => {\n const classes = useStyles();\n const [index] = useState(0); // index is fixed for now until other tabs are added\n const [groupMenuEl, setGroupMenuEl] = useState<Element | null>(null);\n const { group, setGroup } = useFilters(mapFiltersToProps);\n const { loadingActions, dispatchReset } = useLoading(mapLoadingToProps);\n\n const openGroupMenu = (e: any) => setGroupMenuEl(e.currentTarget as Element);\n\n const closeGroupMenu = () => setGroupMenuEl(null);\n\n const updateGroupFilterAndCloseMenu = (g: Group) => () => {\n dispatchReset(loadingActions);\n closeGroupMenu();\n setGroup(g);\n };\n\n const renderTabLabel = () => (\n <div className={classes.tabLabel}>\n <Typography className={classes.tabLabelText} variant=\"overline\">\n {`${groups.length} teams`}\n </Typography>\n <ExpandMoreIcon fontSize=\"small\" />\n </div>\n );\n\n const hasAtLeastTwoGroups = groups.length >= 2;\n\n if (!hasAtLeastTwoGroups) return null;\n\n return (\n <>\n <Tabs\n className={`cost-insights-tabs ${classes.tabs}`}\n data-testid=\"cost-insights-tabs\"\n classes={{ indicator: classes.indicator }}\n value={index}\n >\n <Tab\n className={classes.tab}\n data-testid=\"cost-insights-groups-tab\"\n key=\"cost-insights-groups-tab\"\n label={renderTabLabel()}\n onClick={openGroupMenu}\n component=\"button\"\n />\n </Tabs>\n <Menu\n id=\"group-menu\"\n data-testid=\"group-menu\"\n className={classes.menu}\n getContentAnchorEl={null}\n anchorEl={groupMenuEl}\n keepMounted\n open={Boolean(groupMenuEl)}\n onClose={closeGroupMenu}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'left',\n }}\n transformOrigin={{\n vertical: 'top',\n horizontal: 'left',\n }}\n >\n {groups.map((g: Group) => (\n <MenuItem\n className={classes.menuItem}\n classes={{ selected: classes.menuItemSelected }}\n selected={g.id === group}\n key={g.id}\n data-testid={g.id}\n onClick={updateGroupFilterAndCloseMenu(g)}\n >\n {g.name ?? g.id}\n </MenuItem>\n ))}\n </Menu>\n </>\n );\n};\n"],"names":["useStyles"],"mappings":"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"}
1
+ {"version":3,"file":"CostInsightsTabs.esm.js","sources":["../../../src/components/CostInsightsTabs/CostInsightsTabs.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 { useState } from 'react';\nimport Menu from '@material-ui/core/Menu';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Tab from '@material-ui/core/Tab';\nimport Tabs from '@material-ui/core/Tabs';\nimport Typography from '@material-ui/core/Typography';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport { mapLoadingToProps, mapFiltersToProps } from './selector';\nimport { Group } from '@backstage-community/plugin-cost-insights-common';\nimport { useFilters, useLoading } from '../../hooks';\nimport { useCostInsightsTabsStyles as useStyles } from '../../utils/styles';\n\nexport type CostInsightsTabsProps = {\n groups: Group[];\n};\n\nexport const CostInsightsTabs = ({ groups }: CostInsightsTabsProps) => {\n const classes = useStyles();\n const [index] = useState(0); // index is fixed for now until other tabs are added\n const [groupMenuEl, setGroupMenuEl] = useState<Element | null>(null);\n const { group, setGroup } = useFilters(mapFiltersToProps);\n const { loadingActions, dispatchReset } = useLoading(mapLoadingToProps);\n\n const openGroupMenu = (e: any) => setGroupMenuEl(e.currentTarget as Element);\n\n const closeGroupMenu = () => setGroupMenuEl(null);\n\n const updateGroupFilterAndCloseMenu = (g: Group) => () => {\n dispatchReset(loadingActions);\n closeGroupMenu();\n setGroup(g);\n };\n\n const renderTabLabel = () => (\n <div className={classes.tabLabel}>\n <Typography className={classes.tabLabelText} variant=\"overline\">\n {`${groups.length} teams`}\n </Typography>\n <ExpandMoreIcon fontSize=\"small\" />\n </div>\n );\n\n const hasAtLeastTwoGroups = groups.length >= 2;\n\n if (!hasAtLeastTwoGroups) return null;\n\n return (\n <>\n <Tabs\n className={`cost-insights-tabs ${classes.tabs}`}\n data-testid=\"cost-insights-tabs\"\n classes={{ indicator: classes.indicator }}\n value={index}\n >\n <Tab\n className={classes.tab}\n data-testid=\"cost-insights-groups-tab\"\n key=\"cost-insights-groups-tab\"\n label={renderTabLabel()}\n onClick={openGroupMenu}\n component=\"button\"\n />\n </Tabs>\n <Menu\n id=\"group-menu\"\n data-testid=\"group-menu\"\n className={classes.menu}\n getContentAnchorEl={null}\n anchorEl={groupMenuEl}\n keepMounted\n open={Boolean(groupMenuEl)}\n onClose={closeGroupMenu}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'left',\n }}\n transformOrigin={{\n vertical: 'top',\n horizontal: 'left',\n }}\n >\n {groups.map((g: Group) => (\n <MenuItem\n className={classes.menuItem}\n classes={{ selected: classes.menuItemSelected }}\n selected={g.id === group}\n key={g.id}\n data-testid={g.id}\n onClick={updateGroupFilterAndCloseMenu(g)}\n >\n {g.name ?? g.id}\n </MenuItem>\n ))}\n </Menu>\n </>\n );\n};\n"],"names":["useStyles"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
- import React, { useState } from 'react';
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState } from 'react';
2
3
  import { DateTime } from 'luxon';
3
4
  import Box from '@material-ui/core/Box';
4
5
  import Divider from '@material-ui/core/Divider';
@@ -99,10 +100,9 @@ const CostOverviewBreakdownChart = ({
99
100
  const breakdownsToDisplay = isExpanded ? sortedBreakdowns.map((breakdown) => breakdown.id) : ["Other", ...separatedBreakdowns];
100
101
  return breakdownsToDisplay.map((breakdown, i) => {
101
102
  const color = theme.palette.dataViz[(breakdownsToDisplay.length - 1 - i) % (theme.palette.dataViz.length - 1)];
102
- return /* @__PURE__ */ React.createElement(
103
+ return /* @__PURE__ */ jsx(
103
104
  Area,
104
105
  {
105
- key: breakdown,
106
106
  dataKey: breakdown,
107
107
  isAnimationActive: false,
108
108
  stackId: "1",
@@ -112,7 +112,8 @@ const CostOverviewBreakdownChart = ({
112
112
  style: {
113
113
  cursor: breakdown === "Other" && !isExpanded ? "pointer" : void 0
114
114
  }
115
- }
115
+ },
116
+ breakdown
116
117
  );
117
118
  });
118
119
  };
@@ -126,70 +127,84 @@ const CostOverviewBreakdownChart = ({
126
127
  value: formatGraphValueWith(Number(p.value), i),
127
128
  fill: p.color
128
129
  }));
129
- const expandText = /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
130
- Divider,
131
- {
132
- style: {
133
- backgroundColor: emphasize(theme.palette.divider, 1),
134
- margin: "10px 0"
130
+ const expandText = /* @__PURE__ */ jsxs(Box, { children: [
131
+ /* @__PURE__ */ jsx(
132
+ Divider,
133
+ {
134
+ style: {
135
+ backgroundColor: emphasize(theme.palette.divider, 1),
136
+ margin: "10px 0"
137
+ }
135
138
  }
136
- }
137
- ), /* @__PURE__ */ React.createElement(Box, { display: "flex", justifyContent: "space-between", alignItems: "center" }, /* @__PURE__ */ React.createElement(FullScreenIcon, null), /* @__PURE__ */ React.createElement(Typography, null, "Click to expand")));
138
- return /* @__PURE__ */ React.createElement(BarChartTooltip, { title: dateTitle }, items.reverse().map((item, index) => /* @__PURE__ */ React.createElement(BarChartTooltipItem, { key: `${item.label}-${index}`, item })), canExpand && !isExpanded ? expandText : null);
139
+ ),
140
+ /* @__PURE__ */ jsxs(Box, { display: "flex", justifyContent: "space-between", alignItems: "center", children: [
141
+ /* @__PURE__ */ jsx(FullScreenIcon, {}),
142
+ /* @__PURE__ */ jsx(Typography, { children: "Click to expand" })
143
+ ] })
144
+ ] });
145
+ return /* @__PURE__ */ jsxs(BarChartTooltip, { title: dateTitle, children: [
146
+ items.reverse().map((item, index) => /* @__PURE__ */ jsx(BarChartTooltipItem, { item }, `${item.label}-${index}`)),
147
+ canExpand && !isExpanded ? expandText : null
148
+ ] });
139
149
  };
140
150
  const options = {
141
151
  previousName: formatPeriod(duration, lastCompleteBillingDate, false),
142
152
  currentName: formatPeriod(duration, lastCompleteBillingDate, true),
143
153
  hideMarker: true
144
154
  };
145
- return /* @__PURE__ */ React.createElement(Box, { display: "flex", flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { display: "flex", flexDirection: "row" }, /* @__PURE__ */ React.createElement(
146
- BarChartLegend,
147
- {
148
- costStart: previousPeriodTotal,
149
- costEnd: currentPeriodTotal,
150
- options
151
- }
152
- )), /* @__PURE__ */ React.createElement(
153
- ResponsiveContainer,
154
- {
155
- width: responsive ? "100%" : classes.container.width,
156
- height: classes.container.height
157
- },
158
- /* @__PURE__ */ React.createElement(
159
- AreaChart,
155
+ return /* @__PURE__ */ jsxs(Box, { display: "flex", flexDirection: "column", children: [
156
+ /* @__PURE__ */ jsx(Box, { display: "flex", flexDirection: "row", children: /* @__PURE__ */ jsx(
157
+ BarChartLegend,
160
158
  {
161
- data: chartData,
162
- margin: {
163
- top: 16,
164
- right: 30,
165
- bottom: 40
166
- }
167
- },
168
- /* @__PURE__ */ React.createElement(CartesianGrid, { stroke: classes.cartesianGrid.stroke }),
169
- /* @__PURE__ */ React.createElement(
170
- XAxis,
171
- {
172
- dataKey: "date",
173
- domain: ["dataMin", "dataMax"],
174
- tickFormatter: overviewGraphTickFormatter,
175
- tickCount: 6,
176
- type: "number",
177
- stroke: classes.axis.fill
178
- }
179
- ),
180
- /* @__PURE__ */ React.createElement(
181
- YAxis,
182
- {
183
- domain: [() => 0, "dataMax"],
184
- tick: { fill: classes.axis.fill },
185
- tickFormatter: formatGraphValue(baseCurrency),
186
- width: classes.yAxis.width
187
- }
188
- ),
189
- renderAreas(),
190
- /* @__PURE__ */ React.createElement(Tooltip, { content: tooltipRenderer, animationDuration: 100 })
159
+ costStart: previousPeriodTotal,
160
+ costEnd: currentPeriodTotal,
161
+ options
162
+ }
163
+ ) }),
164
+ /* @__PURE__ */ jsx(
165
+ ResponsiveContainer,
166
+ {
167
+ width: responsive ? "100%" : classes.container.width,
168
+ height: classes.container.height,
169
+ children: /* @__PURE__ */ jsxs(
170
+ AreaChart,
171
+ {
172
+ data: chartData,
173
+ margin: {
174
+ top: 16,
175
+ right: 30,
176
+ bottom: 40
177
+ },
178
+ children: [
179
+ /* @__PURE__ */ jsx(CartesianGrid, { stroke: classes.cartesianGrid.stroke }),
180
+ /* @__PURE__ */ jsx(
181
+ XAxis,
182
+ {
183
+ dataKey: "date",
184
+ domain: ["dataMin", "dataMax"],
185
+ tickFormatter: overviewGraphTickFormatter,
186
+ tickCount: 6,
187
+ type: "number",
188
+ stroke: classes.axis.fill
189
+ }
190
+ ),
191
+ /* @__PURE__ */ jsx(
192
+ YAxis,
193
+ {
194
+ domain: [() => 0, "dataMax"],
195
+ tick: { fill: classes.axis.fill },
196
+ tickFormatter: formatGraphValue(baseCurrency),
197
+ width: classes.yAxis.width
198
+ }
199
+ ),
200
+ renderAreas(),
201
+ /* @__PURE__ */ jsx(Tooltip, { content: tooltipRenderer, animationDuration: 100 })
202
+ ]
203
+ }
204
+ )
205
+ }
191
206
  )
192
- ));
207
+ ] });
193
208
  };
194
209
 
195
210
  export { CostOverviewBreakdownChart };
@@ -1 +1 @@
1
- {"version":3,"file":"CostOverviewBreakdownChart.esm.js","sources":["../../../src/components/CostOverviewCard/CostOverviewBreakdownChart.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, { useState } from 'react';\nimport { DateTime } from 'luxon';\nimport Box from '@material-ui/core/Box';\nimport Divider from '@material-ui/core/Divider';\nimport { emphasize } from '@material-ui/core/styles/colorManipulator';\nimport Typography from '@material-ui/core/Typography';\nimport { useTheme } from '@material-ui/core/styles';\nimport { default as FullScreenIcon } from '@material-ui/icons/Fullscreen';\nimport {\n Area,\n AreaChart,\n CartesianGrid,\n ResponsiveContainer,\n Tooltip as RechartsTooltip,\n XAxis,\n YAxis,\n} from 'recharts';\nimport { DEFAULT_DATE_FORMAT, CostInsightsTheme } from '../../types';\nimport { Cost } from '@backstage-community/plugin-cost-insights-common';\nimport {\n BarChartLegend,\n BarChartTooltip as Tooltip,\n BarChartTooltipItem as TooltipItem,\n} from '../BarChart';\nimport {\n formatGraphValue,\n isInvalid,\n overviewGraphTickFormatter,\n} from '../../utils/graphs';\nimport { useCostOverviewStyles as useStyles } from '../../utils/styles';\nimport { useConfig, useFilters, useLastCompleteBillingDate } from '../../hooks';\nimport { mapFiltersToProps } from './selector';\nimport { getPreviousPeriodTotalCost } from '../../utils/change';\nimport { formatPeriod } from '../../utils/formatters';\nimport { aggregationSum } from '../../utils/sum';\nimport { BarChartLegendOptions } from '../BarChart';\nimport { TooltipRenderer } from '../../types';\n\nexport type CostOverviewBreakdownChartProps = {\n costBreakdown: Cost[];\n responsive?: boolean;\n};\n\nconst LOW_COST_THRESHOLD = 0.1;\n\nexport const CostOverviewBreakdownChart = ({\n costBreakdown,\n responsive = true,\n}: CostOverviewBreakdownChartProps) => {\n const theme = useTheme<CostInsightsTheme>();\n const classes = useStyles(theme);\n const { baseCurrency } = useConfig();\n const lastCompleteBillingDate = useLastCompleteBillingDate();\n const { duration } = useFilters(mapFiltersToProps);\n const [isExpanded, setExpanded] = useState(false);\n\n if (!costBreakdown) {\n return null;\n }\n\n const flattenedAggregation = costBreakdown\n .map(cost => cost.aggregation)\n .flat();\n\n const totalCost = aggregationSum(flattenedAggregation);\n\n const previousPeriodTotal = getPreviousPeriodTotalCost(\n flattenedAggregation,\n duration,\n lastCompleteBillingDate,\n );\n const currentPeriodTotal = totalCost - previousPeriodTotal;\n const canExpand = costBreakdown.length >= 8;\n const otherCategoryIds: string[] = [];\n\n const breakdownsByDate = costBreakdown.reduce(\n (breakdownByDate, breakdown) => {\n const breakdownTotal = aggregationSum(breakdown.aggregation);\n // Group breakdown items with less than 10% of the total cost into \"Other\" category if needed\n const isOtherCategory =\n canExpand && breakdownTotal < totalCost * LOW_COST_THRESHOLD;\n\n const updatedBreakdownByDate = { ...breakdownByDate };\n if (isOtherCategory) {\n otherCategoryIds.push(breakdown.id);\n }\n breakdown.aggregation.forEach(curAggregation => {\n const costsForDate = updatedBreakdownByDate[curAggregation.date] || {};\n\n updatedBreakdownByDate[curAggregation.date] = {\n ...costsForDate,\n [breakdown.id]:\n (costsForDate[breakdown.id] || 0) + curAggregation.amount,\n };\n });\n\n return updatedBreakdownByDate;\n },\n {} as Record<string, Record<string, number>>,\n );\n\n const chartData: Record<string, number>[] = Object.keys(breakdownsByDate)\n .map(date => {\n const costsForDate = Object.keys(breakdownsByDate[date]).reduce(\n (dateCosts, breakdown) => {\n // Group costs for items that belong to 'Other' in the chart.\n const cost = breakdownsByDate[date][breakdown];\n const breakdownCost =\n !isExpanded && otherCategoryIds.includes(breakdown)\n ? { Other: (dateCosts.Other || 0) + cost }\n : { [breakdown]: cost };\n return { ...dateCosts, ...breakdownCost };\n },\n {} as Record<string, number>,\n );\n return {\n ...costsForDate,\n date: Date.parse(date),\n };\n })\n .sort((a, b) => a.date - b.date);\n\n const sortedBreakdowns = costBreakdown.sort(\n (a, b) => aggregationSum(a.aggregation) - aggregationSum(b.aggregation),\n );\n\n const renderAreas = () => {\n const separatedBreakdowns = sortedBreakdowns\n // Check that the breakdown is a separate group and hasn't been added to 'Other'\n .filter(\n breakdown =>\n breakdown.id !== 'Other' && !otherCategoryIds.includes(breakdown.id),\n )\n .map(breakdown => breakdown.id);\n // Keep 'Other' category at the bottom of the stack\n const breakdownsToDisplay = isExpanded\n ? sortedBreakdowns.map(breakdown => breakdown.id)\n : ['Other', ...separatedBreakdowns];\n\n return breakdownsToDisplay.map((breakdown, i) => {\n // Logic to handle case where there are more items than data viz colors.\n const color =\n theme.palette.dataViz[\n (breakdownsToDisplay.length - 1 - i) %\n (theme.palette.dataViz.length - 1)\n ];\n return (\n <Area\n key={breakdown}\n dataKey={breakdown}\n isAnimationActive={false}\n stackId=\"1\"\n stroke={color}\n fill={color}\n onClick={() => setExpanded(true)}\n style={{\n cursor:\n breakdown === 'Other' && !isExpanded ? 'pointer' : undefined,\n }}\n />\n );\n });\n };\n\n const tooltipRenderer: TooltipRenderer = ({ label, payload = [] }) => {\n if (isInvalid({ label, payload })) return null;\n\n const date =\n typeof label === 'number'\n ? DateTime.fromMillis(label)\n : DateTime.fromISO(label!);\n const dateTitle = date.toUTC().toFormat(DEFAULT_DATE_FORMAT);\n const formatGraphValueWith = formatGraphValue(baseCurrency);\n const items = payload.map((p, i) => ({\n label: p.dataKey as string,\n value: formatGraphValueWith(Number(p.value), i),\n fill: p.color!,\n }));\n const expandText = (\n <Box>\n <Divider\n style={{\n backgroundColor: emphasize(theme.palette.divider, 1),\n margin: '10px 0',\n }}\n />\n <Box display=\"flex\" justifyContent=\"space-between\" alignItems=\"center\">\n <FullScreenIcon />\n <Typography>Click to expand</Typography>\n </Box>\n </Box>\n );\n return (\n <Tooltip title={dateTitle}>\n {items.reverse().map((item, index) => (\n <TooltipItem key={`${item.label}-${index}`} item={item} />\n ))}\n {canExpand && !isExpanded ? expandText : null}\n </Tooltip>\n );\n };\n\n const options: Partial<BarChartLegendOptions> = {\n previousName: formatPeriod(duration, lastCompleteBillingDate, false),\n currentName: formatPeriod(duration, lastCompleteBillingDate, true),\n hideMarker: true,\n };\n\n return (\n <Box display=\"flex\" flexDirection=\"column\">\n <Box display=\"flex\" flexDirection=\"row\">\n <BarChartLegend\n costStart={previousPeriodTotal}\n costEnd={currentPeriodTotal}\n options={options}\n />\n </Box>\n <ResponsiveContainer\n width={responsive ? '100%' : classes.container.width}\n height={classes.container.height}\n >\n <AreaChart\n data={chartData}\n margin={{\n top: 16,\n right: 30,\n bottom: 40,\n }}\n >\n <CartesianGrid stroke={classes.cartesianGrid.stroke} />\n <XAxis\n dataKey=\"date\"\n domain={['dataMin', 'dataMax']}\n tickFormatter={overviewGraphTickFormatter}\n tickCount={6}\n type=\"number\"\n stroke={classes.axis.fill}\n />\n <YAxis\n domain={[() => 0, 'dataMax']}\n tick={{ fill: classes.axis.fill }}\n tickFormatter={formatGraphValue(baseCurrency)}\n width={classes.yAxis.width}\n />\n {renderAreas()}\n <RechartsTooltip content={tooltipRenderer} animationDuration={100} />\n </AreaChart>\n </ResponsiveContainer>\n </Box>\n );\n};\n"],"names":["useStyles","Tooltip","TooltipItem","RechartsTooltip"],"mappings":"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"}
1
+ {"version":3,"file":"CostOverviewBreakdownChart.esm.js","sources":["../../../src/components/CostOverviewCard/CostOverviewBreakdownChart.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 { useState } from 'react';\nimport { DateTime } from 'luxon';\nimport Box from '@material-ui/core/Box';\nimport Divider from '@material-ui/core/Divider';\nimport { emphasize } from '@material-ui/core/styles/colorManipulator';\nimport Typography from '@material-ui/core/Typography';\nimport { useTheme } from '@material-ui/core/styles';\nimport { default as FullScreenIcon } from '@material-ui/icons/Fullscreen';\nimport {\n Area,\n AreaChart,\n CartesianGrid,\n ResponsiveContainer,\n Tooltip as RechartsTooltip,\n XAxis,\n YAxis,\n} from 'recharts';\nimport { DEFAULT_DATE_FORMAT, CostInsightsTheme } from '../../types';\nimport { Cost } from '@backstage-community/plugin-cost-insights-common';\nimport {\n BarChartLegend,\n BarChartTooltip as Tooltip,\n BarChartTooltipItem as TooltipItem,\n} from '../BarChart';\nimport {\n formatGraphValue,\n isInvalid,\n overviewGraphTickFormatter,\n} from '../../utils/graphs';\nimport { useCostOverviewStyles as useStyles } from '../../utils/styles';\nimport { useConfig, useFilters, useLastCompleteBillingDate } from '../../hooks';\nimport { mapFiltersToProps } from './selector';\nimport { getPreviousPeriodTotalCost } from '../../utils/change';\nimport { formatPeriod } from '../../utils/formatters';\nimport { aggregationSum } from '../../utils/sum';\nimport { BarChartLegendOptions } from '../BarChart';\nimport { TooltipRenderer } from '../../types';\n\nexport type CostOverviewBreakdownChartProps = {\n costBreakdown: Cost[];\n responsive?: boolean;\n};\n\nconst LOW_COST_THRESHOLD = 0.1;\n\nexport const CostOverviewBreakdownChart = ({\n costBreakdown,\n responsive = true,\n}: CostOverviewBreakdownChartProps) => {\n const theme = useTheme<CostInsightsTheme>();\n const classes = useStyles(theme);\n const { baseCurrency } = useConfig();\n const lastCompleteBillingDate = useLastCompleteBillingDate();\n const { duration } = useFilters(mapFiltersToProps);\n const [isExpanded, setExpanded] = useState(false);\n\n if (!costBreakdown) {\n return null;\n }\n\n const flattenedAggregation = costBreakdown\n .map(cost => cost.aggregation)\n .flat();\n\n const totalCost = aggregationSum(flattenedAggregation);\n\n const previousPeriodTotal = getPreviousPeriodTotalCost(\n flattenedAggregation,\n duration,\n lastCompleteBillingDate,\n );\n const currentPeriodTotal = totalCost - previousPeriodTotal;\n const canExpand = costBreakdown.length >= 8;\n const otherCategoryIds: string[] = [];\n\n const breakdownsByDate = costBreakdown.reduce(\n (breakdownByDate, breakdown) => {\n const breakdownTotal = aggregationSum(breakdown.aggregation);\n // Group breakdown items with less than 10% of the total cost into \"Other\" category if needed\n const isOtherCategory =\n canExpand && breakdownTotal < totalCost * LOW_COST_THRESHOLD;\n\n const updatedBreakdownByDate = { ...breakdownByDate };\n if (isOtherCategory) {\n otherCategoryIds.push(breakdown.id);\n }\n breakdown.aggregation.forEach(curAggregation => {\n const costsForDate = updatedBreakdownByDate[curAggregation.date] || {};\n\n updatedBreakdownByDate[curAggregation.date] = {\n ...costsForDate,\n [breakdown.id]:\n (costsForDate[breakdown.id] || 0) + curAggregation.amount,\n };\n });\n\n return updatedBreakdownByDate;\n },\n {} as Record<string, Record<string, number>>,\n );\n\n const chartData: Record<string, number>[] = Object.keys(breakdownsByDate)\n .map(date => {\n const costsForDate = Object.keys(breakdownsByDate[date]).reduce(\n (dateCosts, breakdown) => {\n // Group costs for items that belong to 'Other' in the chart.\n const cost = breakdownsByDate[date][breakdown];\n const breakdownCost =\n !isExpanded && otherCategoryIds.includes(breakdown)\n ? { Other: (dateCosts.Other || 0) + cost }\n : { [breakdown]: cost };\n return { ...dateCosts, ...breakdownCost };\n },\n {} as Record<string, number>,\n );\n return {\n ...costsForDate,\n date: Date.parse(date),\n };\n })\n .sort((a, b) => a.date - b.date);\n\n const sortedBreakdowns = costBreakdown.sort(\n (a, b) => aggregationSum(a.aggregation) - aggregationSum(b.aggregation),\n );\n\n const renderAreas = () => {\n const separatedBreakdowns = sortedBreakdowns\n // Check that the breakdown is a separate group and hasn't been added to 'Other'\n .filter(\n breakdown =>\n breakdown.id !== 'Other' && !otherCategoryIds.includes(breakdown.id),\n )\n .map(breakdown => breakdown.id);\n // Keep 'Other' category at the bottom of the stack\n const breakdownsToDisplay = isExpanded\n ? sortedBreakdowns.map(breakdown => breakdown.id)\n : ['Other', ...separatedBreakdowns];\n\n return breakdownsToDisplay.map((breakdown, i) => {\n // Logic to handle case where there are more items than data viz colors.\n const color =\n theme.palette.dataViz[\n (breakdownsToDisplay.length - 1 - i) %\n (theme.palette.dataViz.length - 1)\n ];\n return (\n <Area\n key={breakdown}\n dataKey={breakdown}\n isAnimationActive={false}\n stackId=\"1\"\n stroke={color}\n fill={color}\n onClick={() => setExpanded(true)}\n style={{\n cursor:\n breakdown === 'Other' && !isExpanded ? 'pointer' : undefined,\n }}\n />\n );\n });\n };\n\n const tooltipRenderer: TooltipRenderer = ({ label, payload = [] }) => {\n if (isInvalid({ label, payload })) return null;\n\n const date =\n typeof label === 'number'\n ? DateTime.fromMillis(label)\n : DateTime.fromISO(label!);\n const dateTitle = date.toUTC().toFormat(DEFAULT_DATE_FORMAT);\n const formatGraphValueWith = formatGraphValue(baseCurrency);\n const items = payload.map((p, i) => ({\n label: p.dataKey as string,\n value: formatGraphValueWith(Number(p.value), i),\n fill: p.color!,\n }));\n const expandText = (\n <Box>\n <Divider\n style={{\n backgroundColor: emphasize(theme.palette.divider, 1),\n margin: '10px 0',\n }}\n />\n <Box display=\"flex\" justifyContent=\"space-between\" alignItems=\"center\">\n <FullScreenIcon />\n <Typography>Click to expand</Typography>\n </Box>\n </Box>\n );\n return (\n <Tooltip title={dateTitle}>\n {items.reverse().map((item, index) => (\n <TooltipItem key={`${item.label}-${index}`} item={item} />\n ))}\n {canExpand && !isExpanded ? expandText : null}\n </Tooltip>\n );\n };\n\n const options: Partial<BarChartLegendOptions> = {\n previousName: formatPeriod(duration, lastCompleteBillingDate, false),\n currentName: formatPeriod(duration, lastCompleteBillingDate, true),\n hideMarker: true,\n };\n\n return (\n <Box display=\"flex\" flexDirection=\"column\">\n <Box display=\"flex\" flexDirection=\"row\">\n <BarChartLegend\n costStart={previousPeriodTotal}\n costEnd={currentPeriodTotal}\n options={options}\n />\n </Box>\n <ResponsiveContainer\n width={responsive ? '100%' : classes.container.width}\n height={classes.container.height}\n >\n <AreaChart\n data={chartData}\n margin={{\n top: 16,\n right: 30,\n bottom: 40,\n }}\n >\n <CartesianGrid stroke={classes.cartesianGrid.stroke} />\n <XAxis\n dataKey=\"date\"\n domain={['dataMin', 'dataMax']}\n tickFormatter={overviewGraphTickFormatter}\n tickCount={6}\n type=\"number\"\n stroke={classes.axis.fill}\n />\n <YAxis\n domain={[() => 0, 'dataMax']}\n tick={{ fill: classes.axis.fill }}\n tickFormatter={formatGraphValue(baseCurrency)}\n width={classes.yAxis.width}\n />\n {renderAreas()}\n <RechartsTooltip content={tooltipRenderer} animationDuration={100} />\n </AreaChart>\n </ResponsiveContainer>\n </Box>\n );\n};\n"],"names":["useStyles","Tooltip","TooltipItem","RechartsTooltip"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
- import React, { useState, useEffect } from 'react';
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import { useState, useEffect } from 'react';
2
3
  import Box from '@material-ui/core/Box';
3
4
  import { capitalize } from '@material-ui/core/utils';
4
5
  import Card from '@material-ui/core/Card';
@@ -53,46 +54,55 @@ const CostOverviewCard = ({
53
54
  ].concat(breakdownTabs);
54
55
  const safeTabIndex = tabIndex > tabs.length - 1 ? 0 : tabIndex;
55
56
  const OverviewTabs = () => {
56
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
57
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
57
58
  Tabs,
58
59
  {
59
60
  indicatorColor: "primary",
60
61
  onChange: (_, index) => setTabIndex(index),
61
- value: safeTabIndex
62
- },
63
- tabs.map((tab, index) => /* @__PURE__ */ React.createElement(
64
- Tab,
65
- {
66
- className: styles.default,
67
- label: tab.label,
68
- key: tab.id,
69
- value: index,
70
- classes: { selected: styles.selected }
71
- }
72
- ))
73
- ));
62
+ value: safeTabIndex,
63
+ children: tabs.map((tab, index) => /* @__PURE__ */ jsx(
64
+ Tab,
65
+ {
66
+ className: styles.default,
67
+ label: tab.label,
68
+ value: index,
69
+ classes: { selected: styles.selected }
70
+ },
71
+ tab.id
72
+ ))
73
+ }
74
+ ) });
74
75
  };
75
76
  const showMetricSelect = metricData && config.metrics.length && safeTabIndex === 0;
76
- return /* @__PURE__ */ React.createElement(Card, { style: { position: "relative", overflow: "visible" } }, /* @__PURE__ */ React.createElement(ScrollAnchor, { id: DefaultNavigation.CostOverviewCard }), /* @__PURE__ */ React.createElement(CardContent, null, dailyCostData.groupedCosts && /* @__PURE__ */ React.createElement(OverviewTabs, null), /* @__PURE__ */ React.createElement(CostOverviewHeader, { title: tabs[safeTabIndex].title }, /* @__PURE__ */ React.createElement(PeriodSelect, { duration: filters.duration, onSelect: setDuration })), /* @__PURE__ */ React.createElement(Divider, null), /* @__PURE__ */ React.createElement(Box, { ml: 2, my: 1, display: "flex", flexDirection: "column" }, safeTabIndex === 0 ? /* @__PURE__ */ React.createElement(
77
- CostOverviewChart,
78
- {
79
- dailyCostData,
80
- metric,
81
- metricData
82
- }
83
- ) : /* @__PURE__ */ React.createElement(
84
- CostOverviewBreakdownChart,
85
- {
86
- costBreakdown: dailyCostData.groupedCosts[tabs[safeTabIndex].id]
87
- }
88
- )), /* @__PURE__ */ React.createElement(Box, { display: "flex", justifyContent: "flex-end", alignItems: "center" }, showMetricSelect && /* @__PURE__ */ React.createElement(
89
- MetricSelect,
90
- {
91
- metric: filters.metric,
92
- metrics: config.metrics,
93
- onSelect: setMetric
94
- }
95
- ))));
77
+ return /* @__PURE__ */ jsxs(Card, { style: { position: "relative", overflow: "visible" }, children: [
78
+ /* @__PURE__ */ jsx(ScrollAnchor, { id: DefaultNavigation.CostOverviewCard }),
79
+ /* @__PURE__ */ jsxs(CardContent, { children: [
80
+ dailyCostData.groupedCosts && /* @__PURE__ */ jsx(OverviewTabs, {}),
81
+ /* @__PURE__ */ jsx(CostOverviewHeader, { title: tabs[safeTabIndex].title, children: /* @__PURE__ */ jsx(PeriodSelect, { duration: filters.duration, onSelect: setDuration }) }),
82
+ /* @__PURE__ */ jsx(Divider, {}),
83
+ /* @__PURE__ */ jsx(Box, { ml: 2, my: 1, display: "flex", flexDirection: "column", children: safeTabIndex === 0 ? /* @__PURE__ */ jsx(
84
+ CostOverviewChart,
85
+ {
86
+ dailyCostData,
87
+ metric,
88
+ metricData
89
+ }
90
+ ) : /* @__PURE__ */ jsx(
91
+ CostOverviewBreakdownChart,
92
+ {
93
+ costBreakdown: dailyCostData.groupedCosts[tabs[safeTabIndex].id]
94
+ }
95
+ ) }),
96
+ /* @__PURE__ */ jsx(Box, { display: "flex", justifyContent: "flex-end", alignItems: "center", children: showMetricSelect && /* @__PURE__ */ jsx(
97
+ MetricSelect,
98
+ {
99
+ metric: filters.metric,
100
+ metrics: config.metrics,
101
+ onSelect: setMetric
102
+ }
103
+ ) })
104
+ ] })
105
+ ] });
96
106
  };
97
107
 
98
108
  export { CostOverviewCard };
@@ -1 +1 @@
1
- {"version":3,"file":"CostOverviewCard.esm.js","sources":["../../../src/components/CostOverviewCard/CostOverviewCard.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, useState } from 'react';\nimport Box from '@material-ui/core/Box';\nimport { capitalize } from '@material-ui/core/utils';\nimport Card from '@material-ui/core/Card';\nimport CardContent from '@material-ui/core/CardContent';\nimport Divider from '@material-ui/core/Divider';\nimport Tab from '@material-ui/core/Tab';\nimport Tabs from '@material-ui/core/Tabs';\nimport { useTheme } from '@material-ui/core/styles';\nimport { CostOverviewChart } from './CostOverviewChart';\nimport { CostOverviewBreakdownChart } from './CostOverviewBreakdownChart';\nimport { CostOverviewHeader } from './CostOverviewHeader';\nimport { MetricSelect } from '../MetricSelect';\nimport { PeriodSelect } from '../PeriodSelect';\nimport { useConfig, useFilters } from '../../hooks';\nimport { mapFiltersToProps } from './selector';\nimport { DefaultNavigation } from '../../utils/navigation';\nimport { findAlways } from '../../utils/assert';\nimport { CostInsightsTheme } from '../../types';\nimport {\n Cost,\n Maybe,\n MetricData,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { useOverviewTabsStyles } from '../../utils/styles';\nimport { ScrollAnchor } from '../../utils/scroll';\n\nexport type CostOverviewCardProps = {\n dailyCostData: Cost;\n metricData: Maybe<MetricData>;\n};\n\nexport const CostOverviewCard = ({\n dailyCostData,\n metricData,\n}: CostOverviewCardProps) => {\n const theme = useTheme<CostInsightsTheme>();\n const styles = useOverviewTabsStyles(theme);\n const config = useConfig();\n const [tabIndex, setTabIndex] = useState(0);\n const { setDuration, setProject, setMetric, ...filters } =\n useFilters(mapFiltersToProps);\n\n // Reset tabIndex if breakdowns available change\n useEffect(() => {\n // Intentionally off-by-one to account for the overview tab\n const lastIndex = Object.keys(dailyCostData.groupedCosts ?? {}).length;\n if (tabIndex > lastIndex) {\n setTabIndex(0);\n }\n }, [dailyCostData, tabIndex, setTabIndex]);\n\n const metric = filters.metric\n ? findAlways(config.metrics, m => m.kind === filters.metric)\n : null;\n\n const breakdownTabs = Object.keys(dailyCostData.groupedCosts ?? {}).map(\n key => ({\n id: key,\n label: `Breakdown by ${key}`,\n title: `Cloud Cost By ${capitalize(key)}`,\n }),\n );\n const tabs = [\n { id: 'overview', label: 'Total cost', title: 'Cloud Cost' },\n ].concat(breakdownTabs);\n // tabIndex can temporarily be invalid while the useEffect above processes\n const safeTabIndex = tabIndex > tabs.length - 1 ? 0 : tabIndex;\n\n const OverviewTabs = () => {\n return (\n <>\n <Tabs\n indicatorColor=\"primary\"\n onChange={(_, index) => setTabIndex(index)}\n value={safeTabIndex}\n >\n {tabs.map((tab, index) => (\n <Tab\n className={styles.default}\n label={tab.label}\n key={tab.id}\n value={index}\n classes={{ selected: styles.selected }}\n />\n ))}\n </Tabs>\n </>\n );\n };\n\n // Metrics can only be selected on the total cost graph\n const showMetricSelect =\n metricData && config.metrics.length && safeTabIndex === 0;\n\n return (\n <Card style={{ position: 'relative', overflow: 'visible' }}>\n <ScrollAnchor id={DefaultNavigation.CostOverviewCard} />\n <CardContent>\n {dailyCostData.groupedCosts && <OverviewTabs />}\n <CostOverviewHeader title={tabs[safeTabIndex].title}>\n <PeriodSelect duration={filters.duration} onSelect={setDuration} />\n </CostOverviewHeader>\n <Divider />\n <Box ml={2} my={1} display=\"flex\" flexDirection=\"column\">\n {safeTabIndex === 0 ? (\n <CostOverviewChart\n dailyCostData={dailyCostData}\n metric={metric}\n metricData={metricData}\n />\n ) : (\n <CostOverviewBreakdownChart\n costBreakdown={dailyCostData.groupedCosts![tabs[safeTabIndex].id]}\n />\n )}\n </Box>\n <Box display=\"flex\" justifyContent=\"flex-end\" alignItems=\"center\">\n {showMetricSelect && (\n <MetricSelect\n metric={filters.metric}\n metrics={config.metrics}\n onSelect={setMetric}\n />\n )}\n </Box>\n </CardContent>\n </Card>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDO,MAAM,mBAAmB,CAAC;AAAA,EAC/B,aAAA;AAAA,EACA;AACF,CAA6B,KAAA;AAC3B,EAAA,MAAM,QAAQ,QAA4B,EAAA;AAC1C,EAAM,MAAA,MAAA,GAAS,sBAAsB,KAAK,CAAA;AAC1C,EAAA,MAAM,SAAS,SAAU,EAAA;AACzB,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAS,CAAC,CAAA;AAC1C,EAAM,MAAA,EAAE,aAAa,UAAY,EAAA,SAAA,EAAW,GAAG,OAAQ,EAAA,GACrD,WAAW,iBAAiB,CAAA;AAG9B,EAAA,SAAA,CAAU,MAAM;AAEd,IAAA,MAAM,YAAY,MAAO,CAAA,IAAA,CAAK,cAAc,YAAgB,IAAA,EAAE,CAAE,CAAA,MAAA;AAChE,IAAA,IAAI,WAAW,SAAW,EAAA;AACxB,MAAA,WAAA,CAAY,CAAC,CAAA;AAAA;AACf,GACC,EAAA,CAAC,aAAe,EAAA,QAAA,EAAU,WAAW,CAAC,CAAA;AAEzC,EAAM,MAAA,MAAA,GAAS,OAAQ,CAAA,MAAA,GACnB,UAAW,CAAA,MAAA,CAAO,OAAS,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,IAAA,KAAS,OAAQ,CAAA,MAAM,CACzD,GAAA,IAAA;AAEJ,EAAA,MAAM,gBAAgB,MAAO,CAAA,IAAA,CAAK,cAAc,YAAgB,IAAA,EAAE,CAAE,CAAA,GAAA;AAAA,IAClE,CAAQ,GAAA,MAAA;AAAA,MACN,EAAI,EAAA,GAAA;AAAA,MACJ,KAAA,EAAO,gBAAgB,GAAG,CAAA,CAAA;AAAA,MAC1B,KAAO,EAAA,CAAA,cAAA,EAAiB,UAAW,CAAA,GAAG,CAAC,CAAA;AAAA,KACzC;AAAA,GACF;AACA,EAAA,MAAM,IAAO,GAAA;AAAA,IACX,EAAE,EAAI,EAAA,UAAA,EAAY,KAAO,EAAA,YAAA,EAAc,OAAO,YAAa;AAAA,GAC7D,CAAE,OAAO,aAAa,CAAA;AAEtB,EAAA,MAAM,YAAe,GAAA,QAAA,GAAW,IAAK,CAAA,MAAA,GAAS,IAAI,CAAI,GAAA,QAAA;AAEtD,EAAA,MAAM,eAAe,MAAM;AACzB,IAAA,uBAEI,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACC,cAAe,EAAA,SAAA;AAAA,QACf,QAAU,EAAA,CAAC,CAAG,EAAA,KAAA,KAAU,YAAY,KAAK,CAAA;AAAA,QACzC,KAAO,EAAA;AAAA,OAAA;AAAA,MAEN,IAAK,CAAA,GAAA,CAAI,CAAC,GAAA,EAAK,KACd,qBAAA,KAAA,CAAA,aAAA;AAAA,QAAC,GAAA;AAAA,QAAA;AAAA,UACC,WAAW,MAAO,CAAA,OAAA;AAAA,UAClB,OAAO,GAAI,CAAA,KAAA;AAAA,UACX,KAAK,GAAI,CAAA,EAAA;AAAA,UACT,KAAO,EAAA,KAAA;AAAA,UACP,OAAS,EAAA,EAAE,QAAU,EAAA,MAAA,CAAO,QAAS;AAAA;AAAA,OAExC;AAAA,KAEL,CAAA;AAAA,GAEJ;AAGA,EAAA,MAAM,gBACJ,GAAA,UAAA,IAAc,MAAO,CAAA,OAAA,CAAQ,UAAU,YAAiB,KAAA,CAAA;AAE1D,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,EAAE,QAAA,EAAU,YAAY,QAAU,EAAA,SAAA,EAC7C,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,YAAa,EAAA,EAAA,EAAA,EAAI,kBAAkB,gBAAkB,EAAA,CAAA,kBACrD,KAAA,CAAA,aAAA,CAAA,WAAA,EAAA,IAAA,EACE,aAAc,CAAA,YAAA,wCAAiB,YAAa,EAAA,IAAA,CAAA,kBAC5C,KAAA,CAAA,aAAA,CAAA,kBAAA,EAAA,EAAmB,KAAO,EAAA,IAAA,CAAK,YAAY,CAAE,CAAA,KAAA,EAAA,kBAC3C,KAAA,CAAA,aAAA,CAAA,YAAA,EAAA,EAAa,QAAU,EAAA,OAAA,CAAQ,UAAU,QAAU,EAAA,WAAA,EAAa,CACnE,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,IAAQ,mBACR,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,EAAI,EAAA,CAAA,EAAG,EAAI,EAAA,CAAA,EAAG,SAAQ,MAAO,EAAA,aAAA,EAAc,QAC7C,EAAA,EAAA,YAAA,KAAiB,CAChB,mBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,iBAAA;AAAA,IAAA;AAAA,MACC,aAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA;AAAA,GAGF,mBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,0BAAA;AAAA,IAAA;AAAA,MACC,eAAe,aAAc,CAAA,YAAA,CAAc,IAAK,CAAA,YAAY,EAAE,EAAE;AAAA;AAAA,GAGtE,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,OAAA,EAAQ,QAAO,cAAe,EAAA,UAAA,EAAW,UAAW,EAAA,QAAA,EAAA,EACtD,gBACC,oBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MACC,QAAQ,OAAQ,CAAA,MAAA;AAAA,MAChB,SAAS,MAAO,CAAA,OAAA;AAAA,MAChB,QAAU,EAAA;AAAA;AAAA,GAGhB,CACF,CACF,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"CostOverviewCard.esm.js","sources":["../../../src/components/CostOverviewCard/CostOverviewCard.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 { useEffect, useState } from 'react';\nimport Box from '@material-ui/core/Box';\nimport { capitalize } from '@material-ui/core/utils';\nimport Card from '@material-ui/core/Card';\nimport CardContent from '@material-ui/core/CardContent';\nimport Divider from '@material-ui/core/Divider';\nimport Tab from '@material-ui/core/Tab';\nimport Tabs from '@material-ui/core/Tabs';\nimport { useTheme } from '@material-ui/core/styles';\nimport { CostOverviewChart } from './CostOverviewChart';\nimport { CostOverviewBreakdownChart } from './CostOverviewBreakdownChart';\nimport { CostOverviewHeader } from './CostOverviewHeader';\nimport { MetricSelect } from '../MetricSelect';\nimport { PeriodSelect } from '../PeriodSelect';\nimport { useConfig, useFilters } from '../../hooks';\nimport { mapFiltersToProps } from './selector';\nimport { DefaultNavigation } from '../../utils/navigation';\nimport { findAlways } from '../../utils/assert';\nimport { CostInsightsTheme } from '../../types';\nimport {\n Cost,\n Maybe,\n MetricData,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { useOverviewTabsStyles } from '../../utils/styles';\nimport { ScrollAnchor } from '../../utils/scroll';\n\nexport type CostOverviewCardProps = {\n dailyCostData: Cost;\n metricData: Maybe<MetricData>;\n};\n\nexport const CostOverviewCard = ({\n dailyCostData,\n metricData,\n}: CostOverviewCardProps) => {\n const theme = useTheme<CostInsightsTheme>();\n const styles = useOverviewTabsStyles(theme);\n const config = useConfig();\n const [tabIndex, setTabIndex] = useState(0);\n const { setDuration, setProject, setMetric, ...filters } =\n useFilters(mapFiltersToProps);\n\n // Reset tabIndex if breakdowns available change\n useEffect(() => {\n // Intentionally off-by-one to account for the overview tab\n const lastIndex = Object.keys(dailyCostData.groupedCosts ?? {}).length;\n if (tabIndex > lastIndex) {\n setTabIndex(0);\n }\n }, [dailyCostData, tabIndex, setTabIndex]);\n\n const metric = filters.metric\n ? findAlways(config.metrics, m => m.kind === filters.metric)\n : null;\n\n const breakdownTabs = Object.keys(dailyCostData.groupedCosts ?? {}).map(\n key => ({\n id: key,\n label: `Breakdown by ${key}`,\n title: `Cloud Cost By ${capitalize(key)}`,\n }),\n );\n const tabs = [\n { id: 'overview', label: 'Total cost', title: 'Cloud Cost' },\n ].concat(breakdownTabs);\n // tabIndex can temporarily be invalid while the useEffect above processes\n const safeTabIndex = tabIndex > tabs.length - 1 ? 0 : tabIndex;\n\n const OverviewTabs = () => {\n return (\n <>\n <Tabs\n indicatorColor=\"primary\"\n onChange={(_, index) => setTabIndex(index)}\n value={safeTabIndex}\n >\n {tabs.map((tab, index) => (\n <Tab\n className={styles.default}\n label={tab.label}\n key={tab.id}\n value={index}\n classes={{ selected: styles.selected }}\n />\n ))}\n </Tabs>\n </>\n );\n };\n\n // Metrics can only be selected on the total cost graph\n const showMetricSelect =\n metricData && config.metrics.length && safeTabIndex === 0;\n\n return (\n <Card style={{ position: 'relative', overflow: 'visible' }}>\n <ScrollAnchor id={DefaultNavigation.CostOverviewCard} />\n <CardContent>\n {dailyCostData.groupedCosts && <OverviewTabs />}\n <CostOverviewHeader title={tabs[safeTabIndex].title}>\n <PeriodSelect duration={filters.duration} onSelect={setDuration} />\n </CostOverviewHeader>\n <Divider />\n <Box ml={2} my={1} display=\"flex\" flexDirection=\"column\">\n {safeTabIndex === 0 ? (\n <CostOverviewChart\n dailyCostData={dailyCostData}\n metric={metric}\n metricData={metricData}\n />\n ) : (\n <CostOverviewBreakdownChart\n costBreakdown={dailyCostData.groupedCosts![tabs[safeTabIndex].id]}\n />\n )}\n </Box>\n <Box display=\"flex\" justifyContent=\"flex-end\" alignItems=\"center\">\n {showMetricSelect && (\n <MetricSelect\n metric={filters.metric}\n metrics={config.metrics}\n onSelect={setMetric}\n />\n )}\n </Box>\n </CardContent>\n </Card>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDO,MAAM,mBAAmB,CAAC;AAAA,EAC/B,aAAA;AAAA,EACA;AACF,CAA6B,KAAA;AAC3B,EAAA,MAAM,QAAQ,QAA4B,EAAA;AAC1C,EAAM,MAAA,MAAA,GAAS,sBAAsB,KAAK,CAAA;AAC1C,EAAA,MAAM,SAAS,SAAU,EAAA;AACzB,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAS,CAAC,CAAA;AAC1C,EAAM,MAAA,EAAE,aAAa,UAAY,EAAA,SAAA,EAAW,GAAG,OAAQ,EAAA,GACrD,WAAW,iBAAiB,CAAA;AAG9B,EAAA,SAAA,CAAU,MAAM;AAEd,IAAA,MAAM,YAAY,MAAO,CAAA,IAAA,CAAK,cAAc,YAAgB,IAAA,EAAE,CAAE,CAAA,MAAA;AAChE,IAAA,IAAI,WAAW,SAAW,EAAA;AACxB,MAAA,WAAA,CAAY,CAAC,CAAA;AAAA;AACf,GACC,EAAA,CAAC,aAAe,EAAA,QAAA,EAAU,WAAW,CAAC,CAAA;AAEzC,EAAM,MAAA,MAAA,GAAS,OAAQ,CAAA,MAAA,GACnB,UAAW,CAAA,MAAA,CAAO,OAAS,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,IAAA,KAAS,OAAQ,CAAA,MAAM,CACzD,GAAA,IAAA;AAEJ,EAAA,MAAM,gBAAgB,MAAO,CAAA,IAAA,CAAK,cAAc,YAAgB,IAAA,EAAE,CAAE,CAAA,GAAA;AAAA,IAClE,CAAQ,GAAA,MAAA;AAAA,MACN,EAAI,EAAA,GAAA;AAAA,MACJ,KAAA,EAAO,gBAAgB,GAAG,CAAA,CAAA;AAAA,MAC1B,KAAO,EAAA,CAAA,cAAA,EAAiB,UAAW,CAAA,GAAG,CAAC,CAAA;AAAA,KACzC;AAAA,GACF;AACA,EAAA,MAAM,IAAO,GAAA;AAAA,IACX,EAAE,EAAI,EAAA,UAAA,EAAY,KAAO,EAAA,YAAA,EAAc,OAAO,YAAa;AAAA,GAC7D,CAAE,OAAO,aAAa,CAAA;AAEtB,EAAA,MAAM,YAAe,GAAA,QAAA,GAAW,IAAK,CAAA,MAAA,GAAS,IAAI,CAAI,GAAA,QAAA;AAEtD,EAAA,MAAM,eAAe,MAAM;AACzB,IAAA,uBAEI,GAAA,CAAA,QAAA,EAAA,EAAA,QAAA,kBAAA,GAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACC,cAAe,EAAA,SAAA;AAAA,QACf,QAAU,EAAA,CAAC,CAAG,EAAA,KAAA,KAAU,YAAY,KAAK,CAAA;AAAA,QACzC,KAAO,EAAA,YAAA;AAAA,QAEN,QAAK,EAAA,IAAA,CAAA,GAAA,CAAI,CAAC,GAAA,EAAK,KACd,qBAAA,GAAA;AAAA,UAAC,GAAA;AAAA,UAAA;AAAA,YACC,WAAW,MAAO,CAAA,OAAA;AAAA,YAClB,OAAO,GAAI,CAAA,KAAA;AAAA,YAEX,KAAO,EAAA,KAAA;AAAA,YACP,OAAS,EAAA,EAAE,QAAU,EAAA,MAAA,CAAO,QAAS;AAAA,WAAA;AAAA,UAFhC,GAAI,CAAA;AAAA,SAIZ;AAAA;AAAA,KAEL,EAAA,CAAA;AAAA,GAEJ;AAGA,EAAA,MAAM,gBACJ,GAAA,UAAA,IAAc,MAAO,CAAA,OAAA,CAAQ,UAAU,YAAiB,KAAA,CAAA;AAE1D,EACE,uBAAA,IAAA,CAAC,QAAK,KAAO,EAAA,EAAE,UAAU,UAAY,EAAA,QAAA,EAAU,WAC7C,EAAA,QAAA,EAAA;AAAA,oBAAC,GAAA,CAAA,YAAA,EAAA,EAAa,EAAI,EAAA,iBAAA,CAAkB,gBAAkB,EAAA,CAAA;AAAA,yBACrD,WACE,EAAA,EAAA,QAAA,EAAA;AAAA,MAAc,aAAA,CAAA,YAAA,wBAAiB,YAAa,EAAA,EAAA,CAAA;AAAA,sBAC5C,GAAA,CAAA,kBAAA,EAAA,EAAmB,KAAO,EAAA,IAAA,CAAK,YAAY,CAAE,CAAA,KAAA,EAC5C,QAAC,kBAAA,GAAA,CAAA,YAAA,EAAA,EAAa,QAAU,EAAA,OAAA,CAAQ,QAAU,EAAA,QAAA,EAAU,aAAa,CACnE,EAAA,CAAA;AAAA,0BACC,OAAQ,EAAA,EAAA,CAAA;AAAA,sBACT,GAAA,CAAC,GAAI,EAAA,EAAA,EAAA,EAAI,CAAG,EAAA,EAAA,EAAI,CAAG,EAAA,OAAA,EAAQ,MAAO,EAAA,aAAA,EAAc,QAC7C,EAAA,QAAA,EAAA,YAAA,KAAiB,CAChB,mBAAA,GAAA;AAAA,QAAC,iBAAA;AAAA,QAAA;AAAA,UACC,aAAA;AAAA,UACA,MAAA;AAAA,UACA;AAAA;AAAA,OAGF,mBAAA,GAAA;AAAA,QAAC,0BAAA;AAAA,QAAA;AAAA,UACC,eAAe,aAAc,CAAA,YAAA,CAAc,IAAK,CAAA,YAAY,EAAE,EAAE;AAAA;AAAA,OAGtE,EAAA,CAAA;AAAA,sBACA,GAAA,CAAC,OAAI,OAAQ,EAAA,MAAA,EAAO,gBAAe,UAAW,EAAA,UAAA,EAAW,UACtD,QACC,EAAA,gBAAA,oBAAA,GAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UACC,QAAQ,OAAQ,CAAA,MAAA;AAAA,UAChB,SAAS,MAAO,CAAA,OAAA;AAAA,UAChB,QAAU,EAAA;AAAA;AAAA,OAGhB,EAAA;AAAA,KACF,EAAA;AAAA,GACF,EAAA,CAAA;AAEJ;;;;"}