@backstage-community/plugin-cost-insights 0.12.29 → 0.13.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.
- package/CHANGELOG.md +11 -0
- package/dist/alerts/ProjectGrowthAlert.esm.js.map +1 -1
- package/dist/alerts/UnlabeledDataflowAlert.esm.js.map +1 -1
- package/dist/api/CostInsightsApi.esm.js.map +1 -1
- package/dist/components/ActionItems/ActionItemCard.esm.js.map +1 -1
- package/dist/components/ActionItems/ActionItems.esm.js.map +1 -1
- package/dist/components/AlertInsights/AlertDialog.esm.js.map +1 -1
- package/dist/components/AlertInsights/AlertInsights.esm.js.map +1 -1
- package/dist/components/AlertInsights/AlertInsightsHeader.esm.js.map +1 -1
- package/dist/components/AlertInsights/AlertInsightsSection.esm.js.map +1 -1
- package/dist/components/AlertInsights/AlertInsightsSectionHeader.esm.js.map +1 -1
- package/dist/components/AlertInsights/AlertStatusSummary.esm.js.map +1 -1
- package/dist/components/AlertInsights/AlertStatusSummaryButton.esm.js.map +1 -1
- package/dist/components/AlertInstructionsLayout/AlertInstructionsLayout.esm.js.map +1 -1
- package/dist/components/BarChart/BarChart.esm.js.map +1 -1
- package/dist/components/BarChart/BarChartLabel.esm.js.map +1 -1
- package/dist/components/BarChart/BarChartLegend.esm.js.map +1 -1
- package/dist/components/BarChart/BarChartStepper.esm.js.map +1 -1
- package/dist/components/BarChart/BarChartStepperButton.esm.js.map +1 -1
- package/dist/components/BarChart/BarChartSteps.esm.js.map +1 -1
- package/dist/components/BarChart/BarChartTick.esm.js.map +1 -1
- package/dist/components/BarChart/BarChartTooltip.esm.js.map +1 -1
- package/dist/components/BarChart/BarChartTooltipItem.esm.js.map +1 -1
- package/dist/components/CopyUrlToClipboard/CopyUrlToClipboard.esm.js.map +1 -1
- package/dist/components/CostGrowth/CostGrowth.esm.js.map +1 -1
- package/dist/components/CostGrowth/CostGrowthIndicator.esm.js.map +1 -1
- package/dist/components/CostInsightsHeader/CostInsightsHeader.esm.js.map +1 -1
- package/dist/components/CostInsightsLayout/CostInsightsLayout.esm.js.map +1 -1
- package/dist/components/CostInsightsNavigation/CostInsightsNavigation.esm.js.map +1 -1
- package/dist/components/CostInsightsPage/CostInsightsPage.esm.js.map +1 -1
- package/dist/components/CostInsightsPage/CostInsightsThemeProvider.esm.js.map +1 -1
- package/dist/components/CostInsightsPage/selector.esm.js.map +1 -1
- package/dist/components/CostInsightsTabs/CostInsightsTabs.esm.js.map +1 -1
- package/dist/components/CostInsightsTabs/selector.esm.js.map +1 -1
- package/dist/components/CostOverviewCard/CostOverviewBreakdownChart.esm.js.map +1 -1
- package/dist/components/CostOverviewCard/CostOverviewCard.esm.js.map +1 -1
- package/dist/components/CostOverviewCard/CostOverviewChart.esm.js.map +1 -1
- package/dist/components/CostOverviewCard/CostOverviewHeader.esm.js.map +1 -1
- package/dist/components/CostOverviewCard/CostOverviewLegend.esm.js.map +1 -1
- package/dist/components/CostOverviewCard/selector.esm.js.map +1 -1
- package/dist/components/CurrencySelect/CurrencySelect.esm.js.map +1 -1
- package/dist/components/EntityCosts/EntityCosts.esm.js.map +1 -1
- package/dist/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.esm.js.map +1 -1
- package/dist/components/LegendItem/LegendItem.esm.js.map +1 -1
- package/dist/components/MetricSelect/MetricSelect.esm.js.map +1 -1
- package/dist/components/PeriodSelect/PeriodSelect.esm.js.map +1 -1
- package/dist/components/ProductInsights/ProductInsights.esm.js.map +1 -1
- package/dist/components/ProductInsightsCard/ProductEntityDialog.esm.js.map +1 -1
- package/dist/components/ProductInsightsCard/ProductEntityTable.esm.js.map +1 -1
- package/dist/components/ProductInsightsCard/ProductInsightsCard.esm.js.map +1 -1
- package/dist/components/ProductInsightsCard/ProductInsightsCardList.esm.js.map +1 -1
- package/dist/components/ProductInsightsCard/ProductInsightsChart.esm.js.map +1 -1
- package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertCard.esm.js.map +1 -1
- package/dist/components/ProjectGrowthAlertCard/ProjectGrowthAlertChart.esm.js.map +1 -1
- package/dist/components/ProjectGrowthInstructionsPage/ProjectGrowthInstructionsPage.esm.js.map +1 -1
- package/dist/components/ProjectSelect/ProjectSelect.esm.js.map +1 -1
- package/dist/components/UnlabeledDataflowAlertCard/UnlabeledDataflowAlertCard.esm.js.map +1 -1
- package/dist/components/WhyCostsMatter/WhyCostsMatter.esm.js.map +1 -1
- package/dist/example/alerts/KubernetesMigrationAlert.esm.js.map +1 -1
- package/dist/example/client.esm.js.map +1 -1
- package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationAlertCard.esm.js.map +1 -1
- package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChart.esm.js.map +1 -1
- package/dist/example/components/KubernetesMigrationAlertCard/KubernetesMigrationBarChartLegend.esm.js.map +1 -1
- package/dist/example/forms/KubernetesMigrationDismissForm.esm.js.map +1 -1
- package/dist/forms/AlertAcceptForm.esm.js.map +1 -1
- package/dist/forms/AlertDismissForm.esm.js.map +1 -1
- package/dist/forms/AlertSnoozeForm.esm.js.map +1 -1
- package/dist/hooks/useConfig.esm.js.map +1 -1
- package/dist/hooks/useCurrency.esm.js.map +1 -1
- package/dist/hooks/useFilters.esm.js.map +1 -1
- package/dist/hooks/useGroups.esm.js.map +1 -1
- package/dist/hooks/useLastCompleteBillingDate.esm.js.map +1 -1
- package/dist/hooks/useLoading.esm.js.map +1 -1
- package/dist/hooks/useScroll.esm.js.map +1 -1
- package/dist/plugin.esm.js.map +1 -1
- package/dist/testUtils/filters.esm.js.map +1 -1
- package/dist/testUtils/loading.esm.js.map +1 -1
- package/dist/testUtils/mockData.esm.js.map +1 -1
- package/dist/testUtils/products.esm.js.map +1 -1
- package/dist/testUtils/providers.esm.js.map +1 -1
- package/dist/testUtils/testUtils.esm.js.map +1 -1
- package/dist/types/Alert.esm.js.map +1 -1
- package/dist/types/ChangeStatistic.esm.js.map +1 -1
- package/dist/types/CurrencyType.esm.js.map +1 -1
- package/dist/types/Duration.esm.js.map +1 -1
- package/dist/types/Icon.esm.js.map +1 -1
- package/dist/utils/alerts.esm.js.map +1 -1
- package/dist/utils/assert.esm.js.map +1 -1
- package/dist/utils/change.esm.js.map +1 -1
- package/dist/utils/charts.esm.js.map +1 -1
- package/dist/utils/config.esm.js.map +1 -1
- package/dist/utils/currency.esm.js.map +1 -1
- package/dist/utils/duration.esm.js.map +1 -1
- package/dist/utils/filters.esm.js.map +1 -1
- package/dist/utils/formatters.esm.js.map +1 -1
- package/dist/utils/grammar.esm.js.map +1 -1
- package/dist/utils/graphs.esm.js.map +1 -1
- package/dist/utils/history.esm.js.map +1 -1
- package/dist/utils/loading.esm.js.map +1 -1
- package/dist/utils/navigation.esm.js.map +1 -1
- package/dist/utils/scroll.esm.js.map +1 -1
- package/dist/utils/sort.esm.js.map +1 -1
- package/dist/utils/styles.esm.js.map +1 -1
- package/package.json +19 -12
|
@@ -1 +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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"}
|
|
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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"}
|
|
@@ -1 +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
|
|
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;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;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;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CostOverviewLegend.esm.js","sources":["../../../src/components/CostOverviewCard/CostOverviewLegend.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, { PropsWithChildren } from 'react';\nimport Box from '@material-ui/core/Box';\nimport { useTheme } from '@material-ui/core/styles';\nimport { LegendItem } from '../LegendItem';\nimport { CostInsightsTheme } from '../../types';\nimport {\n MetricData,\n Maybe,\n Cost,\n Metric,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { useLastCompleteBillingDate, useFilters } from '../../hooks';\nimport { getComparedChange, choose } from '../../utils/change';\nimport { mapFiltersToProps } from './selector';\nimport { formatChange } from '../../utils/formatters';\nimport { CostGrowth } from '../CostGrowth';\n\ntype CostOverviewLegendProps = {\n metric: Maybe<Metric>;\n metricData: Maybe<MetricData>;\n dailyCostData: Cost;\n};\n\nexport const CostOverviewLegend = ({\n dailyCostData,\n metric,\n metricData,\n}: PropsWithChildren<CostOverviewLegendProps>) => {\n const theme = useTheme<CostInsightsTheme>();\n const { duration } = useFilters(mapFiltersToProps);\n const lastCompleteBillingDate = useLastCompleteBillingDate();\n\n const comparedChange = metricData\n ? getComparedChange(\n dailyCostData,\n metricData,\n duration,\n lastCompleteBillingDate,\n )\n : null;\n\n return (\n <Box display=\"flex\" flexDirection=\"row\">\n {dailyCostData.change && (\n <Box mr={2}>\n <LegendItem title=\"Cost Trend\" markerColor={theme.palette.blue}>\n {formatChange(dailyCostData.change)}\n </LegendItem>\n </Box>\n )}\n {metricData && metric && comparedChange && (\n <>\n <Box mr={2}>\n <LegendItem\n title={`${metric.name} Trend`}\n markerColor={theme.palette.magenta}\n >\n {formatChange(metricData.change)}\n </LegendItem>\n </Box>\n <LegendItem\n title={choose(['Your Savings', 'Your Excess'], comparedChange)}\n >\n <CostGrowth change={comparedChange} duration={duration} />\n </LegendItem>\n </>\n )}\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuCO,MAAM,qBAAqB,CAAC;AAAA,EACjC,aAAA;AAAA,EACA,MAAA;AAAA,EACA
|
|
1
|
+
{"version":3,"file":"CostOverviewLegend.esm.js","sources":["../../../src/components/CostOverviewCard/CostOverviewLegend.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, { PropsWithChildren } from 'react';\nimport Box from '@material-ui/core/Box';\nimport { useTheme } from '@material-ui/core/styles';\nimport { LegendItem } from '../LegendItem';\nimport { CostInsightsTheme } from '../../types';\nimport {\n MetricData,\n Maybe,\n Cost,\n Metric,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { useLastCompleteBillingDate, useFilters } from '../../hooks';\nimport { getComparedChange, choose } from '../../utils/change';\nimport { mapFiltersToProps } from './selector';\nimport { formatChange } from '../../utils/formatters';\nimport { CostGrowth } from '../CostGrowth';\n\ntype CostOverviewLegendProps = {\n metric: Maybe<Metric>;\n metricData: Maybe<MetricData>;\n dailyCostData: Cost;\n};\n\nexport const CostOverviewLegend = ({\n dailyCostData,\n metric,\n metricData,\n}: PropsWithChildren<CostOverviewLegendProps>) => {\n const theme = useTheme<CostInsightsTheme>();\n const { duration } = useFilters(mapFiltersToProps);\n const lastCompleteBillingDate = useLastCompleteBillingDate();\n\n const comparedChange = metricData\n ? getComparedChange(\n dailyCostData,\n metricData,\n duration,\n lastCompleteBillingDate,\n )\n : null;\n\n return (\n <Box display=\"flex\" flexDirection=\"row\">\n {dailyCostData.change && (\n <Box mr={2}>\n <LegendItem title=\"Cost Trend\" markerColor={theme.palette.blue}>\n {formatChange(dailyCostData.change)}\n </LegendItem>\n </Box>\n )}\n {metricData && metric && comparedChange && (\n <>\n <Box mr={2}>\n <LegendItem\n title={`${metric.name} Trend`}\n markerColor={theme.palette.magenta}\n >\n {formatChange(metricData.change)}\n </LegendItem>\n </Box>\n <LegendItem\n title={choose(['Your Savings', 'Your Excess'], comparedChange)}\n >\n <CostGrowth change={comparedChange} duration={duration} />\n </LegendItem>\n </>\n )}\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuCO,MAAM,qBAAqB,CAAC;AAAA,EACjC,aAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAkD,KAAA;AAChD,EAAA,MAAM,QAAQ,QAA4B,EAAA;AAC1C,EAAA,MAAM,EAAE,QAAA,EAAa,GAAA,UAAA,CAAW,iBAAiB,CAAA;AACjD,EAAA,MAAM,0BAA0B,0BAA2B,EAAA;AAE3D,EAAA,MAAM,iBAAiB,UACnB,GAAA,iBAAA;AAAA,IACE,aAAA;AAAA,IACA,UAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GAEF,GAAA,IAAA;AAEJ,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,OAAQ,EAAA,MAAA,EAAO,eAAc,KAC/B,EAAA,EAAA,aAAA,CAAc,MACb,oBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,EAAA,EAAI,CACP,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAW,KAAM,EAAA,YAAA,EAAa,WAAa,EAAA,KAAA,CAAM,OAAQ,CAAA,IAAA,EAAA,EACvD,YAAa,CAAA,aAAA,CAAc,MAAM,CACpC,CACF,CAED,EAAA,UAAA,IAAc,UAAU,cACvB,oBAAA,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBACG,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,IAAI,CACP,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAG,EAAA,MAAA,CAAO,IAAI,CAAA,MAAA,CAAA;AAAA,MACrB,WAAA,EAAa,MAAM,OAAQ,CAAA;AAAA,KAAA;AAAA,IAE1B,YAAA,CAAa,WAAW,MAAM;AAAA,GAEnC,CACA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,OAAO,MAAO,CAAA,CAAC,cAAgB,EAAA,aAAa,GAAG,cAAc;AAAA,KAAA;AAAA,oBAE5D,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,MAAQ,EAAA,cAAA,EAAgB,QAAoB,EAAA;AAAA,GAE5D,CAEJ,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selector.esm.js","sources":["../../../src/components/CostOverviewCard/selector.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 { Duration, PageFilters } from '../../types';\nimport { Maybe } from '@backstage-community/plugin-cost-insights-common';\nimport { MapFiltersToProps } from '../../hooks/useFilters';\n\ntype CostOverviewFilterProps = PageFilters & {\n setDuration: (duration: Duration) => void;\n setProject: (project: Maybe<string>) => void;\n setMetric: (metric: Maybe<string>) => void;\n};\n\nexport const mapFiltersToProps: MapFiltersToProps<CostOverviewFilterProps> = ({\n pageFilters,\n setPageFilters,\n}) => ({\n ...pageFilters,\n project: pageFilters.project || 'all',\n setDuration: (duration: Duration) =>\n setPageFilters({\n ...pageFilters,\n duration,\n }),\n setProject: (project: Maybe<string>) =>\n setPageFilters({\n ...pageFilters,\n project: project === 'all' ? null : project,\n }),\n setMetric: (metric: Maybe<string>) =>\n setPageFilters({\n ...pageFilters,\n metric: metric,\n }),\n});\n"],"names":[],"mappings":"AAyBO,MAAM,oBAAgE,CAAC;AAAA,EAC5E,WAAA;AAAA,EACA
|
|
1
|
+
{"version":3,"file":"selector.esm.js","sources":["../../../src/components/CostOverviewCard/selector.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 { Duration, PageFilters } from '../../types';\nimport { Maybe } from '@backstage-community/plugin-cost-insights-common';\nimport { MapFiltersToProps } from '../../hooks/useFilters';\n\ntype CostOverviewFilterProps = PageFilters & {\n setDuration: (duration: Duration) => void;\n setProject: (project: Maybe<string>) => void;\n setMetric: (metric: Maybe<string>) => void;\n};\n\nexport const mapFiltersToProps: MapFiltersToProps<CostOverviewFilterProps> = ({\n pageFilters,\n setPageFilters,\n}) => ({\n ...pageFilters,\n project: pageFilters.project || 'all',\n setDuration: (duration: Duration) =>\n setPageFilters({\n ...pageFilters,\n duration,\n }),\n setProject: (project: Maybe<string>) =>\n setPageFilters({\n ...pageFilters,\n project: project === 'all' ? null : project,\n }),\n setMetric: (metric: Maybe<string>) =>\n setPageFilters({\n ...pageFilters,\n metric: metric,\n }),\n});\n"],"names":[],"mappings":"AAyBO,MAAM,oBAAgE,CAAC;AAAA,EAC5E,WAAA;AAAA,EACA;AACF,CAAO,MAAA;AAAA,EACL,GAAG,WAAA;AAAA,EACH,OAAA,EAAS,YAAY,OAAW,IAAA,KAAA;AAAA,EAChC,WAAA,EAAa,CAAC,QAAA,KACZ,cAAe,CAAA;AAAA,IACb,GAAG,WAAA;AAAA,IACH;AAAA,GACD,CAAA;AAAA,EACH,UAAA,EAAY,CAAC,OAAA,KACX,cAAe,CAAA;AAAA,IACb,GAAG,WAAA;AAAA,IACH,OAAA,EAAS,OAAY,KAAA,KAAA,GAAQ,IAAO,GAAA;AAAA,GACrC,CAAA;AAAA,EACH,SAAA,EAAW,CAAC,MAAA,KACV,cAAe,CAAA;AAAA,IACb,GAAG,WAAA;AAAA,IACH;AAAA,GACD;AACL,CAAA;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CurrencySelect.esm.js","sources":["../../../src/components/CurrencySelect/CurrencySelect.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport Select, { SelectProps } from '@material-ui/core/Select';\nimport FormControl from '@material-ui/core/FormControl';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Typography from '@material-ui/core/Typography';\nimport { Currency, CurrencyType } from '../../types';\nimport { findAlways } from '../../utils/assert';\nimport { useSelectStyles as useStyles } from '../../utils/styles';\n\nconst NULL_VALUE = 'engineers';\n\ntype CurrencySelectProps = {\n currency: Currency;\n currencies: Currency[];\n onSelect: (currency: Currency) => void;\n};\n\nexport const CurrencySelect = ({\n currency,\n currencies,\n onSelect,\n}: CurrencySelectProps) => {\n const classes = useStyles();\n\n const getOption = (value: unknown) => {\n const kind = (value === NULL_VALUE ? null : value) as CurrencyType;\n return findAlways(currencies, c => c.kind === kind);\n };\n\n const handleOnChange: SelectProps['onChange'] = e => {\n const option = getOption(e.target.value);\n onSelect(option);\n };\n\n const renderValue: SelectProps['renderValue'] = value => {\n const option = getOption(value);\n return <b>{option.label}</b>;\n };\n\n return (\n <FormControl variant=\"outlined\">\n <InputLabel shrink>Convert to:</InputLabel>\n <Select\n className={classes.select}\n variant=\"outlined\"\n labelWidth={100}\n onChange={handleOnChange}\n value={currency.kind || NULL_VALUE}\n renderValue={renderValue}\n >\n {currencies.map((c: Currency) => (\n <MenuItem\n className={classes.menuItem}\n key={c.kind || NULL_VALUE}\n value={c.kind || NULL_VALUE}\n >\n <Typography component=\"span\" role=\"img\" aria-label={c.label}>\n {c.label}\n </Typography>\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n );\n};\n"],"names":["useStyles"],"mappings":";;;;;;;;;AA0BA,MAAM,UAAa,GAAA,WAAA
|
|
1
|
+
{"version":3,"file":"CurrencySelect.esm.js","sources":["../../../src/components/CurrencySelect/CurrencySelect.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport Select, { SelectProps } from '@material-ui/core/Select';\nimport FormControl from '@material-ui/core/FormControl';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Typography from '@material-ui/core/Typography';\nimport { Currency, CurrencyType } from '../../types';\nimport { findAlways } from '../../utils/assert';\nimport { useSelectStyles as useStyles } from '../../utils/styles';\n\nconst NULL_VALUE = 'engineers';\n\ntype CurrencySelectProps = {\n currency: Currency;\n currencies: Currency[];\n onSelect: (currency: Currency) => void;\n};\n\nexport const CurrencySelect = ({\n currency,\n currencies,\n onSelect,\n}: CurrencySelectProps) => {\n const classes = useStyles();\n\n const getOption = (value: unknown) => {\n const kind = (value === NULL_VALUE ? null : value) as CurrencyType;\n return findAlways(currencies, c => c.kind === kind);\n };\n\n const handleOnChange: SelectProps['onChange'] = e => {\n const option = getOption(e.target.value);\n onSelect(option);\n };\n\n const renderValue: SelectProps['renderValue'] = value => {\n const option = getOption(value);\n return <b>{option.label}</b>;\n };\n\n return (\n <FormControl variant=\"outlined\">\n <InputLabel shrink>Convert to:</InputLabel>\n <Select\n className={classes.select}\n variant=\"outlined\"\n labelWidth={100}\n onChange={handleOnChange}\n value={currency.kind || NULL_VALUE}\n renderValue={renderValue}\n >\n {currencies.map((c: Currency) => (\n <MenuItem\n className={classes.menuItem}\n key={c.kind || NULL_VALUE}\n value={c.kind || NULL_VALUE}\n >\n <Typography component=\"span\" role=\"img\" aria-label={c.label}>\n {c.label}\n </Typography>\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n );\n};\n"],"names":["useStyles"],"mappings":";;;;;;;;;AA0BA,MAAM,UAAa,GAAA,WAAA;AAQZ,MAAM,iBAAiB,CAAC;AAAA,EAC7B,QAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAA2B,KAAA;AACzB,EAAA,MAAM,UAAUA,eAAU,EAAA;AAE1B,EAAM,MAAA,SAAA,GAAY,CAAC,KAAmB,KAAA;AACpC,IAAM,MAAA,IAAA,GAAQ,KAAU,KAAA,UAAA,GAAa,IAAO,GAAA,KAAA;AAC5C,IAAA,OAAO,UAAW,CAAA,UAAA,EAAY,CAAK,CAAA,KAAA,CAAA,CAAE,SAAS,IAAI,CAAA;AAAA,GACpD;AAEA,EAAA,MAAM,iBAA0C,CAAK,CAAA,KAAA;AACnD,IAAA,MAAM,MAAS,GAAA,SAAA,CAAU,CAAE,CAAA,MAAA,CAAO,KAAK,CAAA;AACvC,IAAA,QAAA,CAAS,MAAM,CAAA;AAAA,GACjB;AAEA,EAAA,MAAM,cAA0C,CAAS,KAAA,KAAA;AACvD,IAAM,MAAA,MAAA,GAAS,UAAU,KAAK,CAAA;AAC9B,IAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,GAAG,EAAA,IAAA,EAAA,MAAA,CAAO,KAAM,CAAA;AAAA,GAC1B;AAEA,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,eAAY,OAAQ,EAAA,UAAA,EAAA,sCAClB,UAAW,EAAA,EAAA,MAAA,EAAM,IAAC,EAAA,EAAA,aAAW,CAC9B,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,WAAW,OAAQ,CAAA,MAAA;AAAA,MACnB,OAAQ,EAAA,UAAA;AAAA,MACR,UAAY,EAAA,GAAA;AAAA,MACZ,QAAU,EAAA,cAAA;AAAA,MACV,KAAA,EAAO,SAAS,IAAQ,IAAA,UAAA;AAAA,MACxB;AAAA,KAAA;AAAA,IAEC,UAAA,CAAW,GAAI,CAAA,CAAC,CACf,qBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,WAAW,OAAQ,CAAA,QAAA;AAAA,QACnB,GAAA,EAAK,EAAE,IAAQ,IAAA,UAAA;AAAA,QACf,KAAA,EAAO,EAAE,IAAQ,IAAA;AAAA,OAAA;AAAA,sBAEjB,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAU,MAAO,EAAA,IAAA,EAAK,OAAM,YAAY,EAAA,CAAA,CAAE,KACnD,EAAA,EAAA,CAAA,CAAE,KACL;AAAA,KAEH;AAAA,GAEL,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityCosts.esm.js","sources":["../../../src/components/EntityCosts/EntityCosts.tsx"],"sourcesContent":["/*\n * Copyright 2022 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, { useCallback, useEffect, useState } from 'react';\nimport { CostOverviewCard } from '../CostOverviewCard';\nimport {\n BillingDateProvider,\n ConfigProvider,\n CurrencyProvider,\n FilterProvider,\n GroupsProvider,\n LoadingProvider,\n ScrollProvider,\n useFilters,\n useLastCompleteBillingDate,\n useLoading,\n} from '../../hooks';\nimport { CostInsightsThemeProvider } from '../CostInsightsPage/CostInsightsThemeProvider';\nimport { Progress, WarningPanel } from '@backstage/core-components';\nimport { default as MaterialAlert } from '@material-ui/lab/Alert';\nimport { mapLoadingToProps } from '../CostInsightsPage/selector';\nimport { intervalsOf } from '../../utils/duration';\nimport { costInsightsApiRef } from '../../api';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { Cost, Maybe } from '@backstage-community/plugin-cost-insights-common';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\n\nexport const EntityCostsCard = () => {\n const client = useApi(costInsightsApiRef);\n const { entity } = useEntity();\n\n const {\n loadingActions,\n loadingGroups,\n loadingBillingDate,\n loadingInitial,\n dispatchInitial,\n dispatchInsights,\n dispatchNone,\n } = useLoading(mapLoadingToProps);\n\n /* eslint-disable react-hooks/exhaustive-deps */\n // The dispatchLoading functions are derived from loading state using mapLoadingToProps, to\n // provide nicer props for the component. These are re-derived whenever loading state changes,\n // which causes an infinite loop as product panels load and re-trigger the useEffect below.\n // Since the functions don't change, we can memoize - but we trigger the same loop if we satisfy\n // exhaustive-deps by including the function itself in dependencies.\n\n const dispatchLoadingInitial = useCallback(dispatchInitial, []);\n const dispatchLoadingInsights = useCallback(dispatchInsights, []);\n const dispatchLoadingNone = useCallback(dispatchNone, []);\n /* eslint-enable react-hooks/exhaustive-deps */\n\n const lastCompleteBillingDate = useLastCompleteBillingDate();\n const [dailyCost, setDailyCost] = useState<Maybe<Cost>>(null);\n const [error, setError] = useState<Maybe<Error>>(null);\n const { pageFilters } = useFilters(p => p);\n\n useEffect(() => {\n async function getInsights() {\n setError(null);\n try {\n dispatchLoadingInsights(true);\n const intervals = intervalsOf(\n pageFilters.duration,\n lastCompleteBillingDate,\n );\n\n const fetchedDailyCost = await client.getCatalogEntityDailyCost!(\n stringifyEntityRef(entity),\n intervals,\n );\n setDailyCost(fetchedDailyCost);\n } catch (e) {\n setError(e);\n dispatchLoadingNone(loadingActions);\n } finally {\n dispatchLoadingNone(loadingActions);\n dispatchLoadingInitial(false);\n dispatchLoadingInsights(false);\n }\n }\n\n // Wait for metadata to finish loading\n if (!loadingBillingDate) {\n getInsights();\n }\n }, [\n client,\n entity,\n pageFilters,\n loadingActions,\n loadingGroups,\n loadingBillingDate,\n dispatchLoadingInsights,\n dispatchLoadingInitial,\n dispatchLoadingNone,\n lastCompleteBillingDate,\n ]);\n\n if (loadingInitial) {\n return <Progress />;\n }\n\n if (error) {\n return <MaterialAlert severity=\"error\">{error.message}</MaterialAlert>;\n }\n\n if (!dailyCost || !dailyCost.aggregation.length) {\n return <MaterialAlert severity=\"error\">No daily costs</MaterialAlert>;\n }\n\n return <CostOverviewCard dailyCostData={dailyCost} metricData={null} />;\n};\n\nexport const EntityCosts = () => {\n const client = useApi(costInsightsApiRef);\n\n if (!client.getCatalogEntityDailyCost) {\n return (\n <WarningPanel\n title=\"Could display costs for entity\"\n message=\"The getCatalogEntityDailyCost() method is not implemented by the costInsightsApi.\"\n />\n );\n }\n\n return (\n <CostInsightsThemeProvider>\n <ConfigProvider>\n <LoadingProvider>\n <GroupsProvider>\n <BillingDateProvider>\n <FilterProvider>\n <ScrollProvider>\n <CurrencyProvider>\n <EntityCostsCard />\n </CurrencyProvider>\n </ScrollProvider>\n </FilterProvider>\n </BillingDateProvider>\n </GroupsProvider>\n </LoadingProvider>\n </ConfigProvider>\n </CostInsightsThemeProvider>\n );\n};\n"],"names":["MaterialAlert"],"mappings":";;;;;;;;;;;;;;;;;;;AAyCO,MAAM,kBAAkB,MAAM;AACnC,EAAM,MAAA,MAAA,GAAS,OAAO,kBAAkB,CAAA
|
|
1
|
+
{"version":3,"file":"EntityCosts.esm.js","sources":["../../../src/components/EntityCosts/EntityCosts.tsx"],"sourcesContent":["/*\n * Copyright 2022 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, { useCallback, useEffect, useState } from 'react';\nimport { CostOverviewCard } from '../CostOverviewCard';\nimport {\n BillingDateProvider,\n ConfigProvider,\n CurrencyProvider,\n FilterProvider,\n GroupsProvider,\n LoadingProvider,\n ScrollProvider,\n useFilters,\n useLastCompleteBillingDate,\n useLoading,\n} from '../../hooks';\nimport { CostInsightsThemeProvider } from '../CostInsightsPage/CostInsightsThemeProvider';\nimport { Progress, WarningPanel } from '@backstage/core-components';\nimport { default as MaterialAlert } from '@material-ui/lab/Alert';\nimport { mapLoadingToProps } from '../CostInsightsPage/selector';\nimport { intervalsOf } from '../../utils/duration';\nimport { costInsightsApiRef } from '../../api';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { Cost, Maybe } from '@backstage-community/plugin-cost-insights-common';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\n\nexport const EntityCostsCard = () => {\n const client = useApi(costInsightsApiRef);\n const { entity } = useEntity();\n\n const {\n loadingActions,\n loadingGroups,\n loadingBillingDate,\n loadingInitial,\n dispatchInitial,\n dispatchInsights,\n dispatchNone,\n } = useLoading(mapLoadingToProps);\n\n /* eslint-disable react-hooks/exhaustive-deps */\n // The dispatchLoading functions are derived from loading state using mapLoadingToProps, to\n // provide nicer props for the component. These are re-derived whenever loading state changes,\n // which causes an infinite loop as product panels load and re-trigger the useEffect below.\n // Since the functions don't change, we can memoize - but we trigger the same loop if we satisfy\n // exhaustive-deps by including the function itself in dependencies.\n\n const dispatchLoadingInitial = useCallback(dispatchInitial, []);\n const dispatchLoadingInsights = useCallback(dispatchInsights, []);\n const dispatchLoadingNone = useCallback(dispatchNone, []);\n /* eslint-enable react-hooks/exhaustive-deps */\n\n const lastCompleteBillingDate = useLastCompleteBillingDate();\n const [dailyCost, setDailyCost] = useState<Maybe<Cost>>(null);\n const [error, setError] = useState<Maybe<Error>>(null);\n const { pageFilters } = useFilters(p => p);\n\n useEffect(() => {\n async function getInsights() {\n setError(null);\n try {\n dispatchLoadingInsights(true);\n const intervals = intervalsOf(\n pageFilters.duration,\n lastCompleteBillingDate,\n );\n\n const fetchedDailyCost = await client.getCatalogEntityDailyCost!(\n stringifyEntityRef(entity),\n intervals,\n );\n setDailyCost(fetchedDailyCost);\n } catch (e) {\n setError(e);\n dispatchLoadingNone(loadingActions);\n } finally {\n dispatchLoadingNone(loadingActions);\n dispatchLoadingInitial(false);\n dispatchLoadingInsights(false);\n }\n }\n\n // Wait for metadata to finish loading\n if (!loadingBillingDate) {\n getInsights();\n }\n }, [\n client,\n entity,\n pageFilters,\n loadingActions,\n loadingGroups,\n loadingBillingDate,\n dispatchLoadingInsights,\n dispatchLoadingInitial,\n dispatchLoadingNone,\n lastCompleteBillingDate,\n ]);\n\n if (loadingInitial) {\n return <Progress />;\n }\n\n if (error) {\n return <MaterialAlert severity=\"error\">{error.message}</MaterialAlert>;\n }\n\n if (!dailyCost || !dailyCost.aggregation.length) {\n return <MaterialAlert severity=\"error\">No daily costs</MaterialAlert>;\n }\n\n return <CostOverviewCard dailyCostData={dailyCost} metricData={null} />;\n};\n\nexport const EntityCosts = () => {\n const client = useApi(costInsightsApiRef);\n\n if (!client.getCatalogEntityDailyCost) {\n return (\n <WarningPanel\n title=\"Could display costs for entity\"\n message=\"The getCatalogEntityDailyCost() method is not implemented by the costInsightsApi.\"\n />\n );\n }\n\n return (\n <CostInsightsThemeProvider>\n <ConfigProvider>\n <LoadingProvider>\n <GroupsProvider>\n <BillingDateProvider>\n <FilterProvider>\n <ScrollProvider>\n <CurrencyProvider>\n <EntityCostsCard />\n </CurrencyProvider>\n </ScrollProvider>\n </FilterProvider>\n </BillingDateProvider>\n </GroupsProvider>\n </LoadingProvider>\n </ConfigProvider>\n </CostInsightsThemeProvider>\n );\n};\n"],"names":["MaterialAlert"],"mappings":"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"}
|
package/dist/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LabelDataflowInstructionsPage.esm.js","sources":["../../../src/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport Box from '@material-ui/core/Box';\nimport Typography from '@material-ui/core/Typography';\nimport { AlertInstructionsLayout } from '../AlertInstructionsLayout';\nimport { CodeSnippet, Link } from '@backstage/core-components';\n\nexport const LabelDataflowInstructionsPage = () => {\n return (\n <AlertInstructionsLayout title=\"Investigating Growth\">\n <Typography variant=\"h1\">Labeling Dataflow Jobs</Typography>\n <Typography paragraph>\n Labels in Google Cloud Platform are key-value pairs that can be added to\n most types of cloud resources. Since these labels are also exported in\n billing data, adding labels allows a granular breakdown of cloud cost by\n software entity.\n </Typography>\n <Typography paragraph>\n In Cloud Dataflow, labels can be added to a job either programmatically\n or via the command-line when launching a job. Note that GCP has{' '}\n <Link to=\"https://cloud.google.com/compute/docs/labeling-resources#restrictions\">\n restrictions\n </Link>{' '}\n on the length and characters that can be used in labels.\n </Typography>\n <Typography paragraph>\n Labels are not retroactive, so cost tracking is only possible from when\n the labels are first added to a Dataflow job.\n </Typography>\n\n <Box mt={4}>\n <Typography variant=\"h3\">DataflowPipelineOptions</Typography>\n <Typography paragraph>\n Dataflow jobs using Beam's{' '}\n <Link to=\"https://beam.apache.org/releases/javadoc/2.3.0/org/apache/beam/runners/dataflow/options/DataflowPipelineOptions.html\">\n DataflowPipelineOptions\n </Link>{' '}\n directly can use the <b>setLabels</b> function to add one or more\n labels:\n <CodeSnippet\n language=\"java\"\n text={`private DataflowPipelineOptions options = PipelineOptionsFactory.fromArgs(args).as(DataflowPipelineOptionsImpl.class); \noptions.setLabels(ImmutableMap.of(\"job-id\", \"my-dataflow-job\"));`}\n />\n </Typography>\n <Typography paragraph>\n Dataflow jobs using Scio can similarly set options on the ScioContext:\n <CodeSnippet\n language=\"scala\"\n text={`val (sc: ScioContext, args: Args) = ContextAndArgs(cmdLineArgs)\nsc.optionsAs[DataflowPipelineOptions].setLabels(Map(\"job-id\" -> \"my-dataflow-job\").asJava)`}\n />\n </Typography>\n </Box>\n\n <Box mt={4}>\n <Typography variant=\"h3\">Command-line</Typography>\n <Typography paragraph>\n Dataflow jobs launched from the command-line can add labels as an\n argument:\n <CodeSnippet\n language=\"shell\"\n text={`--labels={\"job-id\": \"my-dataflow-job\", \"date-argument\": \"2020-09-16\"}`}\n />\n </Typography>\n <Typography paragraph>\n For more information on specifying options, see the{' '}\n <Link to=\"https://cloud.google.com/dataflow/docs/guides/specifying-exec-params\">\n Dataflow documentation\n </Link>{' '}\n or{' '}\n <Link to=\"https://spotify.github.io/scio/api/com/spotify/scio/ScioContext.html\">\n Scio Scaladoc\n </Link>\n .\n </Typography>\n </Box>\n </AlertInstructionsLayout>\n );\n};\n"],"names":[],"mappings":";;;;;;AAsBO,MAAM,gCAAgC,MAAM;AACjD,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,uBAAA,EAAA,EAAwB,KAAM,EAAA,sBAAA,EAAA,kBAC5B,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,IAAA,EAAA,EAAK,wBAAsB,CAAA,kBAC9C,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,WAAS,IAAC,EAAA,EAAA,2OAKtB,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAS,IAAC,EAAA,EAAA,yIAAA,EAE4C,GAChE,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,EAAA,EAAG,uEAAwE,EAAA,EAAA,cAEjF,CAAQ,EAAA,GAAA,EAAI,0DAEd,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAS,IAAC,EAAA,EAAA,uHAGtB,CAEA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,EAAA,EAAI,CACP,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,IAAK,EAAA,EAAA,yBAAuB,mBAC/C,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,SAAS,EAAA,IAAA,EAAA,EAAC,4BACO,EAAA,GAAA,kBAC1B,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAG,sHAAuH,EAAA,EAAA,yBAEhI,CAAQ,EAAA,GAAA,EAAI,uBACS,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAE,EAAA,IAAA,EAAA,WAAS,GAAI,sCAErC,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,QAAS,EAAA,MAAA;AAAA,MACT,IAAM,EAAA,CAAA;AAAA,gEAAA
|
|
1
|
+
{"version":3,"file":"LabelDataflowInstructionsPage.esm.js","sources":["../../../src/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport Box from '@material-ui/core/Box';\nimport Typography from '@material-ui/core/Typography';\nimport { AlertInstructionsLayout } from '../AlertInstructionsLayout';\nimport { CodeSnippet, Link } from '@backstage/core-components';\n\nexport const LabelDataflowInstructionsPage = () => {\n return (\n <AlertInstructionsLayout title=\"Investigating Growth\">\n <Typography variant=\"h1\">Labeling Dataflow Jobs</Typography>\n <Typography paragraph>\n Labels in Google Cloud Platform are key-value pairs that can be added to\n most types of cloud resources. Since these labels are also exported in\n billing data, adding labels allows a granular breakdown of cloud cost by\n software entity.\n </Typography>\n <Typography paragraph>\n In Cloud Dataflow, labels can be added to a job either programmatically\n or via the command-line when launching a job. Note that GCP has{' '}\n <Link to=\"https://cloud.google.com/compute/docs/labeling-resources#restrictions\">\n restrictions\n </Link>{' '}\n on the length and characters that can be used in labels.\n </Typography>\n <Typography paragraph>\n Labels are not retroactive, so cost tracking is only possible from when\n the labels are first added to a Dataflow job.\n </Typography>\n\n <Box mt={4}>\n <Typography variant=\"h3\">DataflowPipelineOptions</Typography>\n <Typography paragraph>\n Dataflow jobs using Beam's{' '}\n <Link to=\"https://beam.apache.org/releases/javadoc/2.3.0/org/apache/beam/runners/dataflow/options/DataflowPipelineOptions.html\">\n DataflowPipelineOptions\n </Link>{' '}\n directly can use the <b>setLabels</b> function to add one or more\n labels:\n <CodeSnippet\n language=\"java\"\n text={`private DataflowPipelineOptions options = PipelineOptionsFactory.fromArgs(args).as(DataflowPipelineOptionsImpl.class); \noptions.setLabels(ImmutableMap.of(\"job-id\", \"my-dataflow-job\"));`}\n />\n </Typography>\n <Typography paragraph>\n Dataflow jobs using Scio can similarly set options on the ScioContext:\n <CodeSnippet\n language=\"scala\"\n text={`val (sc: ScioContext, args: Args) = ContextAndArgs(cmdLineArgs)\nsc.optionsAs[DataflowPipelineOptions].setLabels(Map(\"job-id\" -> \"my-dataflow-job\").asJava)`}\n />\n </Typography>\n </Box>\n\n <Box mt={4}>\n <Typography variant=\"h3\">Command-line</Typography>\n <Typography paragraph>\n Dataflow jobs launched from the command-line can add labels as an\n argument:\n <CodeSnippet\n language=\"shell\"\n text={`--labels={\"job-id\": \"my-dataflow-job\", \"date-argument\": \"2020-09-16\"}`}\n />\n </Typography>\n <Typography paragraph>\n For more information on specifying options, see the{' '}\n <Link to=\"https://cloud.google.com/dataflow/docs/guides/specifying-exec-params\">\n Dataflow documentation\n </Link>{' '}\n or{' '}\n <Link to=\"https://spotify.github.io/scio/api/com/spotify/scio/ScioContext.html\">\n Scio Scaladoc\n </Link>\n .\n </Typography>\n </Box>\n </AlertInstructionsLayout>\n );\n};\n"],"names":[],"mappings":";;;;;;AAsBO,MAAM,gCAAgC,MAAM;AACjD,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,uBAAA,EAAA,EAAwB,KAAM,EAAA,sBAAA,EAAA,kBAC5B,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,IAAA,EAAA,EAAK,wBAAsB,CAAA,kBAC9C,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,WAAS,IAAC,EAAA,EAAA,2OAKtB,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAS,IAAC,EAAA,EAAA,yIAAA,EAE4C,GAChE,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,EAAA,EAAG,uEAAwE,EAAA,EAAA,cAEjF,CAAQ,EAAA,GAAA,EAAI,0DAEd,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAS,IAAC,EAAA,EAAA,uHAGtB,CAEA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,EAAA,EAAI,CACP,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,IAAK,EAAA,EAAA,yBAAuB,mBAC/C,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,SAAS,EAAA,IAAA,EAAA,EAAC,4BACO,EAAA,GAAA,kBAC1B,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAG,sHAAuH,EAAA,EAAA,yBAEhI,CAAQ,EAAA,GAAA,EAAI,uBACS,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAE,EAAA,IAAA,EAAA,WAAS,GAAI,sCAErC,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,QAAS,EAAA,MAAA;AAAA,MACT,IAAM,EAAA,CAAA;AAAA,gEAAA;AAAA;AAAA,GAGV,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAS,QAAC,wEAEpB,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,QAAS,EAAA,OAAA;AAAA,MACT,IAAM,EAAA,CAAA;AAAA,0FAAA;AAAA;AAAA,GAGV,CACF,CAAA,kBAEC,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,IAAI,CACP,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,QAAK,cAAY,CAAA,sCACpC,UAAW,EAAA,EAAA,SAAA,EAAS,QAAC,6EAGpB,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,QAAS,EAAA,OAAA;AAAA,MACT,IAAM,EAAA,CAAA,qEAAA;AAAA;AAAA,GAEV,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAS,QAAC,qDACgC,EAAA,GAAA,kBACnD,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,EAAG,EAAA,sEAAA,EAAA,EAAuE,wBAEhF,CAAQ,EAAA,GAAA,EAAI,IACT,EAAA,GAAA,kBACF,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,EAAG,EAAA,sEAAA,EAAA,EAAuE,eAEhF,CAAA,EAAO,GAET,CACF,CACF,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LegendItem.esm.js","sources":["../../../src/components/LegendItem/LegendItem.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, { PropsWithChildren } from 'react';\nimport Box from '@material-ui/core/Box';\nimport Typography from '@material-ui/core/Typography';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport LensIcon from '@material-ui/icons/Lens';\nimport HelpOutlineOutlinedIcon from '@material-ui/icons/HelpOutlineOutlined';\nimport { useCostGrowthLegendStyles } from '../../utils/styles';\n\n/** @public */\nexport type LegendItemProps = {\n title: string;\n tooltipText?: string;\n markerColor?: string;\n};\n\n/** @public */\nexport const LegendItem = (props: PropsWithChildren<LegendItemProps>) => {\n const { title, tooltipText, markerColor, children } = props;\n\n const classes = useCostGrowthLegendStyles();\n\n return (\n <Box display=\"flex\" flexDirection=\"column\">\n <Box\n minHeight={25}\n display=\"flex\"\n flexDirection=\"row\"\n alignItems=\"center\"\n >\n {markerColor && (\n <div className={classes.marker}>\n <LensIcon style={{ fontSize: '1em', fill: markerColor }} />\n </div>\n )}\n <Typography className={classes.title} variant=\"overline\">\n {title}\n </Typography>\n {tooltipText && (\n <Tooltip\n classes={{ tooltip: classes.tooltip }}\n title={\n <Typography className={classes.tooltipText}>\n {tooltipText}\n </Typography>\n }\n placement=\"top-start\"\n >\n <Typography\n component=\"span\"\n role=\"img\"\n aria-label=\"help\"\n className={classes.helpIcon}\n >\n <HelpOutlineOutlinedIcon fontSize=\"small\" />\n </Typography>\n </Tooltip>\n )}\n </Box>\n <Box marginLeft={markerColor ? '1.5em' : 0}>\n <Typography className={classes.h5} variant=\"h5\">\n {children}\n </Typography>\n </Box>\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAgCa,MAAA,UAAA,GAAa,CAAC,KAA8C,KAAA;AACvE,EAAA,MAAM,EAAE,KAAA,EAAO,WAAa,EAAA,WAAA,EAAa,UAAa,GAAA,KAAA
|
|
1
|
+
{"version":3,"file":"LegendItem.esm.js","sources":["../../../src/components/LegendItem/LegendItem.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, { PropsWithChildren } from 'react';\nimport Box from '@material-ui/core/Box';\nimport Typography from '@material-ui/core/Typography';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport LensIcon from '@material-ui/icons/Lens';\nimport HelpOutlineOutlinedIcon from '@material-ui/icons/HelpOutlineOutlined';\nimport { useCostGrowthLegendStyles } from '../../utils/styles';\n\n/** @public */\nexport type LegendItemProps = {\n title: string;\n tooltipText?: string;\n markerColor?: string;\n};\n\n/** @public */\nexport const LegendItem = (props: PropsWithChildren<LegendItemProps>) => {\n const { title, tooltipText, markerColor, children } = props;\n\n const classes = useCostGrowthLegendStyles();\n\n return (\n <Box display=\"flex\" flexDirection=\"column\">\n <Box\n minHeight={25}\n display=\"flex\"\n flexDirection=\"row\"\n alignItems=\"center\"\n >\n {markerColor && (\n <div className={classes.marker}>\n <LensIcon style={{ fontSize: '1em', fill: markerColor }} />\n </div>\n )}\n <Typography className={classes.title} variant=\"overline\">\n {title}\n </Typography>\n {tooltipText && (\n <Tooltip\n classes={{ tooltip: classes.tooltip }}\n title={\n <Typography className={classes.tooltipText}>\n {tooltipText}\n </Typography>\n }\n placement=\"top-start\"\n >\n <Typography\n component=\"span\"\n role=\"img\"\n aria-label=\"help\"\n className={classes.helpIcon}\n >\n <HelpOutlineOutlinedIcon fontSize=\"small\" />\n </Typography>\n </Tooltip>\n )}\n </Box>\n <Box marginLeft={markerColor ? '1.5em' : 0}>\n <Typography className={classes.h5} variant=\"h5\">\n {children}\n </Typography>\n </Box>\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAgCa,MAAA,UAAA,GAAa,CAAC,KAA8C,KAAA;AACvE,EAAA,MAAM,EAAE,KAAA,EAAO,WAAa,EAAA,WAAA,EAAa,UAAa,GAAA,KAAA;AAEtD,EAAA,MAAM,UAAU,yBAA0B,EAAA;AAE1C,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,OAAQ,EAAA,MAAA,EAAO,eAAc,QAChC,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,SAAW,EAAA,EAAA;AAAA,MACX,OAAQ,EAAA,MAAA;AAAA,MACR,aAAc,EAAA,KAAA;AAAA,MACd,UAAW,EAAA;AAAA,KAAA;AAAA,IAEV,WACC,oBAAA,KAAA,CAAA,aAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,QAAQ,MACtB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAS,EAAA,EAAA,KAAA,EAAO,EAAE,QAAU,EAAA,KAAA,EAAO,IAAM,EAAA,WAAA,IAAe,CAC3D,CAAA;AAAA,wCAED,UAAW,EAAA,EAAA,SAAA,EAAW,QAAQ,KAAO,EAAA,OAAA,EAAQ,cAC3C,KACH,CAAA;AAAA,IACC,WACC,oBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,OAAS,EAAA,EAAE,OAAS,EAAA,OAAA,CAAQ,OAAQ,EAAA;AAAA,QACpC,uBACG,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,SAAW,EAAA,OAAA,CAAQ,eAC5B,WACH,CAAA;AAAA,QAEF,SAAU,EAAA;AAAA,OAAA;AAAA,sBAEV,KAAA,CAAA,aAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,SAAU,EAAA,MAAA;AAAA,UACV,IAAK,EAAA,KAAA;AAAA,UACL,YAAW,EAAA,MAAA;AAAA,UACX,WAAW,OAAQ,CAAA;AAAA,SAAA;AAAA,wBAEnB,KAAA,CAAA,aAAA,CAAC,uBAAwB,EAAA,EAAA,QAAA,EAAS,OAAQ,EAAA;AAAA;AAC5C;AACF,qBAGH,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,UAAY,EAAA,WAAA,GAAc,UAAU,CACvC,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAW,QAAQ,EAAI,EAAA,OAAA,EAAQ,IACxC,EAAA,EAAA,QACH,CACF,CACF,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetricSelect.esm.js","sources":["../../../src/components/MetricSelect/MetricSelect.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport FormControl from '@material-ui/core/FormControl';\nimport Select from '@material-ui/core/Select';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport {\n Maybe,\n Metric,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { useSelectStyles as useStyles } from '../../utils/styles';\n\nexport type MetricSelectProps = {\n metric: Maybe<string>;\n metrics: Array<Metric>;\n onSelect: (metric: Maybe<string>) => void;\n};\n\nexport const MetricSelect = ({\n metric,\n metrics,\n onSelect,\n}: MetricSelectProps) => {\n const classes = useStyles();\n\n function onChange(e: React.ChangeEvent<{ value: unknown }>) {\n if (e.target.value === 'none') {\n onSelect(null);\n } else {\n onSelect(e.target.value as string);\n }\n }\n\n return (\n <FormControl variant=\"outlined\">\n <InputLabel shrink id=\"metric-select-label\">\n Compare to:\n </InputLabel>\n <Select\n id=\"metric-select\"\n labelId=\"metric-select-label\"\n labelWidth={100}\n className={classes.select}\n value={metric ?? 'none'}\n onChange={onChange}\n >\n <MenuItem className={classes.menuItem} key=\"none\" value=\"none\">\n <em>None</em>\n </MenuItem>\n {metrics.map((m: Metric) => (\n <MenuItem className={classes.menuItem} key={m.kind} value={m.kind}>\n <b>{m.name}</b>\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n );\n};\n"],"names":["useStyles"],"mappings":";;;;;;;AAiCO,MAAM,eAAe,CAAC;AAAA,EAC3B,MAAA;AAAA,EACA,OAAA;AAAA,EACA
|
|
1
|
+
{"version":3,"file":"MetricSelect.esm.js","sources":["../../../src/components/MetricSelect/MetricSelect.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport FormControl from '@material-ui/core/FormControl';\nimport Select from '@material-ui/core/Select';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport {\n Maybe,\n Metric,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { useSelectStyles as useStyles } from '../../utils/styles';\n\nexport type MetricSelectProps = {\n metric: Maybe<string>;\n metrics: Array<Metric>;\n onSelect: (metric: Maybe<string>) => void;\n};\n\nexport const MetricSelect = ({\n metric,\n metrics,\n onSelect,\n}: MetricSelectProps) => {\n const classes = useStyles();\n\n function onChange(e: React.ChangeEvent<{ value: unknown }>) {\n if (e.target.value === 'none') {\n onSelect(null);\n } else {\n onSelect(e.target.value as string);\n }\n }\n\n return (\n <FormControl variant=\"outlined\">\n <InputLabel shrink id=\"metric-select-label\">\n Compare to:\n </InputLabel>\n <Select\n id=\"metric-select\"\n labelId=\"metric-select-label\"\n labelWidth={100}\n className={classes.select}\n value={metric ?? 'none'}\n onChange={onChange}\n >\n <MenuItem className={classes.menuItem} key=\"none\" value=\"none\">\n <em>None</em>\n </MenuItem>\n {metrics.map((m: Metric) => (\n <MenuItem className={classes.menuItem} key={m.kind} value={m.kind}>\n <b>{m.name}</b>\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n );\n};\n"],"names":["useStyles"],"mappings":";;;;;;;AAiCO,MAAM,eAAe,CAAC;AAAA,EAC3B,MAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAyB,KAAA;AACvB,EAAA,MAAM,UAAUA,eAAU,EAAA;AAE1B,EAAA,SAAS,SAAS,CAA0C,EAAA;AAC1D,IAAI,IAAA,CAAA,CAAE,MAAO,CAAA,KAAA,KAAU,MAAQ,EAAA;AAC7B,MAAA,QAAA,CAAS,IAAI,CAAA;AAAA,KACR,MAAA;AACL,MAAS,QAAA,CAAA,CAAA,CAAE,OAAO,KAAe,CAAA;AAAA;AACnC;AAGF,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,WAAY,EAAA,EAAA,OAAA,EAAQ,UACnB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,MAAA,EAAM,IAAC,EAAA,EAAA,EAAG,qBAAsB,EAAA,EAAA,aAE5C,CACA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,EAAG,EAAA,eAAA;AAAA,MACH,OAAQ,EAAA,qBAAA;AAAA,MACR,UAAY,EAAA,GAAA;AAAA,MACZ,WAAW,OAAQ,CAAA,MAAA;AAAA,MACnB,OAAO,MAAU,IAAA,MAAA;AAAA,MACjB;AAAA,KAAA;AAAA,oBAEC,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,SAAW,EAAA,OAAA,CAAQ,QAAU,EAAA,GAAA,EAAI,MAAO,EAAA,KAAA,EAAM,MACtD,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAG,EAAA,IAAA,EAAA,MAAI,CACV,CAAA;AAAA,IACC,OAAA,CAAQ,IAAI,CAAC,CAAA,yCACX,QAAS,EAAA,EAAA,SAAA,EAAW,QAAQ,QAAU,EAAA,GAAA,EAAK,EAAE,IAAM,EAAA,KAAA,EAAO,EAAE,IAC3D,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,WAAG,CAAE,CAAA,IAAK,CACb,CACD;AAAA,GAEL,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PeriodSelect.esm.js","sources":["../../../src/components/PeriodSelect/PeriodSelect.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Select, { SelectProps } from '@material-ui/core/Select';\nimport { Duration } from '../../types';\nimport { formatLastTwoLookaheadQuarters } from '../../utils/formatters';\nimport { findAlways } from '../../utils/assert';\nimport { useSelectStyles as useStyles } from '../../utils/styles';\nimport { useLastCompleteBillingDate } from '../../hooks';\n\nexport type PeriodOption = {\n value: Duration;\n label: string;\n};\n\nexport function getDefaultOptions(\n lastCompleteBillingDate: string,\n): PeriodOption[] {\n return [\n {\n value: Duration.P90D,\n label: 'Past 6 Months',\n },\n {\n value: Duration.P30D,\n label: 'Past 60 Days',\n },\n {\n value: Duration.P3M,\n label: formatLastTwoLookaheadQuarters(lastCompleteBillingDate),\n },\n ];\n}\n\ntype PeriodSelectProps = {\n duration: Duration;\n onSelect: (duration: Duration) => void;\n options?: PeriodOption[];\n};\n\nexport const PeriodSelect = ({\n duration,\n onSelect,\n options,\n}: PeriodSelectProps) => {\n const classes = useStyles();\n const lastCompleteBillingDate = useLastCompleteBillingDate();\n const optionsOrDefault =\n options ?? getDefaultOptions(lastCompleteBillingDate);\n\n const handleOnChange: SelectProps['onChange'] = e => {\n onSelect(e.target.value as Duration);\n };\n\n const renderValue: SelectProps['renderValue'] = value => {\n const option = findAlways(optionsOrDefault, o => o.value === value);\n return <b>{option.label}</b>;\n };\n\n return (\n <Select\n className={classes.select}\n variant=\"outlined\"\n onChange={handleOnChange}\n value={duration}\n renderValue={renderValue}\n data-testid=\"period-select\"\n >\n {optionsOrDefault.map(option => (\n <MenuItem\n className={classes.menuItem}\n key={option.value}\n value={option.value}\n data-testid={`period-select-option-${option.value}`}\n >\n {option.label}\n </MenuItem>\n ))}\n </Select>\n );\n};\n"],"names":["useStyles"],"mappings":";;;;;;;;;;;;;;;;AA8BO,SAAS,kBACd,uBACgB,EAAA;AAChB,EAAO,OAAA;AAAA,IACL;AAAA,MACE,OAAO,QAAS,CAAA,IAAA;AAAA,MAChB,KAAO,EAAA
|
|
1
|
+
{"version":3,"file":"PeriodSelect.esm.js","sources":["../../../src/components/PeriodSelect/PeriodSelect.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Select, { SelectProps } from '@material-ui/core/Select';\nimport { Duration } from '../../types';\nimport { formatLastTwoLookaheadQuarters } from '../../utils/formatters';\nimport { findAlways } from '../../utils/assert';\nimport { useSelectStyles as useStyles } from '../../utils/styles';\nimport { useLastCompleteBillingDate } from '../../hooks';\n\nexport type PeriodOption = {\n value: Duration;\n label: string;\n};\n\nexport function getDefaultOptions(\n lastCompleteBillingDate: string,\n): PeriodOption[] {\n return [\n {\n value: Duration.P90D,\n label: 'Past 6 Months',\n },\n {\n value: Duration.P30D,\n label: 'Past 60 Days',\n },\n {\n value: Duration.P3M,\n label: formatLastTwoLookaheadQuarters(lastCompleteBillingDate),\n },\n ];\n}\n\ntype PeriodSelectProps = {\n duration: Duration;\n onSelect: (duration: Duration) => void;\n options?: PeriodOption[];\n};\n\nexport const PeriodSelect = ({\n duration,\n onSelect,\n options,\n}: PeriodSelectProps) => {\n const classes = useStyles();\n const lastCompleteBillingDate = useLastCompleteBillingDate();\n const optionsOrDefault =\n options ?? getDefaultOptions(lastCompleteBillingDate);\n\n const handleOnChange: SelectProps['onChange'] = e => {\n onSelect(e.target.value as Duration);\n };\n\n const renderValue: SelectProps['renderValue'] = value => {\n const option = findAlways(optionsOrDefault, o => o.value === value);\n return <b>{option.label}</b>;\n };\n\n return (\n <Select\n className={classes.select}\n variant=\"outlined\"\n onChange={handleOnChange}\n value={duration}\n renderValue={renderValue}\n data-testid=\"period-select\"\n >\n {optionsOrDefault.map(option => (\n <MenuItem\n className={classes.menuItem}\n key={option.value}\n value={option.value}\n data-testid={`period-select-option-${option.value}`}\n >\n {option.label}\n </MenuItem>\n ))}\n </Select>\n );\n};\n"],"names":["useStyles"],"mappings":";;;;;;;;;;;;;;;;AA8BO,SAAS,kBACd,uBACgB,EAAA;AAChB,EAAO,OAAA;AAAA,IACL;AAAA,MACE,OAAO,QAAS,CAAA,IAAA;AAAA,MAChB,KAAO,EAAA;AAAA,KACT;AAAA,IACA;AAAA,MACE,OAAO,QAAS,CAAA,IAAA;AAAA,MAChB,KAAO,EAAA;AAAA,KACT;AAAA,IACA;AAAA,MACE,OAAO,QAAS,CAAA,GAAA;AAAA,MAChB,KAAA,EAAO,+BAA+B,uBAAuB;AAAA;AAC/D,GACF;AACF;AAQO,MAAM,eAAe,CAAC;AAAA,EAC3B,QAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAyB,KAAA;AACvB,EAAA,MAAM,UAAUA,eAAU,EAAA;AAC1B,EAAA,MAAM,0BAA0B,0BAA2B,EAAA;AAC3D,EAAM,MAAA,gBAAA,GACJ,OAAW,IAAA,iBAAA,CAAkB,uBAAuB,CAAA;AAEtD,EAAA,MAAM,iBAA0C,CAAK,CAAA,KAAA;AACnD,IAAS,QAAA,CAAA,CAAA,CAAE,OAAO,KAAiB,CAAA;AAAA,GACrC;AAEA,EAAA,MAAM,cAA0C,CAAS,KAAA,KAAA;AACvD,IAAA,MAAM,SAAS,UAAW,CAAA,gBAAA,EAAkB,CAAK,CAAA,KAAA,CAAA,CAAE,UAAU,KAAK,CAAA;AAClE,IAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,GAAG,EAAA,IAAA,EAAA,MAAA,CAAO,KAAM,CAAA;AAAA,GAC1B;AAEA,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,WAAW,OAAQ,CAAA,MAAA;AAAA,MACnB,OAAQ,EAAA,UAAA;AAAA,MACR,QAAU,EAAA,cAAA;AAAA,MACV,KAAO,EAAA,QAAA;AAAA,MACP,WAAA;AAAA,MACA,aAAY,EAAA;AAAA,KAAA;AAAA,IAEX,gBAAA,CAAiB,IAAI,CACpB,MAAA,qBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,WAAW,OAAQ,CAAA,QAAA;AAAA,QACnB,KAAK,MAAO,CAAA,KAAA;AAAA,QACZ,OAAO,MAAO,CAAA,KAAA;AAAA,QACd,aAAA,EAAa,CAAwB,qBAAA,EAAA,MAAA,CAAO,KAAK,CAAA;AAAA,OAAA;AAAA,MAEhD,MAAO,CAAA;AAAA,KAEX;AAAA,GACH;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductInsights.esm.js","sources":["../../../src/components/ProductInsights/ProductInsights.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, { useCallback, useEffect, useRef, useState } from 'react';\nimport Box from '@material-ui/core/Box';\nimport Typography from '@material-ui/core/Typography';\nimport { default as Alert } from '@material-ui/lab/Alert';\nimport { costInsightsApiRef } from '../../api';\nimport { ProductInsightsCardList } from '../ProductInsightsCard/ProductInsightsCardList';\nimport { Duration } from '../../types';\nimport {\n Entity,\n Maybe,\n Product,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { intervalsOf, DEFAULT_DURATION } from '../../utils/duration';\nimport {\n DefaultLoadingAction,\n initialStatesOf,\n settledResponseOf,\n ProductState,\n} from '../../utils/loading';\nimport { totalAggregationSort } from '../../utils/sort';\nimport {\n useLoading,\n useLastCompleteBillingDate,\n MapLoadingToProps,\n} from '../../hooks';\nimport { useApi } from '@backstage/core-plugin-api';\n\ntype LoadingProps = (isLoading: boolean) => void;\n\nconst mapLoadingToProps: MapLoadingToProps<LoadingProps> =\n ({ dispatch }) =>\n (isLoading: boolean) =>\n dispatch({ [DefaultLoadingAction.CostInsightsProducts]: isLoading });\n\ntype ProductInsightsProps = {\n group: string;\n project: Maybe<string>;\n products: Product[];\n onLoaded: (entities: Product[]) => void;\n};\n\nexport const ProductInsights = ({\n group,\n project,\n products,\n onLoaded,\n}: ProductInsightsProps) => {\n const client = useApi(costInsightsApiRef);\n const onceRef = useRef(false);\n const [initialStates, setStates] = useState<ProductState[]>([]);\n const [error, setError] = useState<Maybe<Error>>(null);\n const lastCompleteBillingDate = useLastCompleteBillingDate();\n const dispatchLoading = useLoading(mapLoadingToProps);\n\n /* eslint-disable react-hooks/exhaustive-deps */\n // See @CostInsightsPage\n const dispatchLoadingProducts = useCallback(dispatchLoading, []);\n /* eslint-enable react-hooks/exhaustive-deps */\n\n const onSelectAsyncMemo = useCallback(\n async function onSelectAsync(\n product: Product,\n duration: Duration,\n ): Promise<Entity> {\n return client.getProductInsights({\n group: group,\n project: project,\n product: product.kind,\n intervals: intervalsOf(duration, lastCompleteBillingDate),\n });\n },\n [client, group, project, lastCompleteBillingDate],\n );\n\n useEffect(() => {\n async function getAllProductInsights() {\n try {\n dispatchLoadingProducts(true);\n const responses = await Promise.allSettled(\n products.map(product =>\n client.getProductInsights({\n group: group,\n project: project,\n product: product.kind,\n intervals: intervalsOf(DEFAULT_DURATION, lastCompleteBillingDate),\n }),\n ),\n ).then(settledResponseOf);\n\n const updatedInitialStates = initialStatesOf(products, responses).sort(\n totalAggregationSort,\n );\n setStates(updatedInitialStates);\n } catch (e) {\n setError(e);\n } finally {\n dispatchLoadingProducts(false);\n }\n }\n\n getAllProductInsights();\n }, [\n client,\n group,\n project,\n products,\n lastCompleteBillingDate,\n dispatchLoadingProducts,\n ]);\n\n useEffect(\n function handleOnLoaded() {\n if (onceRef.current) {\n const initialProducts = initialStates.map(state => state.product);\n onLoaded(initialProducts);\n } else {\n onceRef.current = true;\n }\n },\n [initialStates, onLoaded],\n );\n\n return (\n <Box px={3} py={6}>\n <Box mt={0} mb={5} textAlign=\"center\">\n <Typography variant=\"h4\" gutterBottom>\n Your team's product usage\n </Typography>\n </Box>\n {error ? (\n <Alert severity=\"error\">{error.message}</Alert>\n ) : (\n <ProductInsightsCardList\n initialStates={initialStates}\n onSelectAsync={onSelectAsyncMemo}\n />\n )}\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AA6CA,MAAM,iBACJ,GAAA,CAAC,EAAE,QAAA,OACH,CAAC,SAAA,KACC,QAAS,CAAA,EAAE,CAAC,oBAAA,CAAqB,oBAAoB,GAAG,WAAW,CAAA
|
|
1
|
+
{"version":3,"file":"ProductInsights.esm.js","sources":["../../../src/components/ProductInsights/ProductInsights.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, { useCallback, useEffect, useRef, useState } from 'react';\nimport Box from '@material-ui/core/Box';\nimport Typography from '@material-ui/core/Typography';\nimport { default as Alert } from '@material-ui/lab/Alert';\nimport { costInsightsApiRef } from '../../api';\nimport { ProductInsightsCardList } from '../ProductInsightsCard/ProductInsightsCardList';\nimport { Duration } from '../../types';\nimport {\n Entity,\n Maybe,\n Product,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { intervalsOf, DEFAULT_DURATION } from '../../utils/duration';\nimport {\n DefaultLoadingAction,\n initialStatesOf,\n settledResponseOf,\n ProductState,\n} from '../../utils/loading';\nimport { totalAggregationSort } from '../../utils/sort';\nimport {\n useLoading,\n useLastCompleteBillingDate,\n MapLoadingToProps,\n} from '../../hooks';\nimport { useApi } from '@backstage/core-plugin-api';\n\ntype LoadingProps = (isLoading: boolean) => void;\n\nconst mapLoadingToProps: MapLoadingToProps<LoadingProps> =\n ({ dispatch }) =>\n (isLoading: boolean) =>\n dispatch({ [DefaultLoadingAction.CostInsightsProducts]: isLoading });\n\ntype ProductInsightsProps = {\n group: string;\n project: Maybe<string>;\n products: Product[];\n onLoaded: (entities: Product[]) => void;\n};\n\nexport const ProductInsights = ({\n group,\n project,\n products,\n onLoaded,\n}: ProductInsightsProps) => {\n const client = useApi(costInsightsApiRef);\n const onceRef = useRef(false);\n const [initialStates, setStates] = useState<ProductState[]>([]);\n const [error, setError] = useState<Maybe<Error>>(null);\n const lastCompleteBillingDate = useLastCompleteBillingDate();\n const dispatchLoading = useLoading(mapLoadingToProps);\n\n /* eslint-disable react-hooks/exhaustive-deps */\n // See @CostInsightsPage\n const dispatchLoadingProducts = useCallback(dispatchLoading, []);\n /* eslint-enable react-hooks/exhaustive-deps */\n\n const onSelectAsyncMemo = useCallback(\n async function onSelectAsync(\n product: Product,\n duration: Duration,\n ): Promise<Entity> {\n return client.getProductInsights({\n group: group,\n project: project,\n product: product.kind,\n intervals: intervalsOf(duration, lastCompleteBillingDate),\n });\n },\n [client, group, project, lastCompleteBillingDate],\n );\n\n useEffect(() => {\n async function getAllProductInsights() {\n try {\n dispatchLoadingProducts(true);\n const responses = await Promise.allSettled(\n products.map(product =>\n client.getProductInsights({\n group: group,\n project: project,\n product: product.kind,\n intervals: intervalsOf(DEFAULT_DURATION, lastCompleteBillingDate),\n }),\n ),\n ).then(settledResponseOf);\n\n const updatedInitialStates = initialStatesOf(products, responses).sort(\n totalAggregationSort,\n );\n setStates(updatedInitialStates);\n } catch (e) {\n setError(e);\n } finally {\n dispatchLoadingProducts(false);\n }\n }\n\n getAllProductInsights();\n }, [\n client,\n group,\n project,\n products,\n lastCompleteBillingDate,\n dispatchLoadingProducts,\n ]);\n\n useEffect(\n function handleOnLoaded() {\n if (onceRef.current) {\n const initialProducts = initialStates.map(state => state.product);\n onLoaded(initialProducts);\n } else {\n onceRef.current = true;\n }\n },\n [initialStates, onLoaded],\n );\n\n return (\n <Box px={3} py={6}>\n <Box mt={0} mb={5} textAlign=\"center\">\n <Typography variant=\"h4\" gutterBottom>\n Your team's product usage\n </Typography>\n </Box>\n {error ? (\n <Alert severity=\"error\">{error.message}</Alert>\n ) : (\n <ProductInsightsCardList\n initialStates={initialStates}\n onSelectAsync={onSelectAsyncMemo}\n />\n )}\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductEntityDialog.esm.js","sources":["../../../src/components/ProductInsightsCard/ProductEntityDialog.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 Dialog from '@material-ui/core/Dialog';\nimport IconButton from '@material-ui/core/IconButton';\nimport { default as CloseButton } from '@material-ui/icons/Close';\nimport { useEntityDialogStyles as useStyles } from '../../utils/styles';\nimport { Entity } from '@backstage-community/plugin-cost-insights-common';\nimport {\n ProductEntityTable,\n ProductEntityTableOptions,\n} from './ProductEntityTable';\nimport { findAlways } from '../../utils/assert';\nimport { HeaderTabs } from '@backstage/core-components';\n\ntype ProductEntityDialogProps = {\n open: boolean;\n entity: Entity;\n options?: ProductEntityTableOptions;\n onClose: () => void;\n};\n\nexport const ProductEntityDialog = ({\n open,\n entity,\n options = {},\n onClose,\n}: ProductEntityDialogProps) => {\n const classes = useStyles();\n const labels = Object.keys(entity.entities);\n const [selectedLabel, setSelectedLabel] = useState(\n findAlways(labels, _ => true),\n );\n\n const tabs = labels.map((label, index) => ({\n id: index.toString(),\n label: `Breakdown by ${label}`,\n }));\n\n return (\n <Dialog open={open} onClose={onClose} scroll=\"body\" fullWidth maxWidth=\"lg\">\n <IconButton className={classes.closeButton} onClick={onClose}>\n <CloseButton />\n </IconButton>\n <HeaderTabs\n tabs={tabs}\n onChange={index => setSelectedLabel(labels[index])}\n />\n <ProductEntityTable\n entityLabel={selectedLabel}\n entity={entity}\n options={options}\n />\n </Dialog>\n );\n};\n"],"names":["useStyles","CloseButton"],"mappings":";;;;;;;;;AAoCO,MAAM,sBAAsB,CAAC;AAAA,EAClC,IAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAU,EAAC;AAAA,EACX
|
|
1
|
+
{"version":3,"file":"ProductEntityDialog.esm.js","sources":["../../../src/components/ProductInsightsCard/ProductEntityDialog.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 Dialog from '@material-ui/core/Dialog';\nimport IconButton from '@material-ui/core/IconButton';\nimport { default as CloseButton } from '@material-ui/icons/Close';\nimport { useEntityDialogStyles as useStyles } from '../../utils/styles';\nimport { Entity } from '@backstage-community/plugin-cost-insights-common';\nimport {\n ProductEntityTable,\n ProductEntityTableOptions,\n} from './ProductEntityTable';\nimport { findAlways } from '../../utils/assert';\nimport { HeaderTabs } from '@backstage/core-components';\n\ntype ProductEntityDialogProps = {\n open: boolean;\n entity: Entity;\n options?: ProductEntityTableOptions;\n onClose: () => void;\n};\n\nexport const ProductEntityDialog = ({\n open,\n entity,\n options = {},\n onClose,\n}: ProductEntityDialogProps) => {\n const classes = useStyles();\n const labels = Object.keys(entity.entities);\n const [selectedLabel, setSelectedLabel] = useState(\n findAlways(labels, _ => true),\n );\n\n const tabs = labels.map((label, index) => ({\n id: index.toString(),\n label: `Breakdown by ${label}`,\n }));\n\n return (\n <Dialog open={open} onClose={onClose} scroll=\"body\" fullWidth maxWidth=\"lg\">\n <IconButton className={classes.closeButton} onClick={onClose}>\n <CloseButton />\n </IconButton>\n <HeaderTabs\n tabs={tabs}\n onChange={index => setSelectedLabel(labels[index])}\n />\n <ProductEntityTable\n entityLabel={selectedLabel}\n entity={entity}\n options={options}\n />\n </Dialog>\n );\n};\n"],"names":["useStyles","CloseButton"],"mappings":";;;;;;;;;AAoCO,MAAM,sBAAsB,CAAC;AAAA,EAClC,IAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAU,EAAC;AAAA,EACX;AACF,CAAgC,KAAA;AAC9B,EAAA,MAAM,UAAUA,qBAAU,EAAA;AAC1B,EAAA,MAAM,MAAS,GAAA,MAAA,CAAO,IAAK,CAAA,MAAA,CAAO,QAAQ,CAAA;AAC1C,EAAM,MAAA,CAAC,aAAe,EAAA,gBAAgB,CAAI,GAAA,QAAA;AAAA,IACxC,UAAA,CAAW,MAAQ,EAAA,CAAA,CAAA,KAAK,IAAI;AAAA,GAC9B;AAEA,EAAA,MAAM,IAAO,GAAA,MAAA,CAAO,GAAI,CAAA,CAAC,OAAO,KAAW,MAAA;AAAA,IACzC,EAAA,EAAI,MAAM,QAAS,EAAA;AAAA,IACnB,KAAA,EAAO,gBAAgB,KAAK,CAAA;AAAA,GAC5B,CAAA,CAAA;AAEF,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,UAAO,IAAY,EAAA,OAAA,EAAkB,QAAO,MAAO,EAAA,SAAA,EAAS,MAAC,QAAS,EAAA,IAAA,EAAA,sCACpE,UAAW,EAAA,EAAA,SAAA,EAAW,QAAQ,WAAa,EAAA,OAAA,EAAS,2BAClD,KAAA,CAAA,aAAA,CAAAC,SAAA,EAAA,IAAY,CACf,CACA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,IAAA;AAAA,MACA,QAAU,EAAA,CAAA,KAAA,KAAS,gBAAiB,CAAA,MAAA,CAAO,KAAK,CAAC;AAAA;AAAA,GAEnD,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,kBAAA;AAAA,IAAA;AAAA,MACC,WAAa,EAAA,aAAA;AAAA,MACb,MAAA;AAAA,MACA;AAAA;AAAA,GAEJ,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductEntityTable.esm.js","sources":["../../../src/components/ProductInsightsCard/ProductEntityTable.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport classnames from 'classnames';\nimport Typography from '@material-ui/core/Typography';\nimport { formatChange } from '../../utils/formatters';\nimport { useEntityDialogStyles as useStyles } from '../../utils/styles';\nimport { CostGrowthIndicator } from '../CostGrowth';\nimport { BarChartOptions } from '../../types';\nimport {\n ChangeStatistic,\n Entity,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { Table, TableColumn } from '@backstage/core-components';\nimport { useConfig } from '../../hooks';\n\nexport type ProductEntityTableOptions = Partial<\n Pick<BarChartOptions, 'previousName' | 'currentName'>\n>;\n\ntype RowData = {\n id: string;\n label: string;\n previous: number;\n current: number;\n change: ChangeStatistic;\n};\n\nconst createRenderer =\n (baseCurrency: Intl.NumberFormat) =>\n (col: keyof RowData, classes: Record<string, string>) => {\n return function render(rowData: {}): JSX.Element {\n const row = rowData as RowData;\n const rowStyles = classnames(classes.row, {\n [classes.rowTotal]: row.id === 'total',\n [classes.colFirst]: col === 'label',\n [classes.colLast]: col === 'change',\n });\n\n switch (col) {\n case 'previous':\n case 'current':\n return (\n <Typography className={rowStyles}>\n {baseCurrency.format(row[col])}\n </Typography>\n );\n case 'change':\n return (\n <CostGrowthIndicator\n className={rowStyles}\n change={row.change}\n formatter={formatChange}\n />\n );\n default:\n return <Typography className={rowStyles}>{row.label}</Typography>;\n }\n };\n };\n\n// material-table does not support fixed rows. Override the sorting algorithm\n// to force Total row to bottom by default or when a user sort toggles a column.\nfunction createSorter(field?: keyof Omit<RowData, 'id'>) {\n return function rowSort(data1: {}, data2: {}): number {\n const a = data1 as RowData;\n const b = data2 as RowData;\n if (a.id === 'total') return 1;\n if (b.id === 'total') return 1;\n if (field === 'label') return a.label.localeCompare(b.label);\n if (field === 'change') {\n if (formatChange(a[field]) === '∞' || formatChange(b[field]) === '-∞')\n return 1;\n if (formatChange(a[field]) === '-∞' || formatChange(b[field]) === '∞')\n return -1;\n return a[field].ratio! - b[field].ratio!;\n }\n\n return b.previous + b.current - (a.previous + a.current);\n };\n}\n\ntype ProductEntityTableProps = {\n entityLabel: string;\n entity: Entity;\n options: ProductEntityTableOptions;\n};\n\nexport const ProductEntityTable = ({\n entityLabel,\n entity,\n options,\n}: ProductEntityTableProps) => {\n const classes = useStyles();\n const { baseCurrency } = useConfig();\n const entities = entity.entities[entityLabel];\n\n const data = Object.assign(\n {\n previousName: 'Previous',\n currentName: 'Current',\n },\n options,\n );\n\n const firstColClasses = classnames(classes.column, classes.colFirst);\n const lastColClasses = classnames(classes.column, classes.colLast);\n\n const columns: TableColumn[] = [\n {\n field: 'label',\n title: <Typography className={firstColClasses}>{entityLabel}</Typography>,\n render: createRenderer(baseCurrency)('label', classes),\n customSort: createSorter('label'),\n width: '33.33%',\n },\n {\n field: 'previous',\n title: (\n <Typography className={classes.column}>{data.previousName}</Typography>\n ),\n align: 'right',\n render: createRenderer(baseCurrency)('previous', classes),\n customSort: createSorter('previous'),\n },\n {\n field: 'current',\n title: (\n <Typography className={classes.column}>{data.currentName}</Typography>\n ),\n align: 'right',\n render: createRenderer(baseCurrency)('current', classes),\n customSort: createSorter('current'),\n },\n {\n field: 'change',\n title: <Typography className={lastColClasses}>Change</Typography>,\n align: 'right',\n render: createRenderer(baseCurrency)('change', classes),\n customSort: createSorter('change'),\n },\n ];\n\n const rowData: RowData[] = entities\n .map(e => ({\n id: e.id || 'Unknown',\n label: e.id || 'Unknown',\n previous: e.aggregation[0],\n current: e.aggregation[1],\n change: e.change,\n }))\n .concat({\n id: 'total',\n label: 'Total',\n previous: entity.aggregation[0],\n current: entity.aggregation[1],\n change: entity.change,\n })\n .sort(createSorter());\n\n return (\n <Table\n columns={columns}\n data={rowData}\n title={entity.id || 'Unlabeled'}\n options={{\n paging: false,\n search: false,\n hideFilterIcons: true,\n }}\n />\n );\n};\n"],"names":["useStyles"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProductEntityTable.esm.js","sources":["../../../src/components/ProductInsightsCard/ProductEntityTable.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport classnames from 'classnames';\nimport Typography from '@material-ui/core/Typography';\nimport { formatChange } from '../../utils/formatters';\nimport { useEntityDialogStyles as useStyles } from '../../utils/styles';\nimport { CostGrowthIndicator } from '../CostGrowth';\nimport { BarChartOptions } from '../../types';\nimport {\n ChangeStatistic,\n Entity,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { Table, TableColumn } from '@backstage/core-components';\nimport { useConfig } from '../../hooks';\n\nexport type ProductEntityTableOptions = Partial<\n Pick<BarChartOptions, 'previousName' | 'currentName'>\n>;\n\ntype RowData = {\n id: string;\n label: string;\n previous: number;\n current: number;\n change: ChangeStatistic;\n};\n\nconst createRenderer =\n (baseCurrency: Intl.NumberFormat) =>\n (col: keyof RowData, classes: Record<string, string>) => {\n return function render(rowData: {}): JSX.Element {\n const row = rowData as RowData;\n const rowStyles = classnames(classes.row, {\n [classes.rowTotal]: row.id === 'total',\n [classes.colFirst]: col === 'label',\n [classes.colLast]: col === 'change',\n });\n\n switch (col) {\n case 'previous':\n case 'current':\n return (\n <Typography className={rowStyles}>\n {baseCurrency.format(row[col])}\n </Typography>\n );\n case 'change':\n return (\n <CostGrowthIndicator\n className={rowStyles}\n change={row.change}\n formatter={formatChange}\n />\n );\n default:\n return <Typography className={rowStyles}>{row.label}</Typography>;\n }\n };\n };\n\n// material-table does not support fixed rows. Override the sorting algorithm\n// to force Total row to bottom by default or when a user sort toggles a column.\nfunction createSorter(field?: keyof Omit<RowData, 'id'>) {\n return function rowSort(data1: {}, data2: {}): number {\n const a = data1 as RowData;\n const b = data2 as RowData;\n if (a.id === 'total') return 1;\n if (b.id === 'total') return 1;\n if (field === 'label') return a.label.localeCompare(b.label);\n if (field === 'change') {\n if (formatChange(a[field]) === '∞' || formatChange(b[field]) === '-∞')\n return 1;\n if (formatChange(a[field]) === '-∞' || formatChange(b[field]) === '∞')\n return -1;\n return a[field].ratio! - b[field].ratio!;\n }\n\n return b.previous + b.current - (a.previous + a.current);\n };\n}\n\ntype ProductEntityTableProps = {\n entityLabel: string;\n entity: Entity;\n options: ProductEntityTableOptions;\n};\n\nexport const ProductEntityTable = ({\n entityLabel,\n entity,\n options,\n}: ProductEntityTableProps) => {\n const classes = useStyles();\n const { baseCurrency } = useConfig();\n const entities = entity.entities[entityLabel];\n\n const data = Object.assign(\n {\n previousName: 'Previous',\n currentName: 'Current',\n },\n options,\n );\n\n const firstColClasses = classnames(classes.column, classes.colFirst);\n const lastColClasses = classnames(classes.column, classes.colLast);\n\n const columns: TableColumn[] = [\n {\n field: 'label',\n title: <Typography className={firstColClasses}>{entityLabel}</Typography>,\n render: createRenderer(baseCurrency)('label', classes),\n customSort: createSorter('label'),\n width: '33.33%',\n },\n {\n field: 'previous',\n title: (\n <Typography className={classes.column}>{data.previousName}</Typography>\n ),\n align: 'right',\n render: createRenderer(baseCurrency)('previous', classes),\n customSort: createSorter('previous'),\n },\n {\n field: 'current',\n title: (\n <Typography className={classes.column}>{data.currentName}</Typography>\n ),\n align: 'right',\n render: createRenderer(baseCurrency)('current', classes),\n customSort: createSorter('current'),\n },\n {\n field: 'change',\n title: <Typography className={lastColClasses}>Change</Typography>,\n align: 'right',\n render: createRenderer(baseCurrency)('change', classes),\n customSort: createSorter('change'),\n },\n ];\n\n const rowData: RowData[] = entities\n .map(e => ({\n id: e.id || 'Unknown',\n label: e.id || 'Unknown',\n previous: e.aggregation[0],\n current: e.aggregation[1],\n change: e.change,\n }))\n .concat({\n id: 'total',\n label: 'Total',\n previous: entity.aggregation[0],\n current: entity.aggregation[1],\n change: entity.change,\n })\n .sort(createSorter());\n\n return (\n <Table\n columns={columns}\n data={rowData}\n title={entity.id || 'Unlabeled'}\n options={{\n paging: false,\n search: false,\n hideFilterIcons: true,\n }}\n />\n );\n};\n"],"names":["useStyles"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductInsightsCard.esm.js","sources":["../../../src/components/ProductInsightsCard/ProductInsightsCard.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, {\n PropsWithChildren,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport pluralize from 'pluralize';\nimport Typography from '@material-ui/core/Typography';\nimport { default as Alert } from '@material-ui/lab/Alert';\nimport { PeriodSelect } from '../PeriodSelect';\nimport { ProductInsightsChart } from './ProductInsightsChart';\nimport { useProductInsightsCardStyles as useStyles } from '../../utils/styles';\nimport { DefaultLoadingAction } from '../../utils/loading';\nimport { Duration } from '../../types';\nimport {\n Entity,\n Maybe,\n Product,\n} from '@backstage-community/plugin-cost-insights-common';\nimport {\n MapLoadingToProps,\n useLastCompleteBillingDate,\n useLoading,\n} from '../../hooks';\nimport { findAnyKey } from '../../utils/assert';\nimport { ScrollAnchor } from '../../utils/scroll';\nimport { InfoCard } from '@backstage/core-components';\n\ntype LoadingProps = (isLoading: boolean) => void;\n\nexport type ProductInsightsCardProps = {\n product: Product;\n initialState: {\n entity: Maybe<Entity>;\n duration: Duration;\n };\n onSelectAsync: (product: Product, duration: Duration) => Promise<Entity>;\n};\n\nconst mapLoadingToProps: MapLoadingToProps<LoadingProps> =\n ({ dispatch }) =>\n (isLoading: boolean) =>\n dispatch({ [DefaultLoadingAction.CostInsightsProducts]: isLoading });\n\nexport const ProductInsightsCard = ({\n initialState,\n product,\n onSelectAsync,\n}: PropsWithChildren<ProductInsightsCardProps>) => {\n const classes = useStyles();\n const mountedRef = useRef(false);\n const [error, setError] = useState<Maybe<Error>>(null);\n const dispatchLoading = useLoading(mapLoadingToProps);\n const lastCompleteBillingDate = useLastCompleteBillingDate();\n const [entity, setEntity] = useState<Maybe<Entity>>(initialState.entity);\n const [duration, setDuration] = useState<Duration>(initialState.duration);\n\n /* eslint-disable react-hooks/exhaustive-deps */\n const dispatchLoadingProduct = useCallback(dispatchLoading, []);\n /* eslint-enable react-hooks/exhaustive-deps */\n\n useEffect(() => {\n async function handleOnSelectAsync() {\n dispatchLoadingProduct(true);\n try {\n const e = await onSelectAsync(product, duration);\n setEntity(e);\n } catch (e) {\n setEntity(null);\n setError(e);\n } finally {\n dispatchLoadingProduct(false);\n }\n }\n\n if (mountedRef.current) {\n handleOnSelectAsync();\n } else {\n mountedRef.current = true;\n }\n }, [product, duration, onSelectAsync, dispatchLoadingProduct]);\n\n // Only a single entities Record for the root product entity is supported\n const entityKey = findAnyKey(entity?.entities);\n const entities = entityKey ? entity!.entities[entityKey] : [];\n\n const subheader =\n entityKey && entities.length\n ? `${pluralize(entityKey, entities.length, true)}, sorted by cost`\n : null;\n const headerProps = {\n classes: classes,\n action: <PeriodSelect duration={duration} onSelect={setDuration} />,\n };\n\n if (error || !entity) {\n return (\n <InfoCard title={product.name} headerProps={headerProps}>\n <ScrollAnchor id={product.kind} />\n <Alert severity=\"error\">\n {error\n ? error.message\n : `Error: Could not fetch product insights for ${product.name}`}\n </Alert>\n </InfoCard>\n );\n }\n\n return (\n <InfoCard\n title={product.name}\n subheader={subheader}\n headerProps={headerProps}\n >\n <ScrollAnchor id={product.kind} />\n {entities.length ? (\n <ProductInsightsChart\n entity={entity}\n duration={duration}\n billingDate={lastCompleteBillingDate}\n />\n ) : (\n <Typography>\n There are no {product.name} costs within this time frame for your\n team's projects.\n </Typography>\n )}\n </InfoCard>\n );\n};\n"],"names":["useStyles"],"mappings":";;;;;;;;;;;;;;;;;;;AAwDA,MAAM,iBACJ,GAAA,CAAC,EAAE,QAAA,OACH,CAAC,SAAA,KACC,QAAS,CAAA,EAAE,CAAC,oBAAA,CAAqB,oBAAoB,GAAG,WAAW,CAAA
|
|
1
|
+
{"version":3,"file":"ProductInsightsCard.esm.js","sources":["../../../src/components/ProductInsightsCard/ProductInsightsCard.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, {\n PropsWithChildren,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport pluralize from 'pluralize';\nimport Typography from '@material-ui/core/Typography';\nimport { default as Alert } from '@material-ui/lab/Alert';\nimport { PeriodSelect } from '../PeriodSelect';\nimport { ProductInsightsChart } from './ProductInsightsChart';\nimport { useProductInsightsCardStyles as useStyles } from '../../utils/styles';\nimport { DefaultLoadingAction } from '../../utils/loading';\nimport { Duration } from '../../types';\nimport {\n Entity,\n Maybe,\n Product,\n} from '@backstage-community/plugin-cost-insights-common';\nimport {\n MapLoadingToProps,\n useLastCompleteBillingDate,\n useLoading,\n} from '../../hooks';\nimport { findAnyKey } from '../../utils/assert';\nimport { ScrollAnchor } from '../../utils/scroll';\nimport { InfoCard } from '@backstage/core-components';\n\ntype LoadingProps = (isLoading: boolean) => void;\n\nexport type ProductInsightsCardProps = {\n product: Product;\n initialState: {\n entity: Maybe<Entity>;\n duration: Duration;\n };\n onSelectAsync: (product: Product, duration: Duration) => Promise<Entity>;\n};\n\nconst mapLoadingToProps: MapLoadingToProps<LoadingProps> =\n ({ dispatch }) =>\n (isLoading: boolean) =>\n dispatch({ [DefaultLoadingAction.CostInsightsProducts]: isLoading });\n\nexport const ProductInsightsCard = ({\n initialState,\n product,\n onSelectAsync,\n}: PropsWithChildren<ProductInsightsCardProps>) => {\n const classes = useStyles();\n const mountedRef = useRef(false);\n const [error, setError] = useState<Maybe<Error>>(null);\n const dispatchLoading = useLoading(mapLoadingToProps);\n const lastCompleteBillingDate = useLastCompleteBillingDate();\n const [entity, setEntity] = useState<Maybe<Entity>>(initialState.entity);\n const [duration, setDuration] = useState<Duration>(initialState.duration);\n\n /* eslint-disable react-hooks/exhaustive-deps */\n const dispatchLoadingProduct = useCallback(dispatchLoading, []);\n /* eslint-enable react-hooks/exhaustive-deps */\n\n useEffect(() => {\n async function handleOnSelectAsync() {\n dispatchLoadingProduct(true);\n try {\n const e = await onSelectAsync(product, duration);\n setEntity(e);\n } catch (e) {\n setEntity(null);\n setError(e);\n } finally {\n dispatchLoadingProduct(false);\n }\n }\n\n if (mountedRef.current) {\n handleOnSelectAsync();\n } else {\n mountedRef.current = true;\n }\n }, [product, duration, onSelectAsync, dispatchLoadingProduct]);\n\n // Only a single entities Record for the root product entity is supported\n const entityKey = findAnyKey(entity?.entities);\n const entities = entityKey ? entity!.entities[entityKey] : [];\n\n const subheader =\n entityKey && entities.length\n ? `${pluralize(entityKey, entities.length, true)}, sorted by cost`\n : null;\n const headerProps = {\n classes: classes,\n action: <PeriodSelect duration={duration} onSelect={setDuration} />,\n };\n\n if (error || !entity) {\n return (\n <InfoCard title={product.name} headerProps={headerProps}>\n <ScrollAnchor id={product.kind} />\n <Alert severity=\"error\">\n {error\n ? error.message\n : `Error: Could not fetch product insights for ${product.name}`}\n </Alert>\n </InfoCard>\n );\n }\n\n return (\n <InfoCard\n title={product.name}\n subheader={subheader}\n headerProps={headerProps}\n >\n <ScrollAnchor id={product.kind} />\n {entities.length ? (\n <ProductInsightsChart\n entity={entity}\n duration={duration}\n billingDate={lastCompleteBillingDate}\n />\n ) : (\n <Typography>\n There are no {product.name} costs within this time frame for your\n team's projects.\n </Typography>\n )}\n </InfoCard>\n );\n};\n"],"names":["useStyles"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductInsightsCardList.esm.js","sources":["../../../src/components/ProductInsightsCard/ProductInsightsCardList.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport Box from '@material-ui/core/Box';\nimport CircularProgress from '@material-ui/core/CircularProgress';\nimport Collapse from '@material-ui/core/Collapse';\nimport { ProductInsightsCard } from './ProductInsightsCard';\nimport { Duration } from '../../types';\nimport {\n Entity,\n Product,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { ProductState } from '../../utils/loading';\n\ntype ProductInsightsCardListProps = {\n initialStates: ProductState[];\n onSelectAsync: (product: Product, duration: Duration) => Promise<Entity>;\n};\n\nexport const ProductInsightsCardList = ({\n initialStates,\n onSelectAsync,\n}: ProductInsightsCardListProps) => {\n if (!initialStates.length) {\n return (\n <Box display=\"flex\" justifyContent=\"space-around\" alignItems=\"center\">\n <CircularProgress />\n </Box>\n );\n }\n\n return (\n <Collapse in timeout={1000}>\n {initialStates.map(({ product, entity, duration }) => (\n <Box\n key={product.kind}\n mb={6}\n position=\"relative\"\n data-testid={`product-list-item-${product.kind}`}\n >\n <ProductInsightsCard\n product={product}\n onSelectAsync={onSelectAsync}\n initialState={{ entity: entity, duration: duration }}\n />\n </Box>\n ))}\n </Collapse>\n );\n};\n"],"names":[],"mappings":";;;;;;AAiCO,MAAM,0BAA0B,CAAC;AAAA,EACtC,aAAA;AAAA,EACA
|
|
1
|
+
{"version":3,"file":"ProductInsightsCardList.esm.js","sources":["../../../src/components/ProductInsightsCard/ProductInsightsCardList.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport Box from '@material-ui/core/Box';\nimport CircularProgress from '@material-ui/core/CircularProgress';\nimport Collapse from '@material-ui/core/Collapse';\nimport { ProductInsightsCard } from './ProductInsightsCard';\nimport { Duration } from '../../types';\nimport {\n Entity,\n Product,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { ProductState } from '../../utils/loading';\n\ntype ProductInsightsCardListProps = {\n initialStates: ProductState[];\n onSelectAsync: (product: Product, duration: Duration) => Promise<Entity>;\n};\n\nexport const ProductInsightsCardList = ({\n initialStates,\n onSelectAsync,\n}: ProductInsightsCardListProps) => {\n if (!initialStates.length) {\n return (\n <Box display=\"flex\" justifyContent=\"space-around\" alignItems=\"center\">\n <CircularProgress />\n </Box>\n );\n }\n\n return (\n <Collapse in timeout={1000}>\n {initialStates.map(({ product, entity, duration }) => (\n <Box\n key={product.kind}\n mb={6}\n position=\"relative\"\n data-testid={`product-list-item-${product.kind}`}\n >\n <ProductInsightsCard\n product={product}\n onSelectAsync={onSelectAsync}\n initialState={{ entity: entity, duration: duration }}\n />\n </Box>\n ))}\n </Collapse>\n );\n};\n"],"names":[],"mappings":";;;;;;AAiCO,MAAM,0BAA0B,CAAC;AAAA,EACtC,aAAA;AAAA,EACA;AACF,CAAoC,KAAA;AAClC,EAAI,IAAA,CAAC,cAAc,MAAQ,EAAA;AACzB,IACE,uBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,OAAA,EAAQ,MAAO,EAAA,cAAA,EAAe,gBAAe,UAAW,EAAA,QAAA,EAAA,kBAC1D,KAAA,CAAA,aAAA,CAAA,gBAAA,EAAA,IAAiB,CACpB,CAAA;AAAA;AAIJ,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,EAAE,EAAA,IAAA,EAAC,OAAS,EAAA,GAAA,EAAA,EACnB,aAAc,CAAA,GAAA,CAAI,CAAC,EAAE,OAAS,EAAA,MAAA,EAAQ,UACrC,qBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,KAAK,OAAQ,CAAA,IAAA;AAAA,MACb,EAAI,EAAA,CAAA;AAAA,MACJ,QAAS,EAAA,UAAA;AAAA,MACT,aAAA,EAAa,CAAqB,kBAAA,EAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,KAAA;AAAA,oBAE9C,KAAA,CAAA,aAAA;AAAA,MAAC,mBAAA;AAAA,MAAA;AAAA,QACC,OAAA;AAAA,QACA,aAAA;AAAA,QACA,YAAA,EAAc,EAAE,MAAA,EAAgB,QAAmB;AAAA;AAAA;AACrD,GAEH,CACH,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductInsightsChart.esm.js","sources":["../../../src/components/ProductInsightsCard/ProductInsightsChart.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, { useMemo, useState } from 'react';\nimport pluralize from 'pluralize';\nimport Box from '@material-ui/core/Box';\nimport Typography from '@material-ui/core/Typography';\nimport { default as FullScreenIcon } from '@material-ui/icons/Fullscreen';\nimport { LegendItem } from '../LegendItem';\nimport { ProductEntityDialog } from './ProductEntityDialog';\nimport { CostGrowth, CostGrowthIndicator } from '../CostGrowth';\nimport {\n BarChart,\n BarChartLegend,\n BarChartTooltip,\n BarChartTooltipItem,\n BarChartLegendOptions,\n} from '../BarChart';\nimport {\n findAlways,\n notEmpty,\n isUndefined,\n findAnyKey,\n assertAlways,\n} from '../../utils/assert';\nimport { formatPeriod, formatChange } from '../../utils/formatters';\nimport {\n titleOf,\n tooltipItemOf,\n resourceOf,\n isInvalid,\n isLabeled,\n isUnlabeled,\n} from '../../utils/graphs';\nimport {\n useProductInsightsChartStyles as useStyles,\n useBarChartLayoutStyles as useLayoutStyles,\n} from '../../utils/styles';\nimport { Duration } from '../../types';\nimport {\n Entity,\n Maybe,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { choose } from '../../utils/change';\nimport { TooltipRenderer } from '../../types';\nimport { useConfig } from '../../hooks';\n\nexport type ProductInsightsChartProps = {\n billingDate: string;\n entity: Entity;\n duration: Duration;\n};\n\nexport const ProductInsightsChart = ({\n billingDate,\n entity,\n duration,\n}: ProductInsightsChartProps) => {\n const classes = useStyles();\n const layoutClasses = useLayoutStyles();\n const { baseCurrency } = useConfig();\n\n // Only a single entities Record for the root product entity is supported\n const entities = useMemo(() => {\n const entityLabel = assertAlways(findAnyKey(entity.entities));\n return entity.entities[entityLabel] ?? [];\n }, [entity]);\n\n const [activeLabel, setActive] = useState<Maybe<string>>();\n const [selectLabel, setSelected] = useState<Maybe<string>>();\n const isSelected = useMemo(() => !isUndefined(selectLabel), [selectLabel]);\n\n const isClickable = useMemo(() => {\n const breakdowns = Object.keys(\n entities.find(e => e.id === activeLabel)?.entities ?? {},\n );\n return breakdowns.length > 0;\n }, [entities, activeLabel]);\n\n const costStart = entity.aggregation[0];\n const costEnd = entity.aggregation[1];\n const resources = entities.map(resourceOf);\n\n const options: Partial<BarChartLegendOptions> = {\n previousName: formatPeriod(duration, billingDate, false),\n currentName: formatPeriod(duration, billingDate, true),\n };\n\n const onMouseMove: (...args: any[]) => void = (\n data: Record<'activeLabel', string | undefined>,\n ) => {\n if (isLabeled(data)) {\n setActive(data.activeLabel!);\n } else if (isUnlabeled(data)) {\n setActive(null);\n } else {\n setActive(undefined);\n }\n };\n\n const onClick: (...args: any[]) => void = (\n data: Record<'activeLabel', string>,\n ) => {\n if (isLabeled(data)) {\n setSelected(data.activeLabel);\n } else if (isUnlabeled(data)) {\n setSelected(null);\n } else {\n setSelected(undefined);\n }\n };\n\n const renderProductInsightsTooltip: TooltipRenderer = ({\n label,\n payload = [],\n }) => {\n /* Labels and payloads may be undefined or empty */\n if (isInvalid({ label, payload })) return null;\n\n /*\n * recharts coerces null values to strings\n * entity -> resource -> payload\n * { id: null } -> { name: null } -> { label: '' }\n */\n const id = label === '' ? null : label;\n\n const title = titleOf(label);\n const items = payload.map(tooltipItemOf(baseCurrency)).filter(notEmpty);\n\n const activeEntity = findAlways(entities, e => e.id === id);\n const breakdowns = Object.keys(activeEntity.entities);\n\n if (breakdowns.length) {\n const subtitle = breakdowns\n .map(b => pluralize(b, activeEntity.entities[b].length, true))\n .join(', ');\n return (\n <BarChartTooltip\n title={title}\n subtitle={subtitle}\n topRight={\n !!activeEntity.change.ratio && (\n <CostGrowthIndicator\n formatter={formatChange}\n change={activeEntity.change}\n className={classes.indicator}\n />\n )\n }\n actions={\n <Box className={classes.actions}>\n <FullScreenIcon />\n <Typography>Click for breakdown</Typography>\n </Box>\n }\n >\n {items.map((item, index) => (\n <BarChartTooltipItem key={`${item.label}-${index}`} item={item} />\n ))}\n </BarChartTooltip>\n );\n }\n\n // If an entity doesn't have any sub-entities, there aren't any costs to break down.\n return (\n <BarChartTooltip\n title={title}\n topRight={\n !!activeEntity.change.ratio && (\n <CostGrowthIndicator\n formatter={formatChange}\n change={activeEntity.change}\n className={classes.indicator}\n />\n )\n }\n content={\n id\n ? null\n : \"This product has costs that are not labeled and therefore can't be attributed to a specific entity.\"\n }\n >\n {items.map((item, index) => (\n <BarChartTooltipItem key={`${item.label}-${index}`} item={item} />\n ))}\n </BarChartTooltip>\n );\n };\n\n const barChartProps = isClickable ? { onClick } : {};\n\n return (\n <Box className={layoutClasses.wrapper}>\n <BarChartLegend costStart={costStart} costEnd={costEnd} options={options}>\n <LegendItem\n title={choose(['Cost Savings', 'Cost Excess'], entity.change)}\n >\n <CostGrowth change={entity.change} duration={duration} />\n </LegendItem>\n </BarChartLegend>\n <BarChart\n resources={resources}\n tooltip={renderProductInsightsTooltip}\n onMouseMove={onMouseMove}\n options={options}\n {...barChartProps}\n />\n {isSelected && entities.length && (\n <ProductEntityDialog\n open={isSelected}\n onClose={() => setSelected(undefined)}\n entity={findAlways(entities, e => e.id === selectLabel)}\n options={options}\n />\n )}\n </Box>\n );\n};\n"],"names":["useStyles","useLayoutStyles"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProductInsightsChart.esm.js","sources":["../../../src/components/ProductInsightsCard/ProductInsightsChart.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, { useMemo, useState } from 'react';\nimport pluralize from 'pluralize';\nimport Box from '@material-ui/core/Box';\nimport Typography from '@material-ui/core/Typography';\nimport { default as FullScreenIcon } from '@material-ui/icons/Fullscreen';\nimport { LegendItem } from '../LegendItem';\nimport { ProductEntityDialog } from './ProductEntityDialog';\nimport { CostGrowth, CostGrowthIndicator } from '../CostGrowth';\nimport {\n BarChart,\n BarChartLegend,\n BarChartTooltip,\n BarChartTooltipItem,\n BarChartLegendOptions,\n} from '../BarChart';\nimport {\n findAlways,\n notEmpty,\n isUndefined,\n findAnyKey,\n assertAlways,\n} from '../../utils/assert';\nimport { formatPeriod, formatChange } from '../../utils/formatters';\nimport {\n titleOf,\n tooltipItemOf,\n resourceOf,\n isInvalid,\n isLabeled,\n isUnlabeled,\n} from '../../utils/graphs';\nimport {\n useProductInsightsChartStyles as useStyles,\n useBarChartLayoutStyles as useLayoutStyles,\n} from '../../utils/styles';\nimport { Duration } from '../../types';\nimport {\n Entity,\n Maybe,\n} from '@backstage-community/plugin-cost-insights-common';\nimport { choose } from '../../utils/change';\nimport { TooltipRenderer } from '../../types';\nimport { useConfig } from '../../hooks';\n\nexport type ProductInsightsChartProps = {\n billingDate: string;\n entity: Entity;\n duration: Duration;\n};\n\nexport const ProductInsightsChart = ({\n billingDate,\n entity,\n duration,\n}: ProductInsightsChartProps) => {\n const classes = useStyles();\n const layoutClasses = useLayoutStyles();\n const { baseCurrency } = useConfig();\n\n // Only a single entities Record for the root product entity is supported\n const entities = useMemo(() => {\n const entityLabel = assertAlways(findAnyKey(entity.entities));\n return entity.entities[entityLabel] ?? [];\n }, [entity]);\n\n const [activeLabel, setActive] = useState<Maybe<string>>();\n const [selectLabel, setSelected] = useState<Maybe<string>>();\n const isSelected = useMemo(() => !isUndefined(selectLabel), [selectLabel]);\n\n const isClickable = useMemo(() => {\n const breakdowns = Object.keys(\n entities.find(e => e.id === activeLabel)?.entities ?? {},\n );\n return breakdowns.length > 0;\n }, [entities, activeLabel]);\n\n const costStart = entity.aggregation[0];\n const costEnd = entity.aggregation[1];\n const resources = entities.map(resourceOf);\n\n const options: Partial<BarChartLegendOptions> = {\n previousName: formatPeriod(duration, billingDate, false),\n currentName: formatPeriod(duration, billingDate, true),\n };\n\n const onMouseMove: (...args: any[]) => void = (\n data: Record<'activeLabel', string | undefined>,\n ) => {\n if (isLabeled(data)) {\n setActive(data.activeLabel!);\n } else if (isUnlabeled(data)) {\n setActive(null);\n } else {\n setActive(undefined);\n }\n };\n\n const onClick: (...args: any[]) => void = (\n data: Record<'activeLabel', string>,\n ) => {\n if (isLabeled(data)) {\n setSelected(data.activeLabel);\n } else if (isUnlabeled(data)) {\n setSelected(null);\n } else {\n setSelected(undefined);\n }\n };\n\n const renderProductInsightsTooltip: TooltipRenderer = ({\n label,\n payload = [],\n }) => {\n /* Labels and payloads may be undefined or empty */\n if (isInvalid({ label, payload })) return null;\n\n /*\n * recharts coerces null values to strings\n * entity -> resource -> payload\n * { id: null } -> { name: null } -> { label: '' }\n */\n const id = label === '' ? null : label;\n\n const title = titleOf(label);\n const items = payload.map(tooltipItemOf(baseCurrency)).filter(notEmpty);\n\n const activeEntity = findAlways(entities, e => e.id === id);\n const breakdowns = Object.keys(activeEntity.entities);\n\n if (breakdowns.length) {\n const subtitle = breakdowns\n .map(b => pluralize(b, activeEntity.entities[b].length, true))\n .join(', ');\n return (\n <BarChartTooltip\n title={title}\n subtitle={subtitle}\n topRight={\n !!activeEntity.change.ratio && (\n <CostGrowthIndicator\n formatter={formatChange}\n change={activeEntity.change}\n className={classes.indicator}\n />\n )\n }\n actions={\n <Box className={classes.actions}>\n <FullScreenIcon />\n <Typography>Click for breakdown</Typography>\n </Box>\n }\n >\n {items.map((item, index) => (\n <BarChartTooltipItem key={`${item.label}-${index}`} item={item} />\n ))}\n </BarChartTooltip>\n );\n }\n\n // If an entity doesn't have any sub-entities, there aren't any costs to break down.\n return (\n <BarChartTooltip\n title={title}\n topRight={\n !!activeEntity.change.ratio && (\n <CostGrowthIndicator\n formatter={formatChange}\n change={activeEntity.change}\n className={classes.indicator}\n />\n )\n }\n content={\n id\n ? null\n : \"This product has costs that are not labeled and therefore can't be attributed to a specific entity.\"\n }\n >\n {items.map((item, index) => (\n <BarChartTooltipItem key={`${item.label}-${index}`} item={item} />\n ))}\n </BarChartTooltip>\n );\n };\n\n const barChartProps = isClickable ? { onClick } : {};\n\n return (\n <Box className={layoutClasses.wrapper}>\n <BarChartLegend costStart={costStart} costEnd={costEnd} options={options}>\n <LegendItem\n title={choose(['Cost Savings', 'Cost Excess'], entity.change)}\n >\n <CostGrowth change={entity.change} duration={duration} />\n </LegendItem>\n </BarChartLegend>\n <BarChart\n resources={resources}\n tooltip={renderProductInsightsTooltip}\n onMouseMove={onMouseMove}\n options={options}\n {...barChartProps}\n />\n {isSelected && entities.length && (\n <ProductEntityDialog\n open={isSelected}\n onClose={() => setSelected(undefined)}\n entity={findAlways(entities, e => e.id === selectLabel)}\n options={options}\n />\n )}\n </Box>\n );\n};\n"],"names":["useStyles","useLayoutStyles"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAkEO,MAAM,uBAAuB,CAAC;AAAA,EACnC,WAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAiC,KAAA;AAC/B,EAAA,MAAM,UAAUA,6BAAU,EAAA;AAC1B,EAAA,MAAM,gBAAgBC,uBAAgB,EAAA;AACtC,EAAM,MAAA,EAAE,YAAa,EAAA,GAAI,SAAU,EAAA;AAGnC,EAAM,MAAA,QAAA,GAAW,QAAQ,MAAM;AAC7B,IAAA,MAAM,WAAc,GAAA,YAAA,CAAa,UAAW,CAAA,MAAA,CAAO,QAAQ,CAAC,CAAA;AAC5D,IAAA,OAAO,MAAO,CAAA,QAAA,CAAS,WAAW,CAAA,IAAK,EAAC;AAAA,GAC1C,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,MAAM,CAAC,WAAA,EAAa,SAAS,CAAA,GAAI,QAAwB,EAAA;AACzD,EAAA,MAAM,CAAC,WAAA,EAAa,WAAW,CAAA,GAAI,QAAwB,EAAA;AAC3D,EAAM,MAAA,UAAA,GAAa,QAAQ,MAAM,CAAC,YAAY,WAAW,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAEzE,EAAM,MAAA,WAAA,GAAc,QAAQ,MAAM;AAChC,IAAA,MAAM,aAAa,MAAO,CAAA,IAAA;AAAA,MACxB,QAAA,CAAS,KAAK,CAAK,CAAA,KAAA,CAAA,CAAE,OAAO,WAAW,CAAA,EAAG,YAAY;AAAC,KACzD;AACA,IAAA,OAAO,WAAW,MAAS,GAAA,CAAA;AAAA,GAC1B,EAAA,CAAC,QAAU,EAAA,WAAW,CAAC,CAAA;AAE1B,EAAM,MAAA,SAAA,GAAY,MAAO,CAAA,WAAA,CAAY,CAAC,CAAA;AACtC,EAAM,MAAA,OAAA,GAAU,MAAO,CAAA,WAAA,CAAY,CAAC,CAAA;AACpC,EAAM,MAAA,SAAA,GAAY,QAAS,CAAA,GAAA,CAAI,UAAU,CAAA;AAEzC,EAAA,MAAM,OAA0C,GAAA;AAAA,IAC9C,YAAc,EAAA,YAAA,CAAa,QAAU,EAAA,WAAA,EAAa,KAAK,CAAA;AAAA,IACvD,WAAa,EAAA,YAAA,CAAa,QAAU,EAAA,WAAA,EAAa,IAAI;AAAA,GACvD;AAEA,EAAM,MAAA,WAAA,GAAwC,CAC5C,IACG,KAAA;AACH,IAAI,IAAA,SAAA,CAAU,IAAI,CAAG,EAAA;AACnB,MAAA,SAAA,CAAU,KAAK,WAAY,CAAA;AAAA,KAC7B,MAAA,IAAW,WAAY,CAAA,IAAI,CAAG,EAAA;AAC5B,MAAA,SAAA,CAAU,IAAI,CAAA;AAAA,KACT,MAAA;AACL,MAAA,SAAA,CAAU,KAAS,CAAA,CAAA;AAAA;AACrB,GACF;AAEA,EAAM,MAAA,OAAA,GAAoC,CACxC,IACG,KAAA;AACH,IAAI,IAAA,SAAA,CAAU,IAAI,CAAG,EAAA;AACnB,MAAA,WAAA,CAAY,KAAK,WAAW,CAAA;AAAA,KAC9B,MAAA,IAAW,WAAY,CAAA,IAAI,CAAG,EAAA;AAC5B,MAAA,WAAA,CAAY,IAAI,CAAA;AAAA,KACX,MAAA;AACL,MAAA,WAAA,CAAY,KAAS,CAAA,CAAA;AAAA;AACvB,GACF;AAEA,EAAA,MAAM,+BAAgD,CAAC;AAAA,IACrD,KAAA;AAAA,IACA,UAAU;AAAC,GACP,KAAA;AAEJ,IAAA,IAAI,UAAU,EAAE,KAAA,EAAO,OAAQ,EAAC,GAAU,OAAA,IAAA;AAO1C,IAAM,MAAA,EAAA,GAAK,KAAU,KAAA,EAAA,GAAK,IAAO,GAAA,KAAA;AAEjC,IAAM,MAAA,KAAA,GAAQ,QAAQ,KAAK,CAAA;AAC3B,IAAM,MAAA,KAAA,GAAQ,QAAQ,GAAI,CAAA,aAAA,CAAc,YAAY,CAAC,CAAA,CAAE,OAAO,QAAQ,CAAA;AAEtE,IAAA,MAAM,eAAe,UAAW,CAAA,QAAA,EAAU,CAAK,CAAA,KAAA,CAAA,CAAE,OAAO,EAAE,CAAA;AAC1D,IAAA,MAAM,UAAa,GAAA,MAAA,CAAO,IAAK,CAAA,YAAA,CAAa,QAAQ,CAAA;AAEpD,IAAA,IAAI,WAAW,MAAQ,EAAA;AACrB,MAAA,MAAM,QAAW,GAAA,UAAA,CACd,GAAI,CAAA,CAAA,CAAA,KAAK,UAAU,CAAG,EAAA,YAAA,CAAa,QAAS,CAAA,CAAC,EAAE,MAAQ,EAAA,IAAI,CAAC,CAAA,CAC5D,KAAK,IAAI,CAAA;AACZ,MACE,uBAAA,KAAA,CAAA,aAAA;AAAA,QAAC,eAAA;AAAA,QAAA;AAAA,UACC,KAAA;AAAA,UACA,QAAA;AAAA,UACA,QACE,EAAA,CAAC,CAAC,YAAA,CAAa,OAAO,KACpB,oBAAA,KAAA,CAAA,aAAA;AAAA,YAAC,mBAAA;AAAA,YAAA;AAAA,cACC,SAAW,EAAA,YAAA;AAAA,cACX,QAAQ,YAAa,CAAA,MAAA;AAAA,cACrB,WAAW,OAAQ,CAAA;AAAA;AAAA,WACrB;AAAA,UAGJ,OACE,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,OAAA,EAAA,kBACrB,KAAA,CAAA,aAAA,CAAA,cAAA,EAAA,IAAe,CAChB,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,IAAA,EAAA,qBAAmB,CACjC;AAAA,SAAA;AAAA,QAGD,KAAM,CAAA,GAAA,CAAI,CAAC,IAAA,EAAM,0BACf,KAAA,CAAA,aAAA,CAAA,mBAAA,EAAA,EAAoB,GAAK,EAAA,CAAA,EAAG,KAAK,KAAK,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,MAAY,CACjE;AAAA,OACH;AAAA;AAKJ,IACE,uBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,eAAA;AAAA,MAAA;AAAA,QACC,KAAA;AAAA,QACA,QACE,EAAA,CAAC,CAAC,YAAA,CAAa,OAAO,KACpB,oBAAA,KAAA,CAAA,aAAA;AAAA,UAAC,mBAAA;AAAA,UAAA;AAAA,YACC,SAAW,EAAA,YAAA;AAAA,YACX,QAAQ,YAAa,CAAA,MAAA;AAAA,YACrB,WAAW,OAAQ,CAAA;AAAA;AAAA,SACrB;AAAA,QAGJ,OAAA,EACE,KACI,IACA,GAAA;AAAA,OAAA;AAAA,MAGL,KAAM,CAAA,GAAA,CAAI,CAAC,IAAA,EAAM,0BACf,KAAA,CAAA,aAAA,CAAA,mBAAA,EAAA,EAAoB,GAAK,EAAA,CAAA,EAAG,KAAK,KAAK,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,MAAY,CACjE;AAAA,KACH;AAAA,GAEJ;AAEA,EAAA,MAAM,aAAgB,GAAA,WAAA,GAAc,EAAE,OAAA,KAAY,EAAC;AAEnD,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,OAAI,SAAW,EAAA,aAAA,CAAc,2BAC3B,KAAA,CAAA,aAAA,CAAA,cAAA,EAAA,EAAe,SAAsB,EAAA,OAAA,EAAkB,OACtD,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,OAAO,MAAO,CAAA,CAAC,gBAAgB,aAAa,CAAA,EAAG,OAAO,MAAM;AAAA,KAAA;AAAA,oBAE3D,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,MAAQ,EAAA,MAAA,CAAO,QAAQ,QAAoB,EAAA;AAAA,GAE3D,CACA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,SAAA;AAAA,MACA,OAAS,EAAA,4BAAA;AAAA,MACT,WAAA;AAAA,MACA,OAAA;AAAA,MACC,GAAG;AAAA;AAAA,GACN,EACC,UAAc,IAAA,QAAA,CAAS,MACtB,oBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,mBAAA;AAAA,IAAA;AAAA,MACC,IAAM,EAAA,UAAA;AAAA,MACN,OAAA,EAAS,MAAM,WAAA,CAAY,KAAS,CAAA,CAAA;AAAA,MACpC,QAAQ,UAAW,CAAA,QAAA,EAAU,CAAK,CAAA,KAAA,CAAA,CAAE,OAAO,WAAW,CAAA;AAAA,MACtD;AAAA;AAAA,GAGN,CAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectGrowthAlertCard.esm.js","sources":["../../../src/components/ProjectGrowthAlertCard/ProjectGrowthAlertCard.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport pluralize from 'pluralize';\nimport { ProjectGrowthAlertChart } from './ProjectGrowthAlertChart';\nimport { ProjectGrowthData } from '../../types';\nimport { InfoCard } from '@backstage/core-components';\n\ntype ProjectGrowthAlertProps = {\n alert: ProjectGrowthData;\n};\n\nexport const ProjectGrowthAlertCard = ({ alert }: ProjectGrowthAlertProps) => {\n const subheader = `\n ${pluralize('product', alert.products.length, true)}${\n alert.products.length > 1 ? ', sorted by cost' : ''\n }`;\n\n return (\n <InfoCard\n title={`Project growth for ${alert.project}`}\n subheader={subheader}\n >\n <ProjectGrowthAlertChart alert={alert} />\n </InfoCard>\n );\n};\n"],"names":[],"mappings":";;;;;AA0BO,MAAM,sBAAyB,GAAA,CAAC,EAAE,KAAA,EAAqC,KAAA;AAC5E,EAAA,MAAM,SAAY,GAAA
|
|
1
|
+
{"version":3,"file":"ProjectGrowthAlertCard.esm.js","sources":["../../../src/components/ProjectGrowthAlertCard/ProjectGrowthAlertCard.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport pluralize from 'pluralize';\nimport { ProjectGrowthAlertChart } from './ProjectGrowthAlertChart';\nimport { ProjectGrowthData } from '../../types';\nimport { InfoCard } from '@backstage/core-components';\n\ntype ProjectGrowthAlertProps = {\n alert: ProjectGrowthData;\n};\n\nexport const ProjectGrowthAlertCard = ({ alert }: ProjectGrowthAlertProps) => {\n const subheader = `\n ${pluralize('product', alert.products.length, true)}${\n alert.products.length > 1 ? ', sorted by cost' : ''\n }`;\n\n return (\n <InfoCard\n title={`Project growth for ${alert.project}`}\n subheader={subheader}\n >\n <ProjectGrowthAlertChart alert={alert} />\n </InfoCard>\n );\n};\n"],"names":[],"mappings":";;;;;AA0BO,MAAM,sBAAyB,GAAA,CAAC,EAAE,KAAA,EAAqC,KAAA;AAC5E,EAAA,MAAM,SAAY,GAAA;AAAA,IAAA,EACd,SAAU,CAAA,SAAA,EAAW,KAAM,CAAA,QAAA,CAAS,MAAQ,EAAA,IAAI,CAAC,CAAA,EACnD,KAAM,CAAA,QAAA,CAAS,MAAS,GAAA,CAAA,GAAI,qBAAqB,EACnD,CAAA,CAAA;AAEA,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAsB,mBAAA,EAAA,KAAA,CAAM,OAAO,CAAA,CAAA;AAAA,MAC1C;AAAA,KAAA;AAAA,oBAEA,KAAA,CAAA,aAAA,CAAC,2BAAwB,KAAc,EAAA;AAAA,GACzC;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectGrowthAlertChart.esm.js","sources":["../../../src/components/ProjectGrowthAlertCard/ProjectGrowthAlertChart.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { DateTime } from 'luxon';\nimport Box from '@material-ui/core/Box';\nimport { BarChart, BarChartLegend, BarChartLegendOptions } from '../BarChart';\nimport { LegendItem } from '../LegendItem';\nimport { CostGrowth } from '../CostGrowth';\nimport { Duration, ProjectGrowthData } from '../../types';\nimport { useBarChartLayoutStyles as useStyles } from '../../utils/styles';\nimport { resourceOf } from '../../utils/graphs';\n\ntype ProjectGrowthAlertChartProps = {\n alert: ProjectGrowthData;\n};\n\nexport const ProjectGrowthAlertChart = ({\n alert,\n}: ProjectGrowthAlertChartProps) => {\n const classes = useStyles();\n\n const costStart = alert.aggregation[0];\n const costEnd = alert.aggregation[1];\n const resourceData = alert.products.map(resourceOf);\n\n const options: Partial<BarChartLegendOptions> = {\n previousName: DateTime.fromFormat(alert.periodStart, \"yyyy-'Q'q\").toFormat(\n \"'Q'q yyyy\",\n ),\n currentName: DateTime.fromFormat(alert.periodEnd, \"yyyy-'Q'q\").toFormat(\n \"'Q'q yyyy\",\n ),\n };\n\n return (\n <Box className={classes.wrapper}>\n <BarChartLegend costStart={costStart} costEnd={costEnd} options={options}>\n <LegendItem title=\"Cost Growth\">\n <CostGrowth change={alert.change} duration={Duration.P3M} />\n </LegendItem>\n </BarChartLegend>\n <BarChart resources={resourceData} options={options} />\n </Box>\n );\n};\n"],"names":["useStyles"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA8BO,MAAM,0BAA0B,CAAC;AAAA,EACtC
|
|
1
|
+
{"version":3,"file":"ProjectGrowthAlertChart.esm.js","sources":["../../../src/components/ProjectGrowthAlertCard/ProjectGrowthAlertChart.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { DateTime } from 'luxon';\nimport Box from '@material-ui/core/Box';\nimport { BarChart, BarChartLegend, BarChartLegendOptions } from '../BarChart';\nimport { LegendItem } from '../LegendItem';\nimport { CostGrowth } from '../CostGrowth';\nimport { Duration, ProjectGrowthData } from '../../types';\nimport { useBarChartLayoutStyles as useStyles } from '../../utils/styles';\nimport { resourceOf } from '../../utils/graphs';\n\ntype ProjectGrowthAlertChartProps = {\n alert: ProjectGrowthData;\n};\n\nexport const ProjectGrowthAlertChart = ({\n alert,\n}: ProjectGrowthAlertChartProps) => {\n const classes = useStyles();\n\n const costStart = alert.aggregation[0];\n const costEnd = alert.aggregation[1];\n const resourceData = alert.products.map(resourceOf);\n\n const options: Partial<BarChartLegendOptions> = {\n previousName: DateTime.fromFormat(alert.periodStart, \"yyyy-'Q'q\").toFormat(\n \"'Q'q yyyy\",\n ),\n currentName: DateTime.fromFormat(alert.periodEnd, \"yyyy-'Q'q\").toFormat(\n \"'Q'q yyyy\",\n ),\n };\n\n return (\n <Box className={classes.wrapper}>\n <BarChartLegend costStart={costStart} costEnd={costEnd} options={options}>\n <LegendItem title=\"Cost Growth\">\n <CostGrowth change={alert.change} duration={Duration.P3M} />\n </LegendItem>\n </BarChartLegend>\n <BarChart resources={resourceData} options={options} />\n </Box>\n );\n};\n"],"names":["useStyles"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA8BO,MAAM,0BAA0B,CAAC;AAAA,EACtC;AACF,CAAoC,KAAA;AAClC,EAAA,MAAM,UAAUA,uBAAU,EAAA;AAE1B,EAAM,MAAA,SAAA,GAAY,KAAM,CAAA,WAAA,CAAY,CAAC,CAAA;AACrC,EAAM,MAAA,OAAA,GAAU,KAAM,CAAA,WAAA,CAAY,CAAC,CAAA;AACnC,EAAA,MAAM,YAAe,GAAA,KAAA,CAAM,QAAS,CAAA,GAAA,CAAI,UAAU,CAAA;AAElD,EAAA,MAAM,OAA0C,GAAA;AAAA,IAC9C,cAAc,QAAS,CAAA,UAAA,CAAW,KAAM,CAAA,WAAA,EAAa,WAAW,CAAE,CAAA,QAAA;AAAA,MAChE;AAAA,KACF;AAAA,IACA,aAAa,QAAS,CAAA,UAAA,CAAW,KAAM,CAAA,SAAA,EAAW,WAAW,CAAE,CAAA,QAAA;AAAA,MAC7D;AAAA;AACF,GACF;AAEA,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,OACtB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAe,EAAA,EAAA,SAAA,EAAsB,OAAkB,EAAA,OAAA,EAAA,kBACrD,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAM,aAChB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,MAAA,EAAQ,KAAM,CAAA,MAAA,EAAQ,QAAU,EAAA,QAAA,CAAS,GAAK,EAAA,CAC5D,CACF,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,SAAW,EAAA,YAAA,EAAc,SAAkB,CACvD,CAAA;AAEJ;;;;"}
|