@backstage-community/plugin-cost-insights 0.12.24 → 0.12.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +6 -6
- package/dist/alerts/ProjectGrowthAlert.esm.js +24 -0
- package/dist/alerts/ProjectGrowthAlert.esm.js.map +1 -0
- package/dist/alerts/UnlabeledDataflowAlert.esm.js +25 -0
- package/dist/alerts/UnlabeledDataflowAlert.esm.js.map +1 -0
- package/dist/api/CostInsightsApi.esm.js +8 -0
- package/dist/api/CostInsightsApi.esm.js.map +1 -0
- package/dist/components/ActionItems/ActionItemCard.esm.js +46 -0
- package/dist/components/ActionItems/ActionItemCard.esm.js.map +1 -0
- package/dist/components/ActionItems/ActionItems.esm.js +90 -0
- package/dist/components/ActionItems/ActionItems.esm.js.map +1 -0
- package/dist/components/AlertInsights/AlertDialog.esm.js +123 -0
- package/dist/components/AlertInsights/AlertDialog.esm.js.map +1 -0
- package/dist/components/AlertInsights/AlertInsights.esm.js +157 -0
- package/dist/components/AlertInsights/AlertInsights.esm.js.map +1 -0
- package/dist/components/AlertInsights/AlertInsightsHeader.esm.js +17 -0
- package/dist/components/AlertInsights/AlertInsightsHeader.esm.js.map +1 -0
- package/dist/components/AlertInsights/AlertInsightsSection.esm.js +57 -0
- package/dist/components/AlertInsights/AlertInsightsSection.esm.js.map +1 -0
- package/dist/components/AlertInsights/AlertInsightsSectionHeader.esm.js +30 -0
- package/dist/components/AlertInsights/AlertInsightsSectionHeader.esm.js.map +1 -0
- package/dist/components/AlertInsights/AlertStatusSummary.esm.js +93 -0
- package/dist/components/AlertInsights/AlertStatusSummary.esm.js.map +1 -0
- package/dist/components/AlertInsights/AlertStatusSummaryButton.esm.js +35 -0
- package/dist/components/AlertInsights/AlertStatusSummaryButton.esm.js.map +1 -0
- package/dist/components/AlertInstructionsLayout/AlertInstructionsLayout.esm.js +47 -0
- package/dist/components/AlertInstructionsLayout/AlertInstructionsLayout.esm.js.map +1 -0
- package/dist/components/BarChart/BarChart.esm.js +167 -0
- package/dist/components/BarChart/BarChart.esm.js.map +1 -0
- package/dist/components/BarChart/BarChartLabel.esm.js +31 -0
- package/dist/components/BarChart/BarChartLabel.esm.js.map +1 -0
- package/dist/components/BarChart/BarChartLegend.esm.js +47 -0
- package/dist/components/BarChart/BarChartLegend.esm.js.map +1 -0
- package/dist/components/BarChart/BarChartStepper.esm.js +91 -0
- package/dist/components/BarChart/BarChartStepper.esm.js.map +1 -0
- package/dist/components/BarChart/BarChartStepperButton.esm.js +27 -0
- package/dist/components/BarChart/BarChartStepperButton.esm.js.map +1 -0
- package/dist/components/BarChart/BarChartSteps.esm.js +25 -0
- package/dist/components/BarChart/BarChartSteps.esm.js.map +1 -0
- package/dist/components/BarChart/BarChartTick.esm.js +29 -0
- package/dist/components/BarChart/BarChartTick.esm.js.map +1 -0
- package/dist/components/BarChart/BarChartTooltip.esm.js +30 -0
- package/dist/components/BarChart/BarChartTooltip.esm.js.map +1 -0
- package/dist/components/BarChart/BarChartTooltipItem.esm.js +24 -0
- package/dist/components/BarChart/BarChartTooltipItem.esm.js.map +1 -0
- package/dist/components/CopyUrlToClipboard/CopyUrlToClipboard.esm.js +44 -0
- package/dist/components/CopyUrlToClipboard/CopyUrlToClipboard.esm.js.map +1 -0
- package/dist/components/CostGrowth/CostGrowth.esm.js +55 -0
- package/dist/components/CostGrowth/CostGrowth.esm.js.map +1 -0
- package/dist/components/CostGrowth/CostGrowthIndicator.esm.js +31 -0
- package/dist/components/CostGrowth/CostGrowthIndicator.esm.js.map +1 -0
- package/dist/components/CostInsightsHeader/CostInsightsHeader.esm.js +57 -0
- package/dist/components/CostInsightsHeader/CostInsightsHeader.esm.js.map +1 -0
- package/dist/components/CostInsightsLayout/CostInsightsLayout.esm.js +35 -0
- package/dist/components/CostInsightsLayout/CostInsightsLayout.esm.js.map +1 -0
- package/dist/components/CostInsightsNavigation/CostInsightsNavigation.esm.js +87 -0
- package/dist/components/CostInsightsNavigation/CostInsightsNavigation.esm.js.map +1 -0
- package/dist/components/CostInsightsPage/CostInsightsPage.esm.js +229 -0
- package/dist/components/CostInsightsPage/CostInsightsPage.esm.js.map +1 -0
- package/dist/components/CostInsightsPage/CostInsightsPageRoot.esm.js +15 -0
- package/dist/components/CostInsightsPage/CostInsightsPageRoot.esm.js.map +1 -0
- package/dist/components/CostInsightsPage/CostInsightsThemeProvider.esm.js +24 -0
- package/dist/components/CostInsightsPage/CostInsightsThemeProvider.esm.js.map +1 -0
- package/dist/components/CostInsightsPage/index.esm.js +2 -0
- package/dist/components/CostInsightsPage/index.esm.js.map +1 -0
- package/dist/components/CostInsightsPage/selector.esm.js +15 -0
- package/dist/components/CostInsightsPage/selector.esm.js.map +1 -0
- package/dist/components/CostInsightsTabs/CostInsightsTabs.esm.js +89 -0
- package/dist/components/CostInsightsTabs/CostInsightsTabs.esm.js.map +1 -0
- package/dist/components/CostInsightsTabs/selector.esm.js +17 -0
- package/dist/components/CostInsightsTabs/selector.esm.js.map +1 -0
- package/dist/components/CostOverviewCard/CostOverviewBreakdownChart.esm.js +196 -0
- package/dist/components/CostOverviewCard/CostOverviewBreakdownChart.esm.js.map +1 -0
- package/dist/components/CostOverviewCard/CostOverviewCard.esm.js +99 -0
- package/dist/components/CostOverviewCard/CostOverviewCard.esm.js.map +1 -0
- package/dist/components/CostOverviewCard/CostOverviewChart.esm.js +157 -0
- package/dist/components/CostOverviewCard/CostOverviewChart.esm.js.map +1 -0
- package/dist/components/CostOverviewCard/CostOverviewHeader.esm.js +25 -0
- package/dist/components/CostOverviewCard/CostOverviewHeader.esm.js.map +1 -0
- package/dist/components/CostOverviewCard/CostOverviewLegend.esm.js +54 -0
- package/dist/components/CostOverviewCard/CostOverviewLegend.esm.js.map +1 -0
- package/dist/components/CostOverviewCard/selector.esm.js +22 -0
- package/dist/components/CostOverviewCard/selector.esm.js.map +1 -0
- package/dist/components/CurrencySelect/CurrencySelect.esm.js +52 -0
- package/dist/components/CurrencySelect/CurrencySelect.esm.js.map +1 -0
- package/dist/{esm/index-BPzWHt3A.esm.js → components/EntityCosts/EntityCosts.esm.js} +14 -80
- package/dist/{esm/index-BPzWHt3A.esm.js.map → components/EntityCosts/EntityCosts.esm.js.map} +1 -1
- package/dist/components/EntityCosts/index.esm.js +2 -0
- package/dist/components/EntityCosts/index.esm.js.map +1 -0
- package/dist/{esm/index-BA6m_qFS.esm.js → components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.esm.js} +2 -79
- package/dist/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.esm.js.map +1 -0
- package/dist/components/LabelDataflowInstructionsPage/index.esm.js +2 -0
- package/dist/components/LabelDataflowInstructionsPage/index.esm.js.map +1 -0
- package/dist/components/LegendItem/LegendItem.esm.js +44 -0
- package/dist/components/LegendItem/LegendItem.esm.js.map +1 -0
- package/dist/components/MetricSelect/MetricSelect.esm.js +37 -0
- package/dist/components/MetricSelect/MetricSelect.esm.js.map +1 -0
- package/dist/components/PeriodSelect/PeriodSelect.esm.js +72 -0
- package/dist/components/PeriodSelect/PeriodSelect.esm.js.map +1 -0
- package/dist/components/ProductInsights/ProductInsights.esm.js +98 -0
- package/dist/components/ProductInsights/ProductInsights.esm.js.map +1 -0
- package/dist/components/ProductInsightsCard/ProductEntityDialog.esm.js +42 -0
- package/dist/components/ProductInsightsCard/ProductEntityDialog.esm.js.map +1 -0
- package/dist/components/ProductInsightsCard/ProductEntityTable.esm.js +139 -0
- package/dist/components/ProductInsightsCard/ProductEntityTable.esm.js.map +1 -0
- package/dist/components/ProductInsightsCard/ProductInsightsCard.esm.js +83 -0
- package/dist/components/ProductInsightsCard/ProductInsightsCard.esm.js.map +1 -0
- package/dist/components/ProductInsightsCard/ProductInsightsCardList.esm.js +34 -0
- package/dist/components/ProductInsightsCard/ProductInsightsCardList.esm.js.map +1 -0
- package/dist/components/ProductInsightsCard/ProductInsightsChart.esm.js +148 -0
- package/dist/components/ProductInsightsCard/ProductInsightsChart.esm.js.map +1 -0
- package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertCard.esm.js +20 -0
- package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertCard.esm.js.map +1 -0
- package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertChart.esm.js +46 -0
- package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertChart.esm.js.map +1 -0
- package/dist/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.esm.js +111 -0
- package/dist/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.esm.js.map +1 -0
- package/dist/components/ProjectGrowthInstructionsPage/index.esm.js +2 -0
- package/dist/components/ProjectGrowthInstructionsPage/index.esm.js.map +1 -0
- package/dist/components/ProjectSelect/ProjectSelect.esm.js +47 -0
- package/dist/components/ProjectSelect/ProjectSelect.esm.js.map +1 -0
- package/dist/components/UnlabeledDataflowAlertCard/UnlabeledDataflowAlertCard.esm.js +41 -0
- package/dist/components/UnlabeledDataflowAlertCard/UnlabeledDataflowAlertCard.esm.js.map +1 -0
- package/dist/components/WhyCostsMatter/WhyCostsMatter.esm.js +21 -0
- package/dist/components/WhyCostsMatter/WhyCostsMatter.esm.js.map +1 -0
- package/dist/example/alerts/KubernetesMigrationAlert.esm.js +86 -0
- package/dist/example/alerts/KubernetesMigrationAlert.esm.js.map +1 -0
- package/dist/example/client.esm.js +194 -0
- package/dist/example/client.esm.js.map +1 -0
- package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationAlertCard.esm.js +33 -0
- package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationAlertCard.esm.js.map +1 -0
- package/dist/{esm/index-BTIHr4n_.esm.js → example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChart.esm.js} +69 -48
- package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChart.esm.js.map +1 -0
- package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChartLegend.esm.js +107 -0
- package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChartLegend.esm.js.map +1 -0
- package/dist/example/forms/KubernetesMigrationDismissForm.esm.js +57 -0
- package/dist/example/forms/KubernetesMigrationDismissForm.esm.js.map +1 -0
- package/dist/forms/AlertAcceptForm.esm.js +27 -0
- package/dist/forms/AlertAcceptForm.esm.js.map +1 -0
- package/dist/forms/AlertDismissForm.esm.js +100 -0
- package/dist/forms/AlertDismissForm.esm.js.map +1 -0
- package/dist/forms/AlertSnoozeForm.esm.js +52 -0
- package/dist/forms/AlertSnoozeForm.esm.js.map +1 -0
- package/dist/hooks/useConfig.esm.js +153 -0
- package/dist/hooks/useConfig.esm.js.map +1 -0
- package/dist/hooks/useCurrency.esm.js +26 -0
- package/dist/hooks/useCurrency.esm.js.map +1 -0
- package/dist/hooks/useFilters.esm.js +67 -0
- package/dist/hooks/useFilters.esm.js.map +1 -0
- package/dist/hooks/useGroups.esm.js +55 -0
- package/dist/hooks/useGroups.esm.js.map +1 -0
- package/dist/hooks/useLastCompleteBillingDate.esm.js +65 -0
- package/dist/hooks/useLastCompleteBillingDate.esm.js.map +1 -0
- package/dist/hooks/useLoading.esm.js +54 -0
- package/dist/hooks/useLoading.esm.js.map +1 -0
- package/dist/hooks/useScroll.esm.js +24 -0
- package/dist/hooks/useScroll.esm.js.map +1 -0
- package/dist/index.esm.js +37 -22
- package/dist/index.esm.js.map +1 -1
- package/dist/plugin.esm.js +55 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/testUtils/filters.esm.js +8 -0
- package/dist/testUtils/filters.esm.js.map +1 -0
- package/dist/testUtils/loading.esm.js +14 -0
- package/dist/testUtils/loading.esm.js.map +1 -0
- package/dist/testUtils/mockData.esm.js +485 -0
- package/dist/testUtils/mockData.esm.js.map +1 -0
- package/dist/testUtils/products.esm.js +49 -0
- package/dist/testUtils/products.esm.js.map +1 -0
- package/dist/testUtils/providers.esm.js +41 -0
- package/dist/testUtils/providers.esm.js.map +1 -0
- package/dist/testUtils/testUtils.esm.js +142 -0
- package/dist/testUtils/testUtils.esm.js.map +1 -0
- package/dist/types/Alert.esm.js +66 -0
- package/dist/types/Alert.esm.js.map +1 -0
- package/dist/types/ChangeStatistic.esm.js +15 -0
- package/dist/types/ChangeStatistic.esm.js.map +1 -0
- package/dist/types/CurrencyType.esm.js +10 -0
- package/dist/types/CurrencyType.esm.js.map +1 -0
- package/dist/types/DateFormat.esm.js +4 -0
- package/dist/types/DateFormat.esm.js.map +1 -0
- package/dist/types/Duration.esm.js +10 -0
- package/dist/types/Duration.esm.js.map +1 -0
- package/dist/types/Icon.esm.js +12 -0
- package/dist/types/Icon.esm.js.map +1 -0
- package/dist/utils/alerts.esm.js +72 -0
- package/dist/utils/alerts.esm.js.map +1 -0
- package/dist/utils/assert.esm.js +29 -0
- package/dist/utils/assert.esm.js.map +1 -0
- package/dist/utils/change.esm.js +58 -0
- package/dist/utils/change.esm.js.map +1 -0
- package/dist/utils/charts.esm.js +9 -0
- package/dist/utils/charts.esm.js.map +1 -0
- package/dist/utils/config.esm.js +19 -0
- package/dist/utils/config.esm.js.map +1 -0
- package/dist/utils/currency.esm.js +56 -0
- package/dist/utils/currency.esm.js.map +1 -0
- package/dist/utils/duration.esm.js +55 -0
- package/dist/utils/duration.esm.js.map +1 -0
- package/dist/utils/filters.esm.js +14 -0
- package/dist/utils/filters.esm.js.map +1 -0
- package/dist/utils/formatters.esm.js +103 -0
- package/dist/utils/formatters.esm.js.map +1 -0
- package/dist/utils/grammar.esm.js +14 -0
- package/dist/utils/grammar.esm.js.map +1 -0
- package/dist/utils/graphs.esm.js +48 -0
- package/dist/utils/graphs.esm.js.map +1 -0
- package/dist/utils/history.esm.js +32 -0
- package/dist/utils/history.esm.js.map +1 -0
- package/dist/utils/loading.esm.js +51 -0
- package/dist/utils/loading.esm.js.map +1 -0
- package/dist/utils/navigation.esm.js +56 -0
- package/dist/utils/navigation.esm.js.map +1 -0
- package/dist/utils/scroll.esm.js +38 -0
- package/dist/utils/scroll.esm.js.map +1 -0
- package/dist/utils/sort.esm.js +10 -0
- package/dist/utils/sort.esm.js.map +1 -0
- package/dist/utils/styles.esm.js +562 -0
- package/dist/utils/styles.esm.js.map +1 -0
- package/dist/utils/sum.esm.js +4 -0
- package/dist/utils/sum.esm.js.map +1 -0
- package/package.json +17 -12
- package/dist/esm/index-BA6m_qFS.esm.js.map +0 -1
- package/dist/esm/index-BFM2mP6Z.esm.js +0 -4084
- package/dist/esm/index-BFM2mP6Z.esm.js.map +0 -1
- package/dist/esm/index-BTIHr4n_.esm.js.map +0 -1
- package/dist/esm/index-DaitkcPN.esm.js +0 -1136
- package/dist/esm/index-DaitkcPN.esm.js.map +0 -1
- package/dist/esm/selector-D7iXJwd9.esm.js +0 -594
- package/dist/esm/selector-D7iXJwd9.esm.js.map +0 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getResetStateWithoutInitial } from '../../utils/loading.esm.js';
|
|
2
|
+
|
|
3
|
+
const mapFiltersToProps = ({ pageFilters, setPageFilters }) => ({
|
|
4
|
+
...pageFilters,
|
|
5
|
+
setGroup: (group) => setPageFilters({
|
|
6
|
+
...pageFilters,
|
|
7
|
+
group: group.id,
|
|
8
|
+
project: null
|
|
9
|
+
})
|
|
10
|
+
});
|
|
11
|
+
const mapLoadingToProps = ({ actions, dispatch }) => ({
|
|
12
|
+
loadingActions: actions,
|
|
13
|
+
dispatchReset: (loadingActions) => dispatch(getResetStateWithoutInitial(loadingActions))
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export { mapFiltersToProps, mapLoadingToProps };
|
|
17
|
+
//# sourceMappingURL=selector.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector.esm.js","sources":["../../../src/components/CostInsightsTabs/selector.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { MapFiltersToProps } from '../../hooks/useFilters';\nimport { MapLoadingToProps } from '../../hooks/useLoading';\nimport { PageFilters } from '../../types';\nimport { Group } from '@backstage-community/plugin-cost-insights-common';\nimport { getResetStateWithoutInitial } from '../../utils/loading';\n\ntype CostInsightsTabsFilterProps = PageFilters & {\n setGroup: (group: Group) => void;\n};\n\ntype CostInsightsTabsLoadingProps = {\n loadingActions: Array<string>;\n dispatchReset: (loadingActions: string[]) => void;\n};\n\nexport const mapFiltersToProps: MapFiltersToProps<\n CostInsightsTabsFilterProps\n> = ({ pageFilters, setPageFilters }) => ({\n ...pageFilters,\n setGroup: (group: Group) =>\n setPageFilters({\n ...pageFilters,\n group: group.id,\n project: null,\n }),\n});\n\nexport const mapLoadingToProps: MapLoadingToProps<\n CostInsightsTabsLoadingProps\n> = ({ actions, dispatch }) => ({\n loadingActions: actions,\n dispatchReset: (loadingActions: string[]) =>\n dispatch(getResetStateWithoutInitial(loadingActions)),\n});\n"],"names":[],"mappings":";;AA+BO,MAAM,iBAET,GAAA,CAAC,EAAE,WAAA,EAAa,gBAAsB,MAAA;AAAA,EACxC,GAAG,WAAA;AAAA,EACH,QAAA,EAAU,CAAC,KAAA,KACT,cAAe,CAAA;AAAA,IACb,GAAG,WAAA;AAAA,IACH,OAAO,KAAM,CAAA,EAAA;AAAA,IACb,OAAS,EAAA,IAAA;AAAA,GACV,CAAA;AACL,CAAA,EAAA;AAEO,MAAM,iBAET,GAAA,CAAC,EAAE,OAAA,EAAS,UAAgB,MAAA;AAAA,EAC9B,cAAgB,EAAA,OAAA;AAAA,EAChB,eAAe,CAAC,cAAA,KACd,QAAS,CAAA,2BAAA,CAA4B,cAAc,CAAC,CAAA;AACxD,CAAA;;;;"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { DateTime } from 'luxon';
|
|
3
|
+
import Box from '@material-ui/core/Box';
|
|
4
|
+
import Divider from '@material-ui/core/Divider';
|
|
5
|
+
import { emphasize } from '@material-ui/core/styles/colorManipulator';
|
|
6
|
+
import Typography from '@material-ui/core/Typography';
|
|
7
|
+
import { useTheme } from '@material-ui/core/styles';
|
|
8
|
+
import FullScreenIcon from '@material-ui/icons/Fullscreen';
|
|
9
|
+
import { ResponsiveContainer, AreaChart, CartesianGrid, XAxis, YAxis, Tooltip, Area } from 'recharts';
|
|
10
|
+
import '../../types/Alert.esm.js';
|
|
11
|
+
import { DEFAULT_DATE_FORMAT } from '../../types/DateFormat.esm.js';
|
|
12
|
+
import { useCostOverviewStyles } from '../../utils/styles.esm.js';
|
|
13
|
+
import '@material-ui/core/Paper';
|
|
14
|
+
import '@material-ui/core/Slide';
|
|
15
|
+
import '@material-ui/icons/ChevronLeft';
|
|
16
|
+
import '@material-ui/icons/ChevronRight';
|
|
17
|
+
import '../BarChart/BarChartStepperButton.esm.js';
|
|
18
|
+
import '@material-ui/core/ButtonBase';
|
|
19
|
+
import { BarChartTooltip } from '../BarChart/BarChartTooltip.esm.js';
|
|
20
|
+
import { BarChartTooltipItem } from '../BarChart/BarChartTooltipItem.esm.js';
|
|
21
|
+
import { formatPeriod } from '../../utils/formatters.esm.js';
|
|
22
|
+
import { overviewGraphTickFormatter, formatGraphValue, isInvalid } from '../../utils/graphs.esm.js';
|
|
23
|
+
import { useConfig } from '../../hooks/useConfig.esm.js';
|
|
24
|
+
import '../../hooks/useCurrency.esm.js';
|
|
25
|
+
import { useFilters } from '../../hooks/useFilters.esm.js';
|
|
26
|
+
import '../../hooks/useGroups.esm.js';
|
|
27
|
+
import '../../hooks/useLoading.esm.js';
|
|
28
|
+
import '../../hooks/useScroll.esm.js';
|
|
29
|
+
import { useLastCompleteBillingDate } from '../../hooks/useLastCompleteBillingDate.esm.js';
|
|
30
|
+
import { BarChartLegend } from '../BarChart/BarChartLegend.esm.js';
|
|
31
|
+
import { mapFiltersToProps } from './selector.esm.js';
|
|
32
|
+
import { getPreviousPeriodTotalCost } from '../../utils/change.esm.js';
|
|
33
|
+
import { aggregationSum } from '../../utils/sum.esm.js';
|
|
34
|
+
|
|
35
|
+
const LOW_COST_THRESHOLD = 0.1;
|
|
36
|
+
const CostOverviewBreakdownChart = ({
|
|
37
|
+
costBreakdown,
|
|
38
|
+
responsive = true
|
|
39
|
+
}) => {
|
|
40
|
+
const theme = useTheme();
|
|
41
|
+
const classes = useCostOverviewStyles(theme);
|
|
42
|
+
const { baseCurrency } = useConfig();
|
|
43
|
+
const lastCompleteBillingDate = useLastCompleteBillingDate();
|
|
44
|
+
const { duration } = useFilters(mapFiltersToProps);
|
|
45
|
+
const [isExpanded, setExpanded] = useState(false);
|
|
46
|
+
if (!costBreakdown) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const flattenedAggregation = costBreakdown.map((cost) => cost.aggregation).flat();
|
|
50
|
+
const totalCost = aggregationSum(flattenedAggregation);
|
|
51
|
+
const previousPeriodTotal = getPreviousPeriodTotalCost(
|
|
52
|
+
flattenedAggregation,
|
|
53
|
+
duration,
|
|
54
|
+
lastCompleteBillingDate
|
|
55
|
+
);
|
|
56
|
+
const currentPeriodTotal = totalCost - previousPeriodTotal;
|
|
57
|
+
const canExpand = costBreakdown.length >= 8;
|
|
58
|
+
const otherCategoryIds = [];
|
|
59
|
+
const breakdownsByDate = costBreakdown.reduce(
|
|
60
|
+
(breakdownByDate, breakdown) => {
|
|
61
|
+
const breakdownTotal = aggregationSum(breakdown.aggregation);
|
|
62
|
+
const isOtherCategory = canExpand && breakdownTotal < totalCost * LOW_COST_THRESHOLD;
|
|
63
|
+
const updatedBreakdownByDate = { ...breakdownByDate };
|
|
64
|
+
if (isOtherCategory) {
|
|
65
|
+
otherCategoryIds.push(breakdown.id);
|
|
66
|
+
}
|
|
67
|
+
breakdown.aggregation.forEach((curAggregation) => {
|
|
68
|
+
const costsForDate = updatedBreakdownByDate[curAggregation.date] || {};
|
|
69
|
+
updatedBreakdownByDate[curAggregation.date] = {
|
|
70
|
+
...costsForDate,
|
|
71
|
+
[breakdown.id]: (costsForDate[breakdown.id] || 0) + curAggregation.amount
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
return updatedBreakdownByDate;
|
|
75
|
+
},
|
|
76
|
+
{}
|
|
77
|
+
);
|
|
78
|
+
const chartData = Object.keys(breakdownsByDate).map((date) => {
|
|
79
|
+
const costsForDate = Object.keys(breakdownsByDate[date]).reduce(
|
|
80
|
+
(dateCosts, breakdown) => {
|
|
81
|
+
const cost = breakdownsByDate[date][breakdown];
|
|
82
|
+
const breakdownCost = !isExpanded && otherCategoryIds.includes(breakdown) ? { Other: (dateCosts.Other || 0) + cost } : { [breakdown]: cost };
|
|
83
|
+
return { ...dateCosts, ...breakdownCost };
|
|
84
|
+
},
|
|
85
|
+
{}
|
|
86
|
+
);
|
|
87
|
+
return {
|
|
88
|
+
...costsForDate,
|
|
89
|
+
date: Date.parse(date)
|
|
90
|
+
};
|
|
91
|
+
}).sort((a, b) => a.date - b.date);
|
|
92
|
+
const sortedBreakdowns = costBreakdown.sort(
|
|
93
|
+
(a, b) => aggregationSum(a.aggregation) - aggregationSum(b.aggregation)
|
|
94
|
+
);
|
|
95
|
+
const renderAreas = () => {
|
|
96
|
+
const separatedBreakdowns = sortedBreakdowns.filter(
|
|
97
|
+
(breakdown) => breakdown.id !== "Other" && !otherCategoryIds.includes(breakdown.id)
|
|
98
|
+
).map((breakdown) => breakdown.id);
|
|
99
|
+
const breakdownsToDisplay = isExpanded ? sortedBreakdowns.map((breakdown) => breakdown.id) : ["Other", ...separatedBreakdowns];
|
|
100
|
+
return breakdownsToDisplay.map((breakdown, i) => {
|
|
101
|
+
const color = theme.palette.dataViz[(breakdownsToDisplay.length - 1 - i) % (theme.palette.dataViz.length - 1)];
|
|
102
|
+
return /* @__PURE__ */ React.createElement(
|
|
103
|
+
Area,
|
|
104
|
+
{
|
|
105
|
+
key: breakdown,
|
|
106
|
+
dataKey: breakdown,
|
|
107
|
+
isAnimationActive: false,
|
|
108
|
+
stackId: "1",
|
|
109
|
+
stroke: color,
|
|
110
|
+
fill: color,
|
|
111
|
+
onClick: () => setExpanded(true),
|
|
112
|
+
style: {
|
|
113
|
+
cursor: breakdown === "Other" && !isExpanded ? "pointer" : void 0
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
const tooltipRenderer = ({ label, payload = [] }) => {
|
|
120
|
+
if (isInvalid({ label, payload })) return null;
|
|
121
|
+
const date = typeof label === "number" ? DateTime.fromMillis(label) : DateTime.fromISO(label);
|
|
122
|
+
const dateTitle = date.toUTC().toFormat(DEFAULT_DATE_FORMAT);
|
|
123
|
+
const formatGraphValueWith = formatGraphValue(baseCurrency);
|
|
124
|
+
const items = payload.map((p, i) => ({
|
|
125
|
+
label: p.dataKey,
|
|
126
|
+
value: formatGraphValueWith(Number(p.value), i),
|
|
127
|
+
fill: p.color
|
|
128
|
+
}));
|
|
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"
|
|
135
|
+
}
|
|
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
|
+
const options = {
|
|
141
|
+
previousName: formatPeriod(duration, lastCompleteBillingDate, false),
|
|
142
|
+
currentName: formatPeriod(duration, lastCompleteBillingDate, true),
|
|
143
|
+
hideMarker: true
|
|
144
|
+
};
|
|
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,
|
|
160
|
+
{
|
|
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 })
|
|
191
|
+
)
|
|
192
|
+
));
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export { CostOverviewBreakdownChart };
|
|
196
|
+
//# sourceMappingURL=CostOverviewBreakdownChart.esm.js.map
|
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import Box from '@material-ui/core/Box';
|
|
3
|
+
import { capitalize } from '@material-ui/core/utils';
|
|
4
|
+
import Card from '@material-ui/core/Card';
|
|
5
|
+
import CardContent from '@material-ui/core/CardContent';
|
|
6
|
+
import Divider from '@material-ui/core/Divider';
|
|
7
|
+
import Tab from '@material-ui/core/Tab';
|
|
8
|
+
import Tabs from '@material-ui/core/Tabs';
|
|
9
|
+
import { useTheme } from '@material-ui/core/styles';
|
|
10
|
+
import { CostOverviewChart } from './CostOverviewChart.esm.js';
|
|
11
|
+
import { CostOverviewBreakdownChart } from './CostOverviewBreakdownChart.esm.js';
|
|
12
|
+
import { CostOverviewHeader } from './CostOverviewHeader.esm.js';
|
|
13
|
+
import { MetricSelect } from '../MetricSelect/MetricSelect.esm.js';
|
|
14
|
+
import { PeriodSelect } from '../PeriodSelect/PeriodSelect.esm.js';
|
|
15
|
+
import { useConfig } from '../../hooks/useConfig.esm.js';
|
|
16
|
+
import '../../hooks/useCurrency.esm.js';
|
|
17
|
+
import { useFilters } from '../../hooks/useFilters.esm.js';
|
|
18
|
+
import '../../hooks/useGroups.esm.js';
|
|
19
|
+
import '../../hooks/useLoading.esm.js';
|
|
20
|
+
import '../../hooks/useScroll.esm.js';
|
|
21
|
+
import '../../hooks/useLastCompleteBillingDate.esm.js';
|
|
22
|
+
import { mapFiltersToProps } from './selector.esm.js';
|
|
23
|
+
import { DefaultNavigation } from '../../utils/navigation.esm.js';
|
|
24
|
+
import { findAlways } from '../../utils/assert.esm.js';
|
|
25
|
+
import { useOverviewTabsStyles } from '../../utils/styles.esm.js';
|
|
26
|
+
import { ScrollAnchor } from '../../utils/scroll.esm.js';
|
|
27
|
+
|
|
28
|
+
const CostOverviewCard = ({
|
|
29
|
+
dailyCostData,
|
|
30
|
+
metricData
|
|
31
|
+
}) => {
|
|
32
|
+
const theme = useTheme();
|
|
33
|
+
const styles = useOverviewTabsStyles(theme);
|
|
34
|
+
const config = useConfig();
|
|
35
|
+
const [tabIndex, setTabIndex] = useState(0);
|
|
36
|
+
const { setDuration, setProject, setMetric, ...filters } = useFilters(mapFiltersToProps);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const lastIndex = Object.keys(dailyCostData.groupedCosts ?? {}).length;
|
|
39
|
+
if (tabIndex > lastIndex) {
|
|
40
|
+
setTabIndex(0);
|
|
41
|
+
}
|
|
42
|
+
}, [dailyCostData, tabIndex, setTabIndex]);
|
|
43
|
+
const metric = filters.metric ? findAlways(config.metrics, (m) => m.kind === filters.metric) : null;
|
|
44
|
+
const breakdownTabs = Object.keys(dailyCostData.groupedCosts ?? {}).map(
|
|
45
|
+
(key) => ({
|
|
46
|
+
id: key,
|
|
47
|
+
label: `Breakdown by ${key}`,
|
|
48
|
+
title: `Cloud Cost By ${capitalize(key)}`
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
const tabs = [
|
|
52
|
+
{ id: "overview", label: "Total cost", title: "Cloud Cost" }
|
|
53
|
+
].concat(breakdownTabs);
|
|
54
|
+
const safeTabIndex = tabIndex > tabs.length - 1 ? 0 : tabIndex;
|
|
55
|
+
const OverviewTabs = () => {
|
|
56
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
57
|
+
Tabs,
|
|
58
|
+
{
|
|
59
|
+
indicatorColor: "primary",
|
|
60
|
+
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
|
+
));
|
|
74
|
+
};
|
|
75
|
+
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
|
+
))));
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export { CostOverviewCard };
|
|
99
|
+
//# sourceMappingURL=CostOverviewCard.esm.js.map
|
|
@@ -0,0 +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":"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"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DateTime } from 'luxon';
|
|
3
|
+
import Box from '@material-ui/core/Box';
|
|
4
|
+
import { useTheme } from '@material-ui/core/styles';
|
|
5
|
+
import { ResponsiveContainer, ComposedChart, CartesianGrid, XAxis, YAxis, Area, Line, Tooltip } from 'recharts';
|
|
6
|
+
import '../../types/Alert.esm.js';
|
|
7
|
+
import { DEFAULT_DATE_FORMAT } from '../../types/DateFormat.esm.js';
|
|
8
|
+
import '@material-ui/core/Typography';
|
|
9
|
+
import { useCostOverviewStyles } from '../../utils/styles.esm.js';
|
|
10
|
+
import '@material-ui/core/Paper';
|
|
11
|
+
import '@material-ui/core/Slide';
|
|
12
|
+
import '@material-ui/icons/ChevronLeft';
|
|
13
|
+
import '@material-ui/icons/ChevronRight';
|
|
14
|
+
import '../BarChart/BarChartStepperButton.esm.js';
|
|
15
|
+
import '@material-ui/core/ButtonBase';
|
|
16
|
+
import { BarChartTooltip } from '../BarChart/BarChartTooltip.esm.js';
|
|
17
|
+
import { BarChartTooltipItem } from '../BarChart/BarChartTooltipItem.esm.js';
|
|
18
|
+
import 'pluralize';
|
|
19
|
+
import '../../utils/duration.esm.js';
|
|
20
|
+
import { aggregationSort } from '../../utils/sort.esm.js';
|
|
21
|
+
import { overviewGraphTickFormatter, isInvalid, formatGraphValue } from '../../utils/graphs.esm.js';
|
|
22
|
+
import { useConfig } from '../../hooks/useConfig.esm.js';
|
|
23
|
+
import '../../hooks/useCurrency.esm.js';
|
|
24
|
+
import '../../hooks/useFilters.esm.js';
|
|
25
|
+
import '../../hooks/useGroups.esm.js';
|
|
26
|
+
import '../../hooks/useLoading.esm.js';
|
|
27
|
+
import '../../hooks/useScroll.esm.js';
|
|
28
|
+
import '../../hooks/useLastCompleteBillingDate.esm.js';
|
|
29
|
+
import '@material-ui/core/Tooltip';
|
|
30
|
+
import '@material-ui/icons/Lens';
|
|
31
|
+
import '@material-ui/icons/HelpOutlineOutlined';
|
|
32
|
+
import { groupByDate, trendFrom } from '../../utils/charts.esm.js';
|
|
33
|
+
import { CostOverviewLegend } from './CostOverviewLegend.esm.js';
|
|
34
|
+
|
|
35
|
+
const CostOverviewChart = ({
|
|
36
|
+
dailyCostData,
|
|
37
|
+
metric,
|
|
38
|
+
metricData,
|
|
39
|
+
responsive = true
|
|
40
|
+
}) => {
|
|
41
|
+
const theme = useTheme();
|
|
42
|
+
const styles = useCostOverviewStyles(theme);
|
|
43
|
+
const { baseCurrency, hideTrendLine } = useConfig();
|
|
44
|
+
const data = {
|
|
45
|
+
dailyCost: {
|
|
46
|
+
dataKey: "dailyCost",
|
|
47
|
+
name: `Daily Cost`,
|
|
48
|
+
format: "currency",
|
|
49
|
+
data: dailyCostData
|
|
50
|
+
},
|
|
51
|
+
metric: {
|
|
52
|
+
dataKey: metric?.kind ?? "Unknown",
|
|
53
|
+
name: metric?.name ?? "Unknown",
|
|
54
|
+
format: metricData?.format ?? "number",
|
|
55
|
+
data: metricData
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const metricsByDate = data.metric.data ? data.metric.data.aggregation.reduce(groupByDate, {}) : {};
|
|
59
|
+
const chartData = data.dailyCost.data.aggregation.slice().sort(aggregationSort).map((entry) => ({
|
|
60
|
+
date: Date.parse(entry.date),
|
|
61
|
+
trend: trendFrom(data.dailyCost.data.trendline, Date.parse(entry.date)),
|
|
62
|
+
dailyCost: entry.amount,
|
|
63
|
+
...metric && data.metric.data ? { [data.metric.dataKey]: metricsByDate[`${entry.date}`] } : {}
|
|
64
|
+
}));
|
|
65
|
+
const tooltipRenderer = ({ label, payload = [] }) => {
|
|
66
|
+
if (isInvalid({ label, payload })) return null;
|
|
67
|
+
const dataKeys = [data.dailyCost.dataKey, data.metric.dataKey];
|
|
68
|
+
const date = typeof label === "number" ? DateTime.fromMillis(label) : DateTime.fromISO(label);
|
|
69
|
+
const title = date.toUTC().toFormat(DEFAULT_DATE_FORMAT);
|
|
70
|
+
const formatGraphValueWith = formatGraphValue(baseCurrency);
|
|
71
|
+
const items = payload.filter((p) => dataKeys.includes(p.dataKey)).map((p, i) => ({
|
|
72
|
+
label: p.dataKey === data.dailyCost.dataKey ? data.dailyCost.name : data.metric.name,
|
|
73
|
+
value: p.dataKey === data.dailyCost.dataKey ? formatGraphValueWith(Number(p.value), i, data.dailyCost.format) : formatGraphValueWith(Number(p.value), i, data.metric.format),
|
|
74
|
+
fill: p.dataKey === data.dailyCost.dataKey ? theme.palette.blue : theme.palette.magenta
|
|
75
|
+
}));
|
|
76
|
+
return /* @__PURE__ */ React.createElement(BarChartTooltip, { title }, items.map((item, index) => /* @__PURE__ */ React.createElement(BarChartTooltipItem, { key: `${item.label}-${index}`, item })));
|
|
77
|
+
};
|
|
78
|
+
const localizedTickFormatter = formatGraphValue(baseCurrency);
|
|
79
|
+
return /* @__PURE__ */ React.createElement(Box, { display: "flex", flexDirection: "column" }, /* @__PURE__ */ React.createElement(
|
|
80
|
+
CostOverviewLegend,
|
|
81
|
+
{
|
|
82
|
+
dailyCostData,
|
|
83
|
+
metric,
|
|
84
|
+
metricData
|
|
85
|
+
}
|
|
86
|
+
), /* @__PURE__ */ React.createElement(
|
|
87
|
+
ResponsiveContainer,
|
|
88
|
+
{
|
|
89
|
+
width: responsive ? "100%" : styles.container.width,
|
|
90
|
+
height: styles.container.height,
|
|
91
|
+
className: "cost-overview-chart"
|
|
92
|
+
},
|
|
93
|
+
/* @__PURE__ */ React.createElement(ComposedChart, { margin: styles.chart.margin, data: chartData }, /* @__PURE__ */ React.createElement(CartesianGrid, { stroke: styles.cartesianGrid.stroke }), /* @__PURE__ */ React.createElement(
|
|
94
|
+
XAxis,
|
|
95
|
+
{
|
|
96
|
+
dataKey: "date",
|
|
97
|
+
domain: ["dataMin", "dataMax"],
|
|
98
|
+
tickFormatter: overviewGraphTickFormatter,
|
|
99
|
+
tickCount: 6,
|
|
100
|
+
type: "number",
|
|
101
|
+
stroke: styles.axis.fill
|
|
102
|
+
}
|
|
103
|
+
), /* @__PURE__ */ React.createElement(
|
|
104
|
+
YAxis,
|
|
105
|
+
{
|
|
106
|
+
domain: [() => 0, "dataMax"],
|
|
107
|
+
tick: { fill: styles.axis.fill },
|
|
108
|
+
tickFormatter: localizedTickFormatter,
|
|
109
|
+
width: styles.yAxis.width,
|
|
110
|
+
yAxisId: data.dailyCost.dataKey
|
|
111
|
+
}
|
|
112
|
+
), metric && /* @__PURE__ */ React.createElement(
|
|
113
|
+
YAxis,
|
|
114
|
+
{
|
|
115
|
+
domain: ["auto", "auto"],
|
|
116
|
+
width: styles.yAxis.width,
|
|
117
|
+
yAxisId: data.metric.dataKey,
|
|
118
|
+
tickFormatter: (value, index) => localizedTickFormatter(value, index, data.metric.format),
|
|
119
|
+
orientation: "right"
|
|
120
|
+
}
|
|
121
|
+
), /* @__PURE__ */ React.createElement(
|
|
122
|
+
Area,
|
|
123
|
+
{
|
|
124
|
+
dataKey: data.dailyCost.dataKey,
|
|
125
|
+
isAnimationActive: false,
|
|
126
|
+
fill: theme.palette.blue,
|
|
127
|
+
fillOpacity: 0.4,
|
|
128
|
+
stroke: "none",
|
|
129
|
+
yAxisId: data.dailyCost.dataKey
|
|
130
|
+
}
|
|
131
|
+
), !hideTrendLine && /* @__PURE__ */ React.createElement(
|
|
132
|
+
Line,
|
|
133
|
+
{
|
|
134
|
+
activeDot: false,
|
|
135
|
+
dataKey: "trend",
|
|
136
|
+
dot: false,
|
|
137
|
+
isAnimationActive: false,
|
|
138
|
+
strokeWidth: 2,
|
|
139
|
+
stroke: theme.palette.blue,
|
|
140
|
+
yAxisId: data.dailyCost.dataKey
|
|
141
|
+
}
|
|
142
|
+
), metric && /* @__PURE__ */ React.createElement(
|
|
143
|
+
Line,
|
|
144
|
+
{
|
|
145
|
+
dataKey: data.metric.dataKey,
|
|
146
|
+
dot: false,
|
|
147
|
+
isAnimationActive: false,
|
|
148
|
+
strokeWidth: 2,
|
|
149
|
+
stroke: theme.palette.magenta,
|
|
150
|
+
yAxisId: data.metric.dataKey
|
|
151
|
+
}
|
|
152
|
+
), /* @__PURE__ */ React.createElement(Tooltip, { content: tooltipRenderer, animationDuration: 100 }))
|
|
153
|
+
));
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export { CostOverviewChart };
|
|
157
|
+
//# sourceMappingURL=CostOverviewChart.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CostOverviewChart.esm.js","sources":["../../../src/components/CostOverviewCard/CostOverviewChart.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 from 'react';\nimport { DateTime } from 'luxon';\nimport Box from '@material-ui/core/Box';\nimport { useTheme } from '@material-ui/core/styles';\nimport {\n ComposedChart,\n XAxis,\n YAxis,\n Tooltip as RechartsTooltip,\n CartesianGrid,\n Area,\n Line,\n ResponsiveContainer,\n} from 'recharts';\nimport { ChartData, DEFAULT_DATE_FORMAT, CostInsightsTheme } from '../../types';\nimport {\n Cost,\n Maybe,\n Metric,\n MetricData,\n} from '@backstage-community/plugin-cost-insights-common';\nimport {\n BarChartTooltip as Tooltip,\n BarChartTooltipItem as TooltipItem,\n} from '../BarChart';\nimport {\n overviewGraphTickFormatter,\n formatGraphValue,\n isInvalid,\n} from '../../utils/graphs';\nimport { useCostOverviewStyles as useStyles } from '../../utils/styles';\nimport { groupByDate, trendFrom } from '../../utils/charts';\nimport { aggregationSort } from '../../utils/sort';\nimport { CostOverviewLegend } from './CostOverviewLegend';\nimport { TooltipRenderer } from '../../types';\nimport { useConfig } from '../../hooks';\n\ntype CostOverviewChartProps = {\n metric: Maybe<Metric>;\n metricData: Maybe<MetricData>;\n dailyCostData: Cost;\n responsive?: boolean;\n};\n\nexport const CostOverviewChart = ({\n dailyCostData,\n metric,\n metricData,\n responsive = true,\n}: CostOverviewChartProps) => {\n const theme = useTheme<CostInsightsTheme>();\n const styles = useStyles(theme);\n const { baseCurrency, hideTrendLine } = useConfig();\n\n const data = {\n dailyCost: {\n dataKey: 'dailyCost',\n name: `Daily Cost`,\n format: 'currency',\n data: dailyCostData,\n },\n metric: {\n dataKey: metric?.kind ?? 'Unknown',\n name: metric?.name ?? 'Unknown',\n format: metricData?.format ?? 'number',\n data: metricData,\n },\n };\n\n const metricsByDate = data.metric.data\n ? data.metric.data.aggregation.reduce(groupByDate, {})\n : {};\n\n const chartData: ChartData[] = data.dailyCost.data.aggregation\n .slice()\n .sort(aggregationSort)\n .map(entry => ({\n date: Date.parse(entry.date),\n trend: trendFrom(data.dailyCost.data.trendline!, Date.parse(entry.date)),\n dailyCost: entry.amount,\n ...(metric && data.metric.data\n ? { [data.metric.dataKey]: metricsByDate[`${entry.date}`] }\n : {}),\n }));\n\n const tooltipRenderer: TooltipRenderer = ({ label, payload = [] }) => {\n if (isInvalid({ label, payload })) return null;\n\n const dataKeys = [data.dailyCost.dataKey, data.metric.dataKey];\n const date =\n typeof label === 'number'\n ? DateTime.fromMillis(label)\n : DateTime.fromISO(label!);\n const title = date.toUTC().toFormat(DEFAULT_DATE_FORMAT);\n const formatGraphValueWith = formatGraphValue(baseCurrency);\n const items = payload\n .filter(p => dataKeys.includes(p.dataKey as string))\n .map((p, i) => ({\n label:\n p.dataKey === data.dailyCost.dataKey\n ? data.dailyCost.name\n : data.metric.name,\n value:\n p.dataKey === data.dailyCost.dataKey\n ? formatGraphValueWith(Number(p.value), i, data.dailyCost.format)\n : formatGraphValueWith(Number(p.value), i, data.metric.format),\n fill:\n p.dataKey === data.dailyCost.dataKey\n ? theme.palette.blue\n : theme.palette.magenta,\n }));\n\n return (\n <Tooltip title={title}>\n {items.map((item, index) => (\n <TooltipItem key={`${item.label}-${index}`} item={item} />\n ))}\n </Tooltip>\n );\n };\n\n const localizedTickFormatter = formatGraphValue(baseCurrency);\n\n return (\n <Box display=\"flex\" flexDirection=\"column\">\n <CostOverviewLegend\n dailyCostData={dailyCostData}\n metric={metric}\n metricData={metricData}\n />\n <ResponsiveContainer\n width={responsive ? '100%' : styles.container.width}\n height={styles.container.height}\n className=\"cost-overview-chart\"\n >\n <ComposedChart margin={styles.chart.margin} data={chartData}>\n <CartesianGrid stroke={styles.cartesianGrid.stroke} />\n <XAxis\n dataKey=\"date\"\n domain={['dataMin', 'dataMax']}\n tickFormatter={overviewGraphTickFormatter}\n tickCount={6}\n type=\"number\"\n stroke={styles.axis.fill}\n />\n <YAxis\n domain={[() => 0, 'dataMax']}\n tick={{ fill: styles.axis.fill }}\n tickFormatter={localizedTickFormatter}\n width={styles.yAxis.width}\n yAxisId={data.dailyCost.dataKey}\n />\n {metric && (\n <YAxis\n domain={['auto', 'auto']}\n width={styles.yAxis.width}\n yAxisId={data.metric.dataKey}\n tickFormatter={(value: any, index: number) =>\n localizedTickFormatter(value, index, data.metric.format)\n }\n orientation=\"right\"\n />\n )}\n <Area\n dataKey={data.dailyCost.dataKey}\n isAnimationActive={false}\n fill={theme.palette.blue}\n fillOpacity={0.4}\n stroke=\"none\"\n yAxisId={data.dailyCost.dataKey}\n />\n {!hideTrendLine && (\n <Line\n activeDot={false}\n dataKey=\"trend\"\n dot={false}\n isAnimationActive={false}\n strokeWidth={2}\n stroke={theme.palette.blue}\n yAxisId={data.dailyCost.dataKey}\n />\n )}\n {metric && (\n <Line\n dataKey={data.metric.dataKey}\n dot={false}\n isAnimationActive={false}\n strokeWidth={2}\n stroke={theme.palette.magenta}\n yAxisId={data.metric.dataKey}\n />\n )}\n <RechartsTooltip content={tooltipRenderer} animationDuration={100} />\n </ComposedChart>\n </ResponsiveContainer>\n </Box>\n );\n};\n"],"names":["useStyles","Tooltip","TooltipItem","RechartsTooltip"],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Box from '@material-ui/core/Box';
|
|
3
|
+
import Typography from '@material-ui/core/Typography';
|
|
4
|
+
|
|
5
|
+
const CostOverviewHeader = ({
|
|
6
|
+
title,
|
|
7
|
+
subtitle,
|
|
8
|
+
children
|
|
9
|
+
}) => /* @__PURE__ */ React.createElement(
|
|
10
|
+
Box,
|
|
11
|
+
{
|
|
12
|
+
mt: 2,
|
|
13
|
+
ml: 1,
|
|
14
|
+
mb: 1,
|
|
15
|
+
display: "flex",
|
|
16
|
+
flexDirection: "row",
|
|
17
|
+
justifyContent: "space-between",
|
|
18
|
+
alignItems: "center"
|
|
19
|
+
},
|
|
20
|
+
/* @__PURE__ */ React.createElement(Box, { minHeight: 40, paddingRight: 5 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5", gutterBottom: true }, title), !!subtitle && /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle2", color: "textSecondary", component: "div" }, subtitle)),
|
|
21
|
+
/* @__PURE__ */ React.createElement(Box, { minHeight: 40, maxHeight: 60, display: "flex" }, children)
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export { CostOverviewHeader };
|
|
25
|
+
//# sourceMappingURL=CostOverviewHeader.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CostOverviewHeader.esm.js","sources":["../../../src/components/CostOverviewCard/CostOverviewHeader.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, { PropsWithChildren } from 'react';\nimport Box from '@material-ui/core/Box';\nimport Typography from '@material-ui/core/Typography';\n\ntype CostOverviewHeaderProps = {\n title: string;\n subtitle?: string;\n};\n\nexport const CostOverviewHeader = ({\n title,\n subtitle,\n children,\n}: PropsWithChildren<CostOverviewHeaderProps>) => (\n <Box\n mt={2}\n ml={1}\n mb={1}\n display=\"flex\"\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n >\n <Box minHeight={40} paddingRight={5}>\n <Typography variant=\"h5\" gutterBottom>\n {title}\n </Typography>\n {!!subtitle && (\n <Typography variant=\"subtitle2\" color=\"textSecondary\" component=\"div\">\n {subtitle}\n </Typography>\n )}\n </Box>\n <Box minHeight={40} maxHeight={60} display=\"flex\">\n {children}\n </Box>\n </Box>\n);\n"],"names":[],"mappings":";;;;AAwBO,MAAM,qBAAqB,CAAC;AAAA,EACjC,KAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AACF,CACE,qBAAA,KAAA,CAAA,aAAA;AAAA,EAAC,GAAA;AAAA,EAAA;AAAA,IACC,EAAI,EAAA,CAAA;AAAA,IACJ,EAAI,EAAA,CAAA;AAAA,IACJ,EAAI,EAAA,CAAA;AAAA,IACJ,OAAQ,EAAA,MAAA;AAAA,IACR,aAAc,EAAA,KAAA;AAAA,IACd,cAAe,EAAA,eAAA;AAAA,IACf,UAAW,EAAA,QAAA;AAAA,GAAA;AAAA,kBAEX,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,SAAA,EAAW,EAAI,EAAA,YAAA,EAAc,CAChC,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,IAAK,EAAA,YAAA,EAAY,IAClC,EAAA,EAAA,KACH,GACC,CAAC,CAAC,QACD,oBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,WAAY,EAAA,KAAA,EAAM,eAAgB,EAAA,SAAA,EAAU,KAC7D,EAAA,EAAA,QACH,CAEJ,CAAA;AAAA,kBACA,KAAA,CAAA,aAAA,CAAC,OAAI,SAAW,EAAA,EAAA,EAAI,WAAW,EAAI,EAAA,OAAA,EAAQ,UACxC,QACH,CAAA;AACF;;;;"}
|