@red-hat-developer-hub/backstage-plugin-scorecard 2.3.5 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/components/Common/ErrorTooltip.esm.js +25 -0
  3. package/dist/components/Common/ErrorTooltip.esm.js.map +1 -0
  4. package/dist/components/Scorecard/CustomLegend.esm.js +13 -5
  5. package/dist/components/Scorecard/CustomLegend.esm.js.map +1 -1
  6. package/dist/components/Scorecard/EntityScorecardContent.esm.js +4 -2
  7. package/dist/components/Scorecard/EntityScorecardContent.esm.js.map +1 -1
  8. package/dist/components/Scorecard/Scorecard.esm.js +154 -71
  9. package/dist/components/Scorecard/Scorecard.esm.js.map +1 -1
  10. package/dist/components/ScorecardHomepageSection/CustomLegend.esm.js +7 -1
  11. package/dist/components/ScorecardHomepageSection/CustomLegend.esm.js.map +1 -1
  12. package/dist/components/ScorecardHomepageSection/CustomTooltip.esm.js.map +1 -1
  13. package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js +42 -49
  14. package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js.map +1 -1
  15. package/dist/components/ScorecardHomepageSection/ResponsivePieChart.esm.js +27 -1
  16. package/dist/components/ScorecardHomepageSection/ResponsivePieChart.esm.js.map +1 -1
  17. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCardComponent.esm.js +9 -5
  18. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCardComponent.esm.js.map +1 -1
  19. package/dist/index.d.ts +2 -0
  20. package/dist/index.esm.js +2 -0
  21. package/dist/index.esm.js.map +1 -1
  22. package/dist/translations/de.esm.js +7 -31
  23. package/dist/translations/de.esm.js.map +1 -1
  24. package/dist/translations/es.esm.js +9 -33
  25. package/dist/translations/es.esm.js.map +1 -1
  26. package/dist/utils/chartLabelUtils.esm.js +23 -0
  27. package/dist/utils/chartLabelUtils.esm.js.map +1 -0
  28. package/dist/utils/colorUtils.esm.js +38 -0
  29. package/dist/utils/colorUtils.esm.js.map +1 -0
  30. package/dist/utils/constants.esm.js +4 -0
  31. package/dist/utils/constants.esm.js.map +1 -0
  32. package/dist/utils/statusUtils.esm.js +32 -0
  33. package/dist/utils/statusUtils.esm.js.map +1 -0
  34. package/package.json +2 -2
  35. package/dist/utils/utils.esm.js +0 -31
  36. package/dist/utils/utils.esm.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @red-hat-developer-hub/backstage-plugin-scorecard
2
2
 
3
+ ## 2.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7062658: Introduces custom threshold rule keys and colors that can be configured in `app-config.yaml`.
8
+
9
+ ### Patch Changes
10
+
11
+ - 10aabb3: Fix tooltip display and error title clipping for some languages
12
+ - f6d5102: Translation updated for German and Spanish
13
+ - 34fc6c4: Fix Scorecard translations not working in cluster
14
+ - Updated dependencies [7062658]
15
+ - @red-hat-developer-hub/backstage-plugin-scorecard-common@2.4.0
16
+
3
17
  ## 2.3.5
4
18
 
5
19
  ### Patch Changes
@@ -0,0 +1,25 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import MuiTooltip from '@mui/material/Tooltip';
3
+
4
+ const ErrorTooltip = ({
5
+ title,
6
+ tooltipPosition
7
+ }) => {
8
+ if (!title || !tooltipPosition) {
9
+ return null;
10
+ }
11
+ return /* @__PURE__ */ jsx(
12
+ "div",
13
+ {
14
+ style: {
15
+ position: "absolute",
16
+ left: tooltipPosition?.x,
17
+ top: tooltipPosition?.y
18
+ },
19
+ children: /* @__PURE__ */ jsx(MuiTooltip, { open: true, title, placement: "bottom", arrow: true, children: /* @__PURE__ */ jsx("div", { style: { visibility: "hidden" }, children: "Tooltip" }) })
20
+ }
21
+ );
22
+ };
23
+
24
+ export { ErrorTooltip };
25
+ //# sourceMappingURL=ErrorTooltip.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorTooltip.esm.js","sources":["../../../src/components/Common/ErrorTooltip.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 MuiTooltip from '@mui/material/Tooltip';\n\nexport const ErrorTooltip = ({\n title,\n tooltipPosition,\n}: {\n title: string | undefined;\n tooltipPosition: { x: number; y: number } | undefined;\n}) => {\n if (!title || !tooltipPosition) {\n return null;\n }\n\n return (\n <div\n style={{\n position: 'absolute',\n left: tooltipPosition?.x,\n top: tooltipPosition?.y,\n }}\n >\n <MuiTooltip open title={title} placement=\"bottom\" arrow>\n {/* Anchor for tooltip so it appears under the pie chart */}\n <div style={{ visibility: 'hidden' }}>Tooltip</div>\n </MuiTooltip>\n </div>\n );\n};\n"],"names":[],"mappings":";;;AAkBO,MAAM,eAAe,CAAC;AAAA,EAC3B,KAAA;AAAA,EACA;AACF,CAGM,KAAA;AACJ,EAAI,IAAA,CAAC,KAAS,IAAA,CAAC,eAAiB,EAAA;AAC9B,IAAO,OAAA,IAAA;AAAA;AAGT,EACE,uBAAA,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAO,EAAA;AAAA,QACL,QAAU,EAAA,UAAA;AAAA,QACV,MAAM,eAAiB,EAAA,CAAA;AAAA,QACvB,KAAK,eAAiB,EAAA;AAAA,OACxB;AAAA,MAEA,8BAAC,UAAW,EAAA,EAAA,IAAA,EAAI,IAAC,EAAA,KAAA,EAAc,WAAU,QAAS,EAAA,KAAA,EAAK,IAErD,EAAA,QAAA,kBAAA,GAAA,CAAC,SAAI,KAAO,EAAA,EAAE,YAAY,QAAS,EAAA,EAAG,qBAAO,CAC/C,EAAA;AAAA;AAAA,GACF;AAEJ;;;;"}
@@ -3,6 +3,11 @@ import Box from '@mui/material/Box';
3
3
  import Typography from '@mui/material/Typography';
4
4
  import { useTheme, styled } from '@mui/material/styles';
5
5
  import { useTranslation } from '../../hooks/useTranslation.esm.js';
6
+ import { resolveStatusColor, getThresholdRuleColor } from '../../utils/colorUtils.esm.js';
7
+ import { SCORECARD_ERROR_STATE_COLOR } from '../../utils/constants.esm.js';
8
+ import '@mui/icons-material/WarningAmber';
9
+ import '@mui/icons-material/CheckCircleOutline';
10
+ import '@mui/icons-material/DangerousOutlined';
6
11
 
7
12
  const StyledLegend = styled(Box)(({ theme }) => ({
8
13
  display: "flex",
@@ -37,11 +42,14 @@ const CustomLegend = (props) => {
37
42
  /* @__PURE__ */ jsx(
38
43
  StyledLegendColorBox,
39
44
  {
40
- color: {
41
- error: theme.palette.error.main,
42
- warning: theme.palette.warning.main,
43
- success: theme.palette.success.main
44
- }[ruleKey] ?? theme.palette.success.main
45
+ "data-testid": `legend-colorbox-${ruleKey}`,
46
+ color: resolveStatusColor(
47
+ theme,
48
+ getThresholdRuleColor(
49
+ thresholds.definition?.rules ?? [],
50
+ ruleKey
51
+ ) ?? SCORECARD_ERROR_STATE_COLOR
52
+ )
45
53
  }
46
54
  ),
47
55
  /* @__PURE__ */ jsxs(
@@ -1 +1 @@
1
- {"version":3,"file":"CustomLegend.esm.js","sources":["../../../src/components/Scorecard/CustomLegend.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ThresholdResult,\n ThresholdRule,\n} from '@red-hat-developer-hub/backstage-plugin-scorecard-common';\n\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport { styled, useTheme } from '@mui/material/styles';\n\nimport { useTranslation } from '../../hooks/useTranslation';\n\nconst StyledLegend = styled(Box)(({ theme }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1),\n paddingLeft: theme.spacing(3.2),\n}));\n\nconst StyledLegendItem = styled(Box)(({ theme }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n}));\n\nconst StyledLegendColorBox = styled(Box)<{ color: string }>(({ color }) => ({\n width: '10px',\n height: '10px',\n backgroundColor: color,\n flexShrink: 0,\n}));\n\ntype CustomLegendProps = {\n thresholds?: ThresholdResult;\n};\n\nconst CustomLegend = (props: CustomLegendProps) => {\n const { thresholds } = props;\n const theme = useTheme();\n const { t } = useTranslation();\n\n if (\n !thresholds ||\n thresholds?.definition?.rules?.length === 0 ||\n thresholds?.definition?.rules === undefined\n ) {\n return (\n <StyledLegend>\n <StyledLegendItem>\n <StyledLegendColorBox color={theme.palette.grey['400']} /> --\n </StyledLegendItem>\n </StyledLegend>\n );\n }\n\n return (\n <StyledLegend>\n {thresholds?.definition?.rules?.map(\n ({ key: ruleKey, expression: ruleExpression }: ThresholdRule) => {\n return (\n <StyledLegendItem key={`legend-${ruleKey}`}>\n <StyledLegendColorBox\n color={\n (\n {\n error: theme.palette.error.main,\n warning: theme.palette.warning.main,\n success: theme.palette.success.main,\n } as Record<string, string>\n )[ruleKey] ?? theme.palette.success.main\n }\n />\n <Typography\n variant=\"body2\"\n sx={{ fontSize: '0.875rem', fontWeight: 400 }}\n >\n {(() => {\n const translated = t(`thresholds.${ruleKey}` as any, {});\n // If translation returns the ruleKey itself, fallback to capitalized ruleKey\n return translated === `thresholds.${ruleKey}`\n ? ruleKey.charAt(0).toUpperCase() + ruleKey.slice(1)\n : translated;\n })()}{' '}\n {ruleExpression && `${ruleExpression}`}\n </Typography>\n </StyledLegendItem>\n );\n },\n )}\n </StyledLegend>\n );\n};\n\nexport default CustomLegend;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CustomLegend.esm.js","sources":["../../../src/components/Scorecard/CustomLegend.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ThresholdResult,\n ThresholdRule,\n} from '@red-hat-developer-hub/backstage-plugin-scorecard-common';\n\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport { styled, useTheme } from '@mui/material/styles';\n\nimport { useTranslation } from '../../hooks/useTranslation';\nimport {\n getThresholdRuleColor,\n resolveStatusColor,\n SCORECARD_ERROR_STATE_COLOR,\n} from '../../utils';\n\nconst StyledLegend = styled(Box)(({ theme }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1),\n paddingLeft: theme.spacing(3.2),\n}));\n\nconst StyledLegendItem = styled(Box)(({ theme }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n}));\n\nconst StyledLegendColorBox = styled(Box)<{ color: string }>(({ color }) => ({\n width: '10px',\n height: '10px',\n backgroundColor: color,\n flexShrink: 0,\n}));\n\ntype CustomLegendProps = {\n thresholds?: ThresholdResult;\n};\n\nconst CustomLegend = (props: CustomLegendProps) => {\n const { thresholds } = props;\n const theme = useTheme();\n const { t } = useTranslation();\n\n if (\n !thresholds ||\n thresholds?.definition?.rules?.length === 0 ||\n thresholds?.definition?.rules === undefined\n ) {\n return (\n <StyledLegend>\n <StyledLegendItem>\n <StyledLegendColorBox color={theme.palette.grey['400']} /> --\n </StyledLegendItem>\n </StyledLegend>\n );\n }\n\n return (\n <StyledLegend>\n {thresholds?.definition?.rules?.map(\n ({ key: ruleKey, expression: ruleExpression }: ThresholdRule) => {\n return (\n <StyledLegendItem key={`legend-${ruleKey}`}>\n <StyledLegendColorBox\n data-testid={`legend-colorbox-${ruleKey}`}\n color={resolveStatusColor(\n theme,\n getThresholdRuleColor(\n thresholds.definition?.rules ?? [],\n ruleKey,\n ) ?? SCORECARD_ERROR_STATE_COLOR,\n )}\n />\n <Typography\n variant=\"body2\"\n sx={{ fontSize: '0.875rem', fontWeight: 400 }}\n >\n {(() => {\n const translated = t(`thresholds.${ruleKey}` as any, {});\n // If translation returns the ruleKey itself, fallback to capitalized ruleKey\n return translated === `thresholds.${ruleKey}`\n ? ruleKey.charAt(0).toUpperCase() + ruleKey.slice(1)\n : translated;\n })()}{' '}\n {ruleExpression && `${ruleExpression}`}\n </Typography>\n </StyledLegendItem>\n );\n },\n )}\n </StyledLegend>\n );\n};\n\nexport default CustomLegend;\n"],"names":[],"mappings":"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"}
@@ -5,7 +5,8 @@ import CircularProgress from '@mui/material/CircularProgress';
5
5
  import NoScorecardsState from '../Common/NoScorecardsState.esm.js';
6
6
  import Scorecard from './Scorecard.esm.js';
7
7
  import { useScorecards } from '../../hooks/useScorecards.esm.js';
8
- import { getStatusConfig } from '../../utils/utils.esm.js';
8
+ import '@red-hat-developer-hub/backstage-plugin-scorecard-common';
9
+ import { getStatusConfig } from '../../utils/statusUtils.esm.js';
9
10
  import PermissionRequiredState from '../Common/PermissionRequiredState.esm.js';
10
11
  import { useTranslation } from '../../hooks/useTranslation.esm.js';
11
12
 
@@ -46,7 +47,8 @@ const EntityScorecardContent = () => {
46
47
  const statusConfig = getStatusConfig({
47
48
  evaluation: metric.result?.thresholdResult?.evaluation,
48
49
  thresholdStatus: metric.result?.thresholdResult?.status,
49
- metricStatus: metric.status
50
+ metricStatus: metric.status,
51
+ thresholdRules: metric.result.thresholdResult.definition?.rules
50
52
  });
51
53
  const titleKey = `metric.${metric.id}.title`;
52
54
  const descriptionKey = `metric.${metric.id}.description`;
@@ -1 +1 @@
1
- {"version":3,"file":"EntityScorecardContent.esm.js","sources":["../../../src/components/Scorecard/EntityScorecardContent.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { MetricResult } from '@red-hat-developer-hub/backstage-plugin-scorecard-common';\nimport { ResponseErrorPanel } from '@backstage/core-components';\n\nimport Box from '@mui/material/Box';\nimport CircularProgress from '@mui/material/CircularProgress';\n\nimport NoScorecardsState from '../Common/NoScorecardsState';\nimport Scorecard from './Scorecard';\nimport { useScorecards } from '../../hooks/useScorecards';\nimport { getStatusConfig } from '../../utils/utils';\nimport PermissionRequiredState from '../Common/PermissionRequiredState';\nimport { useTranslation } from '../../hooks/useTranslation';\n\nexport const EntityScorecardContent = () => {\n const { scorecards, loadingData, error } = useScorecards();\n const { t } = useTranslation();\n\n if (loadingData) {\n return (\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n minHeight=\"200px\"\n >\n <CircularProgress />\n </Box>\n );\n }\n\n if (error) {\n if (error.message?.includes('NotAllowedError')) {\n return <PermissionRequiredState />;\n }\n return <ResponseErrorPanel error={error} />;\n }\n\n if (!loadingData && scorecards?.length === 0) {\n return <NoScorecardsState />;\n }\n\n return (\n <Box\n display=\"flex\"\n flexWrap=\"wrap\"\n gap={2}\n sx={{ alignItems: 'flex-start' }}\n >\n {scorecards?.map((metric: MetricResult) => {\n // Check if metric data unavailable\n const isMetricDataError =\n metric.status === 'error' || metric.result?.value === null;\n\n // Check if threshold has an error\n const isThresholdError =\n metric.result?.thresholdResult?.status === 'error';\n\n const statusConfig = getStatusConfig({\n evaluation: metric.result?.thresholdResult?.evaluation,\n thresholdStatus: metric.result?.thresholdResult?.status,\n metricStatus: metric.status,\n });\n\n // Use metric ID to construct translation keys, fallback to original title/description\n const titleKey = `metric.${metric.id}.title`;\n const descriptionKey = `metric.${metric.id}.description`;\n\n const title = t(titleKey as any, {});\n const description = t(descriptionKey as any, {});\n\n // If translation returns the key itself, fallback to original title/description\n const finalTitle = title === titleKey ? metric.metadata.title : title;\n const finalDescription =\n description === descriptionKey\n ? metric.metadata.description\n : description;\n\n return (\n <Scorecard\n key={metric.id}\n cardTitle={finalTitle}\n description={finalDescription}\n statusColor={statusConfig.color}\n StatusIcon={statusConfig.icon ?? (() => null)}\n value={metric.result?.value}\n thresholds={metric.result?.thresholdResult}\n isMetricDataError={isMetricDataError}\n metricDataError={metric?.error}\n isThresholdError={isThresholdError}\n thresholdError={metric.result?.thresholdResult?.error}\n />\n );\n })}\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"EntityScorecardContent.esm.js","sources":["../../../src/components/Scorecard/EntityScorecardContent.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { MetricResult } from '@red-hat-developer-hub/backstage-plugin-scorecard-common';\nimport { ResponseErrorPanel } from '@backstage/core-components';\n\nimport Box from '@mui/material/Box';\nimport CircularProgress from '@mui/material/CircularProgress';\n\nimport NoScorecardsState from '../Common/NoScorecardsState';\nimport Scorecard from './Scorecard';\nimport { useScorecards } from '../../hooks/useScorecards';\nimport { getStatusConfig } from '../../utils';\nimport PermissionRequiredState from '../Common/PermissionRequiredState';\nimport { useTranslation } from '../../hooks/useTranslation';\n\nexport const EntityScorecardContent = () => {\n const { scorecards, loadingData, error } = useScorecards();\n const { t } = useTranslation();\n\n if (loadingData) {\n return (\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n minHeight=\"200px\"\n >\n <CircularProgress />\n </Box>\n );\n }\n\n if (error) {\n if (error.message?.includes('NotAllowedError')) {\n return <PermissionRequiredState />;\n }\n return <ResponseErrorPanel error={error} />;\n }\n\n if (!loadingData && scorecards?.length === 0) {\n return <NoScorecardsState />;\n }\n\n return (\n <Box\n display=\"flex\"\n flexWrap=\"wrap\"\n gap={2}\n sx={{ alignItems: 'flex-start' }}\n >\n {scorecards?.map((metric: MetricResult) => {\n // Check if metric data unavailable\n const isMetricDataError =\n metric.status === 'error' || metric.result?.value === null;\n\n // Check if threshold has an error\n const isThresholdError =\n metric.result?.thresholdResult?.status === 'error';\n\n const statusConfig = getStatusConfig({\n evaluation: metric.result?.thresholdResult?.evaluation,\n thresholdStatus: metric.result?.thresholdResult?.status,\n metricStatus: metric.status,\n thresholdRules: metric.result.thresholdResult.definition?.rules,\n });\n\n // Use metric ID to construct translation keys, fallback to original title/description\n const titleKey = `metric.${metric.id}.title`;\n const descriptionKey = `metric.${metric.id}.description`;\n\n const title = t(titleKey as any, {});\n const description = t(descriptionKey as any, {});\n\n // If translation returns the key itself, fallback to original title/description\n const finalTitle = title === titleKey ? metric.metadata.title : title;\n const finalDescription =\n description === descriptionKey\n ? metric.metadata.description\n : description;\n\n return (\n <Scorecard\n key={metric.id}\n cardTitle={finalTitle}\n description={finalDescription}\n statusColor={statusConfig.color}\n StatusIcon={statusConfig.icon ?? (() => null)}\n value={metric.result?.value}\n thresholds={metric.result?.thresholdResult}\n isMetricDataError={isMetricDataError}\n metricDataError={metric?.error}\n isThresholdError={isThresholdError}\n thresholdError={metric.result?.thresholdResult?.error}\n />\n );\n })}\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,13 +1,97 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useState, useRef, useLayoutEffect } from 'react';
2
3
  import { ResponsiveContainer, PieChart, Pie, Cell, Legend, Tooltip } from 'recharts';
3
4
  import Box from '@mui/material/Box';
4
5
  import { useTheme } from '@mui/material/styles';
5
- import MuiTooltip from '@mui/material/Tooltip';
6
6
  import { useTranslation } from '../../hooks/useTranslation.esm.js';
7
7
  import { CardWrapper } from '../Common/CardWrapper.esm.js';
8
8
  import CustomLegend from './CustomLegend.esm.js';
9
- import { getRingColor } from '../../utils/utils.esm.js';
9
+ import { getHeightForCenterLabel, getYOffsetForCenterLabel } from '../../utils/chartLabelUtils.esm.js';
10
+ import { resolveStatusColor } from '../../utils/colorUtils.esm.js';
11
+ import '@mui/icons-material/WarningAmber';
12
+ import '@mui/icons-material/CheckCircleOutline';
13
+ import '@mui/icons-material/DangerousOutlined';
14
+ import { ErrorTooltip } from '../Common/ErrorTooltip.esm.js';
10
15
 
16
+ const ScorecardCenterLabel = ({
17
+ cx,
18
+ cy,
19
+ StatusIcon,
20
+ value,
21
+ isErrorState,
22
+ errorLabel,
23
+ color,
24
+ onLabelMouseEnter,
25
+ onLabelMouseLeave
26
+ }) => {
27
+ const fontSize = 14;
28
+ const lineHeight = 1.2;
29
+ const textRef = useRef(null);
30
+ const [layout, setLayout] = useState({ yOffset: -10, height: 40 });
31
+ useLayoutEffect(() => {
32
+ if (!isErrorState) return;
33
+ const el = textRef.current;
34
+ if (!el) return;
35
+ const lineHeightPx = fontSize * lineHeight;
36
+ const lineCount = Math.round(el.scrollHeight / lineHeightPx);
37
+ const nextOffset = getYOffsetForCenterLabel(lineCount);
38
+ const nextHeight = getHeightForCenterLabel(lineCount);
39
+ setLayout(
40
+ (prev) => prev.yOffset === nextOffset && prev.height === nextHeight ? prev : { yOffset: nextOffset, height: nextHeight }
41
+ );
42
+ }, [isErrorState, errorLabel]);
43
+ return /* @__PURE__ */ jsxs("g", { transform: `translate(${cx}, ${cy})`, children: [
44
+ /* @__PURE__ */ jsx("foreignObject", { x: -12, y: -28, width: 24, height: 24, children: /* @__PURE__ */ jsx(
45
+ StatusIcon,
46
+ {
47
+ sx: {
48
+ fontSize: 24,
49
+ color
50
+ }
51
+ }
52
+ ) }),
53
+ !isErrorState && /* @__PURE__ */ jsx(
54
+ "text",
55
+ {
56
+ y: 12,
57
+ textAnchor: "middle",
58
+ dominantBaseline: "middle",
59
+ fontSize: 24,
60
+ fontWeight: 500,
61
+ fill: color,
62
+ children: value
63
+ }
64
+ ),
65
+ isErrorState && /* @__PURE__ */ jsx(
66
+ "foreignObject",
67
+ {
68
+ x: -50,
69
+ y: layout.yOffset,
70
+ width: 100,
71
+ height: layout.height,
72
+ children: /* @__PURE__ */ jsx(
73
+ "div",
74
+ {
75
+ ref: textRef,
76
+ style: {
77
+ maxWidth: 100,
78
+ fontSize,
79
+ fontWeight: 400,
80
+ color,
81
+ textAlign: "center",
82
+ lineHeight,
83
+ wordBreak: "break-word",
84
+ cursor: "pointer"
85
+ },
86
+ onMouseEnter: onLabelMouseEnter,
87
+ onMouseLeave: onLabelMouseLeave,
88
+ children: errorLabel
89
+ }
90
+ )
91
+ }
92
+ )
93
+ ] });
94
+ };
11
95
  const Scorecard = ({
12
96
  cardTitle,
13
97
  description,
@@ -22,9 +106,12 @@ const Scorecard = ({
22
106
  }) => {
23
107
  const theme = useTheme();
24
108
  const { t } = useTranslation();
109
+ const [isPieAreaActive, setIsPieAreaActive] = useState(false);
25
110
  const isErrorState = isMetricDataError || isThresholdError;
26
- const ringColor = getRingColor(theme, statusColor, isErrorState);
27
- const pieData = [{ name: "full", value: 100, color: ringColor }];
111
+ const resolvedStatusColor = resolveStatusColor(theme, statusColor);
112
+ const pieData = [
113
+ { name: "full", value: 100, color: resolvedStatusColor }
114
+ ];
28
115
  return /* @__PURE__ */ jsx(
29
116
  CardWrapper,
30
117
  {
@@ -57,6 +144,24 @@ const Scorecard = ({
57
144
  outline: "none"
58
145
  },
59
146
  children: /* @__PURE__ */ jsxs(PieChart, { margin: { top: 0, right: 0, bottom: 0, left: 0 }, children: [
147
+ isErrorState && /* @__PURE__ */ jsx("g", { children: /* @__PURE__ */ jsx(
148
+ "circle",
149
+ {
150
+ cx: "22%",
151
+ cy: "50%",
152
+ r: 74,
153
+ fill: "transparent",
154
+ style: { cursor: "pointer" },
155
+ onMouseEnter: (e) => {
156
+ setIsPieAreaActive(true);
157
+ e.stopPropagation();
158
+ },
159
+ onMouseLeave: (e) => {
160
+ setIsPieAreaActive(false);
161
+ e.stopPropagation();
162
+ }
163
+ }
164
+ ) }),
60
165
  /* @__PURE__ */ jsx(
61
166
  Pie,
62
167
  {
@@ -78,57 +183,38 @@ const Scorecard = ({
78
183
  labelLine: false,
79
184
  label: ({ cx, cy }) => {
80
185
  if (cx === null || cy === null) return null;
81
- const palettePath = statusColor.split(".");
82
- let color;
83
- const paletteRoot = theme.palette[palettePath[0]];
84
- if (palettePath.length === 1) {
85
- color = paletteRoot;
86
- } else if (palettePath.length === 2) {
87
- color = paletteRoot?.[palettePath[1]];
88
- } else if (palettePath.length === 3) {
89
- color = paletteRoot?.[palettePath[1]]?.[palettePath[2]];
186
+ let errorLabel = "";
187
+ if (isMetricDataError) {
188
+ errorLabel = t("errors.metricDataUnavailable");
189
+ } else if (isThresholdError) {
190
+ errorLabel = t("errors.invalidThresholds");
90
191
  }
91
- return /* @__PURE__ */ jsxs("g", { transform: `translate(${cx}, ${cy})`, children: [
92
- /* @__PURE__ */ jsx("foreignObject", { x: -12, y: -28, width: 24, height: 24, children: /* @__PURE__ */ jsx(
192
+ return /* @__PURE__ */ jsx(
193
+ ScorecardCenterLabel,
194
+ {
195
+ cx: Number(cx),
196
+ cy: Number(cy),
93
197
  StatusIcon,
94
- {
95
- sx: {
96
- fontSize: 24,
97
- color: (muiTheme) => muiTheme.palette[statusColor.split(".")[0]][statusColor.split(".")[1]]
98
- }
99
- }
100
- ) }),
101
- !isErrorState && /* @__PURE__ */ jsx(
102
- "text",
103
- {
104
- y: 12,
105
- textAnchor: "middle",
106
- dominantBaseline: "middle",
107
- fontSize: 24,
108
- fontWeight: 500,
109
- fill: color,
110
- children: value
111
- }
112
- ),
113
- isErrorState && /* @__PURE__ */ jsx("foreignObject", { x: -50, y: -17, width: 100, height: 40, children: /* @__PURE__ */ jsxs(
114
- "div",
115
- {
116
- style: {
117
- maxWidth: 100,
118
- fontSize: 14,
119
- fontWeight: 400,
120
- color,
121
- textAlign: "center",
122
- lineHeight: 1.2,
123
- wordBreak: "break-word"
124
- },
125
- children: [
126
- isMetricDataError && t("errors.metricDataUnavailable"),
127
- !isMetricDataError && isThresholdError && t("errors.invalidThresholds")
128
- ]
198
+ value,
199
+ isErrorState,
200
+ errorLabel,
201
+ color: resolvedStatusColor,
202
+ onLabelMouseEnter: (e) => {
203
+ setIsPieAreaActive(true);
204
+ e.stopPropagation();
205
+ },
206
+ onLabelMouseLeave: (e) => {
207
+ setIsPieAreaActive(false);
208
+ e.stopPropagation();
129
209
  }
130
- ) })
131
- ] });
210
+ }
211
+ );
212
+ },
213
+ onMouseEnter: () => {
214
+ setIsPieAreaActive(true);
215
+ },
216
+ onMouseLeave: () => {
217
+ setIsPieAreaActive(false);
132
218
  },
133
219
  children: pieData.map((entry) => /* @__PURE__ */ jsx(Cell, { fill: entry.color }, entry.name))
134
220
  }
@@ -153,28 +239,25 @@ const Scorecard = ({
153
239
  /* @__PURE__ */ jsx(
154
240
  Tooltip,
155
241
  {
156
- position: { x: 27, y: 136 },
157
242
  isAnimationActive: false,
158
- content: ({ active }) => {
159
- if (!active) return null;
243
+ content: ({ coordinate }) => {
244
+ let errorTooltipTitle;
245
+ if (isMetricDataError) {
246
+ errorTooltipTitle = metricDataError;
247
+ } else if (isThresholdError) {
248
+ errorTooltipTitle = thresholdError;
249
+ } else {
250
+ errorTooltipTitle = void 0;
251
+ }
252
+ if (!isPieAreaActive || coordinate === void 0) return null;
160
253
  return /* @__PURE__ */ jsx(
161
- MuiTooltip,
254
+ ErrorTooltip,
162
255
  {
163
- open: true,
164
- title: (
165
- // eslint-disable-next-line no-nested-ternary
166
- isMetricDataError ? metricDataError : isThresholdError ? thresholdError : void 0
167
- ),
168
- placement: "bottom",
169
- arrow: true,
170
- slotProps: {
171
- tooltip: {
172
- sx: {
173
- cursor: isErrorState ? "pointer" : "default"
174
- }
175
- }
176
- },
177
- children: /* @__PURE__ */ jsx("div", { style: { visibility: "hidden" }, children: "Tooltip content" })
256
+ title: errorTooltipTitle,
257
+ tooltipPosition: {
258
+ x: coordinate.x - 25,
259
+ y: coordinate?.y - 16
260
+ }
178
261
  }
179
262
  );
180
263
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Scorecard.esm.js","sources":["../../../src/components/Scorecard/Scorecard.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n MetricValue,\n ThresholdResult,\n} from '@red-hat-developer-hub/backstage-plugin-scorecard-common';\n\nimport {\n PieChart,\n Pie,\n ResponsiveContainer,\n Cell,\n Legend,\n Tooltip,\n} from 'recharts';\n\nimport Box from '@mui/material/Box';\nimport { useTheme } from '@mui/material/styles';\nimport MuiTooltip from '@mui/material/Tooltip';\nimport { useTranslation } from '../../hooks/useTranslation';\nimport { CardWrapper } from '../Common/CardWrapper';\nimport CustomLegend from './CustomLegend';\nimport { getRingColor } from '../../utils/utils';\n\ninterface ScorecardProps {\n cardTitle: string;\n description: string;\n statusColor: string;\n StatusIcon: React.ElementType;\n value: MetricValue | null;\n thresholds?: ThresholdResult;\n isMetricDataError?: boolean;\n metricDataError?: string;\n isThresholdError?: boolean;\n thresholdError?: string;\n}\n\nconst Scorecard = ({\n cardTitle,\n description,\n statusColor,\n StatusIcon,\n value,\n thresholds,\n isMetricDataError = false,\n metricDataError,\n isThresholdError = false,\n thresholdError,\n}: ScorecardProps) => {\n const theme = useTheme();\n const { t } = useTranslation();\n\n const isErrorState = isMetricDataError || isThresholdError;\n\n const ringColor = getRingColor(theme, statusColor, isErrorState);\n\n const pieData = [{ name: 'full', value: 100, color: ringColor }];\n\n return (\n <CardWrapper\n role=\"article\"\n title={cardTitle}\n description={description}\n width=\"371px\"\n >\n <Box\n width=\"100%\"\n height={160}\n data-chart-container\n position=\"relative\"\n sx={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n cursor: 'default',\n '& .recharts-wrapper > svg': {\n outline: 'none',\n },\n }}\n >\n <ResponsiveContainer\n width=\"100%\"\n height={160}\n style={{\n outline: 'none',\n }}\n >\n <PieChart margin={{ top: 0, right: 0, bottom: 0, left: 0 }}>\n <Pie\n data={pieData}\n dataKey=\"value\"\n nameKey=\"name\"\n cx=\"22%\"\n cy=\"50%\"\n innerRadius={64}\n outerRadius={74}\n startAngle={90}\n endAngle={-270}\n stroke=\"none\"\n cursor={isErrorState ? 'pointer' : 'default'}\n isAnimationActive={false}\n style={{\n outline: 'none',\n }}\n labelLine={false}\n label={({ cx, cy }) => {\n if (cx === null || cy === null) return null;\n\n const palettePath = statusColor.split('.');\n let color: string | undefined;\n const paletteRoot =\n theme.palette[palettePath[0] as keyof typeof theme.palette];\n if (palettePath.length === 1) {\n color = paletteRoot as string | undefined;\n } else if (palettePath.length === 2) {\n color = (paletteRoot as Record<string, any>)?.[\n palettePath[1]\n ] as string | undefined;\n } else if (palettePath.length === 3) {\n color = (paletteRoot as Record<string, any>)?.[\n palettePath[1]\n ]?.[palettePath[2]] as string | undefined;\n }\n\n return (\n <g transform={`translate(${cx}, ${cy})`}>\n <foreignObject x={-12} y={-28} width={24} height={24}>\n <StatusIcon\n sx={{\n fontSize: 24,\n color: (muiTheme: any) =>\n muiTheme.palette[statusColor.split('.')[0]][\n statusColor.split('.')[1]\n ],\n }}\n />\n </foreignObject>\n {!isErrorState && (\n <text\n y={12}\n textAnchor=\"middle\"\n dominantBaseline=\"middle\"\n fontSize={24}\n fontWeight={500}\n fill={color}\n >\n {value}\n </text>\n )}\n\n {isErrorState && (\n <foreignObject x={-50} y={-17} width={100} height={40}>\n <div\n style={{\n maxWidth: 100,\n fontSize: 14,\n fontWeight: 400,\n color,\n textAlign: 'center',\n lineHeight: 1.2,\n wordBreak: 'break-word',\n }}\n >\n {isMetricDataError &&\n t('errors.metricDataUnavailable')}\n {!isMetricDataError &&\n isThresholdError &&\n t('errors.invalidThresholds')}\n </div>\n </foreignObject>\n )}\n </g>\n );\n }}\n >\n {pieData.map(entry => (\n <Cell key={entry.name} fill={entry.color} />\n ))}\n </Pie>\n\n <Legend\n layout=\"vertical\"\n align=\"center\"\n verticalAlign=\"middle\"\n wrapperStyle={{\n position: 'absolute',\n left: '160px',\n top: '42px',\n display: 'flex',\n alignItems: 'center',\n height: '76px',\n }}\n content={props => (\n <CustomLegend {...props} thresholds={thresholds} />\n )}\n />\n\n <Tooltip\n position={{ x: 27, y: 136 }}\n isAnimationActive={false}\n content={({ active }) => {\n if (!active) return null;\n\n return (\n <MuiTooltip\n open\n title={\n // eslint-disable-next-line no-nested-ternary\n isMetricDataError\n ? metricDataError\n : isThresholdError\n ? thresholdError\n : undefined\n }\n placement=\"bottom\"\n arrow\n slotProps={{\n tooltip: {\n sx: {\n cursor: isErrorState ? 'pointer' : 'default',\n },\n },\n }}\n >\n {/* Need to hide the tooltip content because we are using the position prop to position the tooltip */}\n <div style={{ visibility: 'hidden' }}>Tooltip content</div>\n </MuiTooltip>\n );\n }}\n />\n </PieChart>\n </ResponsiveContainer>\n </Box>\n </CardWrapper>\n );\n};\n\nexport default Scorecard;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Scorecard.esm.js","sources":["../../../src/components/Scorecard/Scorecard.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { useLayoutEffect, useRef, useState } from 'react';\n\nimport {\n MetricValue,\n ThresholdResult,\n} from '@red-hat-developer-hub/backstage-plugin-scorecard-common';\n\nimport {\n PieChart,\n Pie,\n ResponsiveContainer,\n Cell,\n Legend,\n Tooltip,\n} from 'recharts';\nimport Box from '@mui/material/Box';\nimport { useTheme } from '@mui/material/styles';\n\nimport { useTranslation } from '../../hooks/useTranslation';\nimport { CardWrapper } from '../Common/CardWrapper';\nimport CustomLegend from './CustomLegend';\nimport {\n getHeightForCenterLabel,\n getYOffsetForCenterLabel,\n resolveStatusColor,\n} from '../../utils';\nimport { ErrorTooltip } from '../Common/ErrorTooltip';\nimport type { PieData } from '../types';\n\ninterface ScorecardProps {\n cardTitle: string;\n description: string;\n statusColor: string;\n StatusIcon: React.ElementType;\n value: MetricValue | null;\n thresholds?: ThresholdResult;\n isMetricDataError?: boolean;\n metricDataError?: string;\n isThresholdError?: boolean;\n thresholdError?: string;\n}\n\nconst ScorecardCenterLabel = ({\n cx,\n cy,\n StatusIcon,\n value,\n isErrorState,\n errorLabel,\n color,\n onLabelMouseEnter,\n onLabelMouseLeave,\n}: {\n cx: number;\n cy: number;\n StatusIcon: React.ElementType;\n value: MetricValue | null;\n isErrorState: boolean;\n errorLabel: string;\n color: string | undefined;\n onLabelMouseEnter: (e: React.MouseEvent) => void;\n onLabelMouseLeave: (e: React.MouseEvent) => void;\n}) => {\n const fontSize = 14;\n const lineHeight = 1.2;\n\n const textRef = useRef<HTMLDivElement>(null);\n const [layout, setLayout] = useState({ yOffset: -10, height: 40 });\n\n useLayoutEffect(() => {\n if (!isErrorState) return;\n const el = textRef.current;\n if (!el) return;\n\n const lineHeightPx = fontSize * lineHeight;\n const lineCount = Math.round(el.scrollHeight / lineHeightPx);\n\n const nextOffset = getYOffsetForCenterLabel(lineCount);\n const nextHeight = getHeightForCenterLabel(lineCount);\n\n setLayout(prev =>\n prev.yOffset === nextOffset && prev.height === nextHeight\n ? prev\n : { yOffset: nextOffset, height: nextHeight },\n );\n }, [isErrorState, errorLabel]);\n\n return (\n <g transform={`translate(${cx}, ${cy})`}>\n <foreignObject x={-12} y={-28} width={24} height={24}>\n <StatusIcon\n sx={{\n fontSize: 24,\n color,\n }}\n />\n </foreignObject>\n {!isErrorState && (\n <text\n y={12}\n textAnchor=\"middle\"\n dominantBaseline=\"middle\"\n fontSize={24}\n fontWeight={500}\n fill={color}\n >\n {value}\n </text>\n )}\n {isErrorState && (\n <foreignObject\n x={-50}\n y={layout.yOffset}\n width={100}\n height={layout.height}\n >\n <div\n ref={textRef}\n style={{\n maxWidth: 100,\n fontSize,\n fontWeight: 400,\n color,\n textAlign: 'center',\n lineHeight,\n wordBreak: 'break-word',\n cursor: 'pointer',\n }}\n onMouseEnter={onLabelMouseEnter}\n onMouseLeave={onLabelMouseLeave}\n >\n {errorLabel}\n </div>\n </foreignObject>\n )}\n </g>\n );\n};\n\nconst Scorecard = ({\n cardTitle,\n description,\n statusColor,\n StatusIcon,\n value,\n thresholds,\n isMetricDataError = false,\n metricDataError,\n isThresholdError = false,\n thresholdError,\n}: ScorecardProps) => {\n const theme = useTheme();\n const { t } = useTranslation();\n\n const [isPieAreaActive, setIsPieAreaActive] = useState(false);\n\n const isErrorState = isMetricDataError || isThresholdError;\n\n const resolvedStatusColor = resolveStatusColor(theme, statusColor);\n\n const pieData: PieData[] = [\n { name: 'full', value: 100, color: resolvedStatusColor },\n ];\n\n return (\n <CardWrapper\n role=\"article\"\n title={cardTitle}\n description={description}\n width=\"371px\"\n >\n <Box\n width=\"100%\"\n height={160}\n data-chart-container\n position=\"relative\"\n sx={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n cursor: 'default',\n '& .recharts-wrapper > svg': {\n outline: 'none',\n },\n }}\n >\n <ResponsiveContainer\n width=\"100%\"\n height={160}\n style={{\n outline: 'none',\n }}\n >\n <PieChart margin={{ top: 0, right: 0, bottom: 0, left: 0 }}>\n {/* This is the circle that is used to trigger the tooltip */}\n {isErrorState && (\n <g>\n <circle\n cx=\"22%\"\n cy=\"50%\"\n r={74}\n fill=\"transparent\"\n style={{ cursor: 'pointer' }}\n onMouseEnter={e => {\n setIsPieAreaActive(true);\n e.stopPropagation();\n }}\n onMouseLeave={e => {\n setIsPieAreaActive(false);\n e.stopPropagation();\n }}\n />\n </g>\n )}\n\n <Pie\n data={pieData}\n dataKey=\"value\"\n nameKey=\"name\"\n cx=\"22%\"\n cy=\"50%\"\n innerRadius={64}\n outerRadius={74}\n startAngle={90}\n endAngle={-270}\n stroke=\"none\"\n cursor={isErrorState ? 'pointer' : 'default'}\n isAnimationActive={false}\n style={{\n outline: 'none',\n }}\n labelLine={false}\n label={({ cx, cy }) => {\n if (cx === null || cy === null) return null;\n\n let errorLabel = '';\n if (isMetricDataError) {\n errorLabel = t('errors.metricDataUnavailable');\n } else if (isThresholdError) {\n errorLabel = t('errors.invalidThresholds');\n }\n\n return (\n <ScorecardCenterLabel\n cx={Number(cx)}\n cy={Number(cy)}\n StatusIcon={StatusIcon}\n value={value}\n isErrorState={isErrorState}\n errorLabel={errorLabel}\n color={resolvedStatusColor}\n onLabelMouseEnter={e => {\n setIsPieAreaActive(true);\n e.stopPropagation();\n }}\n onLabelMouseLeave={e => {\n setIsPieAreaActive(false);\n e.stopPropagation();\n }}\n />\n );\n }}\n onMouseEnter={() => {\n setIsPieAreaActive(true);\n }}\n onMouseLeave={() => {\n setIsPieAreaActive(false);\n }}\n >\n {pieData.map(entry => (\n <Cell key={entry.name} fill={entry.color} />\n ))}\n </Pie>\n\n <Legend\n layout=\"vertical\"\n align=\"center\"\n verticalAlign=\"middle\"\n wrapperStyle={{\n position: 'absolute',\n left: '160px',\n top: '42px',\n display: 'flex',\n alignItems: 'center',\n height: '76px',\n }}\n content={props => (\n <CustomLegend {...props} thresholds={thresholds} />\n )}\n />\n\n <Tooltip\n isAnimationActive={false}\n content={({ coordinate }) => {\n let errorTooltipTitle: string | undefined;\n if (isMetricDataError) {\n errorTooltipTitle = metricDataError;\n } else if (isThresholdError) {\n errorTooltipTitle = thresholdError;\n } else {\n errorTooltipTitle = undefined;\n }\n\n if (!isPieAreaActive || coordinate === undefined) return null;\n return (\n <ErrorTooltip\n title={errorTooltipTitle}\n tooltipPosition={{\n x: coordinate.x - 25,\n y: coordinate?.y - 16,\n }}\n />\n );\n }}\n />\n </PieChart>\n </ResponsiveContainer>\n </Box>\n </CardWrapper>\n );\n};\n\nexport default Scorecard;\n"],"names":[],"mappings":"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"}
@@ -71,7 +71,13 @@ const CustomLegend = (props) => {
71
71
  }
72
72
  },
73
73
  children: [
74
- /* @__PURE__ */ jsx(StyledLegendColorBox, { color: category?.color }),
74
+ /* @__PURE__ */ jsx(
75
+ StyledLegendColorBox,
76
+ {
77
+ "data-testid": `legend-colorbox-${category.name}`,
78
+ color: category?.color
79
+ }
80
+ ),
75
81
  /* @__PURE__ */ jsx(
76
82
  Typography,
77
83
  {
@@ -1 +1 @@
1
- {"version":3,"file":"CustomLegend.esm.js","sources":["../../../src/components/ScorecardHomepageSection/CustomLegend.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport { styled } from '@mui/material/styles';\n\nimport type { PieData as PieDataProps } from '../../utils/utils';\nimport { useTranslation } from '../../hooks/useTranslation';\n\nconst StyledLegend = styled(Box)(({ theme }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1),\n paddingLeft: theme.spacing(3.2),\n}));\n\nconst StyledLegendItem = styled(Box)(({ theme }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n cursor: 'pointer',\n}));\n\nconst StyledLegendColorBox = styled(Box)<{ color?: string }>(\n ({ color = 'success.main' }) => ({\n width: '10px',\n height: '10px',\n backgroundColor: color,\n flexShrink: 0,\n }),\n);\n\ntype CustomLegendProps = {\n pieData: PieDataProps[];\n activeIndex: number | null;\n setActiveIndex: (index: number | null) => void;\n setTooltipPosition: (position: { x: number; y: number } | null) => void;\n};\n\nconst CustomLegend = (props: CustomLegendProps) => {\n const { pieData, activeIndex, setActiveIndex, setTooltipPosition } = props;\n const { t } = useTranslation();\n if (!pieData || pieData.length === 0) return null;\n\n return (\n <StyledLegend\n onMouseLeave={() => {\n setActiveIndex(null);\n setTooltipPosition(null);\n }}\n >\n {pieData.map((category: PieDataProps, index: number) => {\n return (\n <StyledLegendItem\n key={`legend-${category.name}`}\n onMouseEnter={e => {\n if (activeIndex === index) return;\n setActiveIndex(index);\n const rect = e.currentTarget.getBoundingClientRect();\n const containerRect = e.currentTarget\n .closest('[data-chart-container]')\n ?.getBoundingClientRect();\n if (containerRect) {\n setTooltipPosition({\n x: rect.left - containerRect.left + rect.width / 2,\n y: rect.top - containerRect.top,\n });\n }\n }}\n onMouseMove={e => {\n if (activeIndex === index) return;\n const rect = e.currentTarget.getBoundingClientRect();\n const containerRect = e.currentTarget\n .closest('[data-chart-container]')\n ?.getBoundingClientRect();\n if (containerRect) {\n setTooltipPosition({\n x: rect.left - containerRect.left + rect.width / 2,\n y: rect.top - containerRect.top,\n });\n }\n }}\n onMouseLeave={e => {\n const relatedTarget = e.relatedTarget as Node | null;\n const currentTarget = e.currentTarget;\n\n if (\n !relatedTarget ||\n !(relatedTarget instanceof Node) ||\n !currentTarget.contains(relatedTarget)\n ) {\n setActiveIndex(null);\n setTooltipPosition(null);\n }\n }}\n >\n <StyledLegendColorBox color={category?.color} />\n <Typography\n variant=\"body2\"\n sx={{ fontSize: '0.875rem', fontWeight: 400 }}\n >\n {(() => {\n const translated = t(`thresholds.${category.name}` as any, {});\n return translated === `thresholds.${category.name}`\n ? category.name.charAt(0).toUpperCase() +\n category.name.slice(1)\n : translated;\n })()}\n </Typography>\n </StyledLegendItem>\n );\n })}\n </StyledLegend>\n );\n};\n\nexport default CustomLegend;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CustomLegend.esm.js","sources":["../../../src/components/ScorecardHomepageSection/CustomLegend.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport { styled } from '@mui/material/styles';\n\nimport type { PieData as PieDataProps } from '../types';\nimport { useTranslation } from '../../hooks/useTranslation';\n\nconst StyledLegend = styled(Box)(({ theme }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1),\n paddingLeft: theme.spacing(3.2),\n}));\n\nconst StyledLegendItem = styled(Box)(({ theme }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n cursor: 'pointer',\n}));\n\nconst StyledLegendColorBox = styled(Box)<{ color?: string }>(\n ({ color = 'success.main' }) => ({\n width: '10px',\n height: '10px',\n backgroundColor: color,\n flexShrink: 0,\n }),\n);\n\ntype CustomLegendProps = {\n pieData: PieDataProps[];\n activeIndex: number | null;\n setActiveIndex: (index: number | null) => void;\n setTooltipPosition: (position: { x: number; y: number } | null) => void;\n};\n\nconst CustomLegend = (props: CustomLegendProps) => {\n const { pieData, activeIndex, setActiveIndex, setTooltipPosition } = props;\n const { t } = useTranslation();\n if (!pieData || pieData.length === 0) return null;\n\n return (\n <StyledLegend\n onMouseLeave={() => {\n setActiveIndex(null);\n setTooltipPosition(null);\n }}\n >\n {pieData.map((category: PieDataProps, index: number) => {\n return (\n <StyledLegendItem\n key={`legend-${category.name}`}\n onMouseEnter={e => {\n if (activeIndex === index) return;\n setActiveIndex(index);\n const rect = e.currentTarget.getBoundingClientRect();\n const containerRect = e.currentTarget\n .closest('[data-chart-container]')\n ?.getBoundingClientRect();\n if (containerRect) {\n setTooltipPosition({\n x: rect.left - containerRect.left + rect.width / 2,\n y: rect.top - containerRect.top,\n });\n }\n }}\n onMouseMove={e => {\n if (activeIndex === index) return;\n const rect = e.currentTarget.getBoundingClientRect();\n const containerRect = e.currentTarget\n .closest('[data-chart-container]')\n ?.getBoundingClientRect();\n if (containerRect) {\n setTooltipPosition({\n x: rect.left - containerRect.left + rect.width / 2,\n y: rect.top - containerRect.top,\n });\n }\n }}\n onMouseLeave={e => {\n const relatedTarget = e.relatedTarget as Node | null;\n const currentTarget = e.currentTarget;\n\n if (\n !relatedTarget ||\n !(relatedTarget instanceof Node) ||\n !currentTarget.contains(relatedTarget)\n ) {\n setActiveIndex(null);\n setTooltipPosition(null);\n }\n }}\n >\n <StyledLegendColorBox\n data-testid={`legend-colorbox-${category.name}`}\n color={category?.color}\n />\n <Typography\n variant=\"body2\"\n sx={{ fontSize: '0.875rem', fontWeight: 400 }}\n >\n {(() => {\n const translated = t(`thresholds.${category.name}` as any, {});\n return translated === `thresholds.${category.name}`\n ? category.name.charAt(0).toUpperCase() +\n category.name.slice(1)\n : translated;\n })()}\n </Typography>\n </StyledLegendItem>\n );\n })}\n </StyledLegend>\n );\n};\n\nexport default CustomLegend;\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CustomTooltip.esm.js","sources":["../../../src/components/ScorecardHomepageSection/CustomTooltip.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 type { TooltipProps } from 'recharts';\n\nimport Paper from '@mui/material/Paper';\nimport Typography from '@mui/material/Typography';\n\nimport type { PieData } from '../../utils/utils';\nimport { useTranslation } from '../../hooks/useTranslation';\n\ntype CustomTooltipPayload = {\n name?: string;\n value?: number;\n payload?: PieData;\n};\n\ntype CustomTooltipProps = TooltipProps<number, string> & {\n payload?: readonly CustomTooltipPayload[];\n pieData: PieData[];\n customContent?: string;\n};\n\nexport const CustomTooltip = ({\n payload,\n pieData,\n customContent,\n}: CustomTooltipProps) => {\n const { t } = useTranslation();\n\n const getPercentage = () => {\n if (!Array.isArray(pieData) || pieData.length === 0) return 0;\n if (!payload || payload.length === 0) return 0;\n\n const total = pieData.reduce(\n (acc: number, curr: PieData) => acc + (curr.value || 0),\n 0,\n );\n const threshold = pieData.find(\n (item: PieData) => item.name === payload?.[0]?.name,\n );\n\n const thresholdValue = threshold?.value || 0;\n\n return total > 0 ? Math.round((thresholdValue / total) * 100) : 0;\n };\n\n let contentElement = null;\n\n if (customContent) {\n contentElement = (\n <Typography sx={{ fontSize: '0.875rem', margin: 0, fontWeight: '500' }}>\n {customContent}\n </Typography>\n );\n } else if (payload?.[0]?.value === 0 || payload?.[0]?.value === undefined) {\n const translatedState = t(`thresholds.${payload?.[0]?.name}` as any, {});\n contentElement = (\n <Typography sx={{ fontSize: '0.875rem', margin: 0, fontWeight: '500' }}>\n {t('thresholds.noEntities', { category: translatedState } as any)}\n </Typography>\n );\n } else {\n contentElement = (\n <>\n <Typography sx={{ fontSize: '0.875rem', margin: 0, fontWeight: '500' }}>\n {t('thresholds.entities', { count: payload?.[0]?.value })}\n </Typography>\n <Typography\n sx={{\n fontSize: '2.5rem',\n margin: 0,\n color: '#37a3a3',\n fontWeight: 500,\n }}\n >\n {getPercentage()}%\n </Typography>\n </>\n );\n }\n\n return (\n <Paper\n elevation={1}\n sx={{\n width:\n payload?.[0]?.value === 0 || payload?.[0]?.value === undefined\n ? '220px'\n : 'auto',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 1px 2px 0 rgba(0, 0, 0, 0.50)',\n border: theme => `1px solid ${theme.palette.grey[300]}`,\n }}\n >\n {contentElement}\n </Paper>\n );\n};\n"],"names":[],"mappings":";;;;;AAoCO,MAAM,gBAAgB,CAAC;AAAA,EAC5B,OAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAA0B,KAAA;AACxB,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,cAAe,EAAA;AAE7B,EAAA,MAAM,gBAAgB,MAAM;AAC1B,IAAI,IAAA,CAAC,MAAM,OAAQ,CAAA,OAAO,KAAK,OAAQ,CAAA,MAAA,KAAW,GAAU,OAAA,CAAA;AAC5D,IAAA,IAAI,CAAC,OAAA,IAAW,OAAQ,CAAA,MAAA,KAAW,GAAU,OAAA,CAAA;AAE7C,IAAA,MAAM,QAAQ,OAAQ,CAAA,MAAA;AAAA,MACpB,CAAC,GAAA,EAAa,IAAkB,KAAA,GAAA,IAAO,KAAK,KAAS,IAAA,CAAA,CAAA;AAAA,MACrD;AAAA,KACF;AACA,IAAA,MAAM,YAAY,OAAQ,CAAA,IAAA;AAAA,MACxB,CAAC,IAAkB,KAAA,IAAA,CAAK,IAAS,KAAA,OAAA,GAAU,CAAC,CAAG,EAAA;AAAA,KACjD;AAEA,IAAM,MAAA,cAAA,GAAiB,WAAW,KAAS,IAAA,CAAA;AAE3C,IAAA,OAAO,QAAQ,CAAI,GAAA,IAAA,CAAK,MAAO,cAAiB,GAAA,KAAA,GAAS,GAAG,CAAI,GAAA,CAAA;AAAA,GAClE;AAEA,EAAA,IAAI,cAAiB,GAAA,IAAA;AAErB,EAAA,IAAI,aAAe,EAAA;AACjB,IACE,cAAA,mBAAA,GAAA,CAAC,UAAW,EAAA,EAAA,EAAA,EAAI,EAAE,QAAA,EAAU,UAAY,EAAA,MAAA,EAAQ,CAAG,EAAA,UAAA,EAAY,KAAM,EAAA,EAClE,QACH,EAAA,aAAA,EAAA,CAAA;AAAA,GAEJ,MAAA,IAAW,OAAU,GAAA,CAAC,CAAG,EAAA,KAAA,KAAU,KAAK,OAAU,GAAA,CAAC,CAAG,EAAA,KAAA,KAAU,MAAW,EAAA;AACzE,IAAM,MAAA,eAAA,GAAkB,EAAE,CAAc,WAAA,EAAA,OAAA,GAAU,CAAC,CAAG,EAAA,IAAI,CAAW,CAAA,EAAA,EAAE,CAAA;AACvE,IAAA,cAAA,uBACG,UAAW,EAAA,EAAA,EAAA,EAAI,EAAE,QAAA,EAAU,YAAY,MAAQ,EAAA,CAAA,EAAG,UAAY,EAAA,KAAA,IAC5D,QAAE,EAAA,CAAA,CAAA,uBAAA,EAAyB,EAAE,QAAU,EAAA,eAAA,EAAwB,CAClE,EAAA,CAAA;AAAA,GAEG,MAAA;AACL,IAAA,cAAA,mBAEI,IAAA,CAAA,QAAA,EAAA,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,cAAW,EAAI,EAAA,EAAE,UAAU,UAAY,EAAA,MAAA,EAAQ,GAAG,UAAY,EAAA,KAAA,IAC5D,QAAE,EAAA,CAAA,CAAA,qBAAA,EAAuB,EAAE,KAAO,EAAA,OAAA,GAAU,CAAC,CAAG,EAAA,KAAA,EAAO,CAC1D,EAAA,CAAA;AAAA,sBACA,IAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,EAAI,EAAA;AAAA,YACF,QAAU,EAAA,QAAA;AAAA,YACV,MAAQ,EAAA,CAAA;AAAA,YACR,KAAO,EAAA,SAAA;AAAA,YACP,UAAY,EAAA;AAAA,WACd;AAAA,UAEC,QAAA,EAAA;AAAA,YAAc,aAAA,EAAA;AAAA,YAAE;AAAA;AAAA;AAAA;AACnB,KACF,EAAA,CAAA;AAAA;AAIJ,EACE,uBAAA,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAW,EAAA,CAAA;AAAA,MACX,EAAI,EAAA;AAAA,QACF,KAAA,EACE,OAAU,GAAA,CAAC,CAAG,EAAA,KAAA,KAAU,CAAK,IAAA,OAAA,GAAU,CAAC,CAAA,EAAG,KAAU,KAAA,MAAA,GACjD,OACA,GAAA,MAAA;AAAA,QACN,OAAS,EAAA,MAAA;AAAA,QACT,YAAc,EAAA,MAAA;AAAA,QACd,SAAW,EAAA,iCAAA;AAAA,QACX,QAAQ,CAAS,KAAA,KAAA,CAAA,UAAA,EAAa,MAAM,OAAQ,CAAA,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,OACvD;AAAA,MAEC,QAAA,EAAA;AAAA;AAAA,GACH;AAEJ;;;;"}
1
+ {"version":3,"file":"CustomTooltip.esm.js","sources":["../../../src/components/ScorecardHomepageSection/CustomTooltip.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 type { TooltipProps } from 'recharts';\n\nimport Paper from '@mui/material/Paper';\nimport Typography from '@mui/material/Typography';\n\nimport type { PieData } from '../types';\nimport { useTranslation } from '../../hooks/useTranslation';\n\ntype CustomTooltipPayload = {\n name?: string;\n value?: number;\n payload?: PieData;\n};\n\ntype CustomTooltipProps = TooltipProps<number, string> & {\n payload?: readonly CustomTooltipPayload[];\n pieData: PieData[];\n customContent?: string;\n};\n\nexport const CustomTooltip = ({\n payload,\n pieData,\n customContent,\n}: CustomTooltipProps) => {\n const { t } = useTranslation();\n\n const getPercentage = () => {\n if (!Array.isArray(pieData) || pieData.length === 0) return 0;\n if (!payload || payload.length === 0) return 0;\n\n const total = pieData.reduce(\n (acc: number, curr: PieData) => acc + (curr.value || 0),\n 0,\n );\n const threshold = pieData.find(\n (item: PieData) => item.name === payload?.[0]?.name,\n );\n\n const thresholdValue = threshold?.value || 0;\n\n return total > 0 ? Math.round((thresholdValue / total) * 100) : 0;\n };\n\n let contentElement = null;\n\n if (customContent) {\n contentElement = (\n <Typography sx={{ fontSize: '0.875rem', margin: 0, fontWeight: '500' }}>\n {customContent}\n </Typography>\n );\n } else if (payload?.[0]?.value === 0 || payload?.[0]?.value === undefined) {\n const translatedState = t(`thresholds.${payload?.[0]?.name}` as any, {});\n contentElement = (\n <Typography sx={{ fontSize: '0.875rem', margin: 0, fontWeight: '500' }}>\n {t('thresholds.noEntities', { category: translatedState } as any)}\n </Typography>\n );\n } else {\n contentElement = (\n <>\n <Typography sx={{ fontSize: '0.875rem', margin: 0, fontWeight: '500' }}>\n {t('thresholds.entities', { count: payload?.[0]?.value })}\n </Typography>\n <Typography\n sx={{\n fontSize: '2.5rem',\n margin: 0,\n color: '#37a3a3',\n fontWeight: 500,\n }}\n >\n {getPercentage()}%\n </Typography>\n </>\n );\n }\n\n return (\n <Paper\n elevation={1}\n sx={{\n width:\n payload?.[0]?.value === 0 || payload?.[0]?.value === undefined\n ? '220px'\n : 'auto',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 1px 2px 0 rgba(0, 0, 0, 0.50)',\n border: theme => `1px solid ${theme.palette.grey[300]}`,\n }}\n >\n {contentElement}\n </Paper>\n );\n};\n"],"names":[],"mappings":"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"}