@red-hat-developer-hub/backstage-plugin-scorecard 2.2.0 → 2.3.1
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 +58 -0
- package/README.md +2 -2
- package/dist/alpha.d.ts +9 -3
- package/dist/api/index.esm.js +30 -0
- package/dist/api/index.esm.js.map +1 -1
- package/dist/components/Common/CardWrapper.esm.js +108 -0
- package/dist/components/Common/CardWrapper.esm.js.map +1 -0
- package/dist/components/Common/PermissionRequiredState.esm.js +1 -1
- package/dist/components/Common/PermissionRequiredState.esm.js.map +1 -1
- package/dist/components/Scorecard/CustomLegend.esm.js +68 -0
- package/dist/components/Scorecard/CustomLegend.esm.js.map +1 -0
- package/dist/components/Scorecard/EntityScorecardContent.esm.js +1 -2
- package/dist/components/Scorecard/EntityScorecardContent.esm.js.map +1 -1
- package/dist/components/Scorecard/Scorecard.esm.js +161 -217
- package/dist/components/Scorecard/Scorecard.esm.js.map +1 -1
- package/dist/components/ScorecardHomepageSection/CustomLegend.esm.js +96 -0
- package/dist/components/ScorecardHomepageSection/CustomLegend.esm.js.map +1 -0
- package/dist/components/ScorecardHomepageSection/CustomTooltip.esm.js +69 -0
- package/dist/components/ScorecardHomepageSection/CustomTooltip.esm.js.map +1 -0
- package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js +110 -0
- package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js.map +1 -0
- package/dist/components/ScorecardHomepageSection/ResponsivePieChart.esm.js +50 -0
- package/dist/components/ScorecardHomepageSection/ResponsivePieChart.esm.js.map +1 -0
- package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js +50 -0
- package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js.map +1 -0
- package/dist/components/ScorecardHomepageSection/ScorecardHomepageCardComponent.esm.js +105 -0
- package/dist/components/ScorecardHomepageSection/ScorecardHomepageCardComponent.esm.js.map +1 -0
- package/dist/components/ScorecardHomepageSection/index.esm.js +2 -0
- package/dist/components/ScorecardHomepageSection/index.esm.js.map +1 -0
- package/dist/hooks/useAggregatedScorecard.esm.js +42 -0
- package/dist/hooks/useAggregatedScorecard.esm.js.map +1 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.esm.js +6 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/plugin.esm.js +13 -3
- package/dist/plugin.esm.js.map +1 -1
- package/dist/translations/de.esm.js +7 -1
- package/dist/translations/de.esm.js.map +1 -1
- package/dist/translations/es.esm.js +7 -1
- package/dist/translations/es.esm.js.map +1 -1
- package/dist/translations/fr.esm.js +22 -21
- package/dist/translations/fr.esm.js.map +1 -1
- package/dist/translations/index.esm.js +3 -1
- package/dist/translations/index.esm.js.map +1 -1
- package/dist/translations/it.esm.js +34 -0
- package/dist/translations/it.esm.js.map +1 -0
- package/dist/translations/ja.esm.js +34 -0
- package/dist/translations/ja.esm.js.map +1 -0
- package/dist/translations/ref.esm.js +8 -2
- package/dist/translations/ref.esm.js.map +1 -1
- package/dist/utils/utils.esm.js +8 -1
- package/dist/utils/utils.esm.js.map +1 -1
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,63 @@
|
|
|
1
1
|
# @red-hat-developer-hub/backstage-plugin-scorecard
|
|
2
2
|
|
|
3
|
+
## 2.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- a2c7cce: Fix MUI styling issue
|
|
8
|
+
- @red-hat-developer-hub/backstage-plugin-scorecard-common@2.3.1
|
|
9
|
+
|
|
10
|
+
## 2.3.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- 52b60ee: Added aggregated metric cards frontend
|
|
15
|
+
- 4e360d5: Implemented endpoint to aggregate metrics for scorecard metrics
|
|
16
|
+
|
|
17
|
+
**BREAKING** Update attribute `value` in the `MetricResult` type and update validation to support `null` instead `undefined` for the updated attribute
|
|
18
|
+
|
|
19
|
+
```diff
|
|
20
|
+
export type MetricResult = {
|
|
21
|
+
id: string;
|
|
22
|
+
status: 'success' | 'error';
|
|
23
|
+
metadata: {
|
|
24
|
+
title: string;
|
|
25
|
+
description: string;
|
|
26
|
+
type: MetricType;
|
|
27
|
+
history?: boolean;
|
|
28
|
+
};
|
|
29
|
+
result: {
|
|
30
|
+
- value?: MetricValue;
|
|
31
|
+
+ value: MetricValue | null;
|
|
32
|
+
timestamp: string;
|
|
33
|
+
thresholdResult: ThresholdResult;
|
|
34
|
+
};
|
|
35
|
+
error?: string;
|
|
36
|
+
};
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**BREAKING** Update attribute `evaluation` in the `ThresholdResult` type and update validation to support `null` instead `undefined` for the updated attribute
|
|
40
|
+
|
|
41
|
+
```diff
|
|
42
|
+
export type ThresholdResult = {
|
|
43
|
+
status: 'success' | 'error';
|
|
44
|
+
- definition: ThresholdConfig | undefined;
|
|
45
|
+
+ definition: ThresholdConfig | null;
|
|
46
|
+
evaluation: string | undefined; // threshold key the expression evaluated to
|
|
47
|
+
error?: string;
|
|
48
|
+
};
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Patch Changes
|
|
52
|
+
|
|
53
|
+
- 9dee966: Integrated UI with backend aggregated api
|
|
54
|
+
- f74564d: Added 'it' and 'ja' i18n translation support and updated 'fr' translations.
|
|
55
|
+
- 6318931: Updated dependency `@red-hat-developer-hub/backstage-plugin-theme` to `^0.12.0`.
|
|
56
|
+
- 61d0c34: Updated dependency `@red-hat-developer-hub/backstage-plugin-theme` to `^0.11.0`.
|
|
57
|
+
- Updated dependencies [52b60ee]
|
|
58
|
+
- Updated dependencies [4e360d5]
|
|
59
|
+
- @red-hat-developer-hub/backstage-plugin-scorecard-common@2.3.0
|
|
60
|
+
|
|
3
61
|
## 2.2.0
|
|
4
62
|
|
|
5
63
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -53,11 +53,11 @@ permission:
|
|
|
53
53
|
1. Add the Scorecard page to you Entity overview page by modifying `packages/app/src/components/catalog/EntityPage.tsx`:
|
|
54
54
|
|
|
55
55
|
```tsx
|
|
56
|
-
import {
|
|
56
|
+
import { EntityScorecardContent } from '@red-hat-developer-hub/backstage-plugin-scorecard';
|
|
57
57
|
|
|
58
58
|
const scorecardRoute = (
|
|
59
59
|
<EntityLayout.Route path="/scorecard" title="Scorecard">
|
|
60
|
-
<
|
|
60
|
+
<EntityScorecardContent />
|
|
61
61
|
</EntityLayout.Route>
|
|
62
62
|
);
|
|
63
63
|
|
package/dist/alpha.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Translation reference for scorecard plugin
|
|
5
5
|
* @public
|
|
6
6
|
*/
|
|
7
|
-
declare const scorecardTranslationRef:
|
|
7
|
+
declare const scorecardTranslationRef: _backstage_frontend_plugin_api.TranslationRef<"plugin.scorecard", {
|
|
8
8
|
readonly "emptyState.button": string;
|
|
9
9
|
readonly "emptyState.title": string;
|
|
10
10
|
readonly "emptyState.description": string;
|
|
@@ -18,6 +18,9 @@ declare const scorecardTranslationRef: _backstage_core_plugin_api_alpha.Translat
|
|
|
18
18
|
readonly "errors.fetchError": string;
|
|
19
19
|
readonly "errors.metricDataUnavailable": string;
|
|
20
20
|
readonly "errors.invalidThresholds": string;
|
|
21
|
+
readonly "errors.missingPermission": string;
|
|
22
|
+
readonly "errors.missingPermissionMessage": string;
|
|
23
|
+
readonly "errors.userNotFoundInCatalogMessage": string;
|
|
21
24
|
readonly "metric.github.open_prs.title": string;
|
|
22
25
|
readonly "metric.github.open_prs.description": string;
|
|
23
26
|
readonly "metric.jira.open_issues.title": string;
|
|
@@ -25,12 +28,15 @@ declare const scorecardTranslationRef: _backstage_core_plugin_api_alpha.Translat
|
|
|
25
28
|
readonly "thresholds.success": string;
|
|
26
29
|
readonly "thresholds.error": string;
|
|
27
30
|
readonly "thresholds.warning": string;
|
|
31
|
+
readonly "thresholds.noEntities": string;
|
|
32
|
+
readonly "thresholds.entities_one": string;
|
|
33
|
+
readonly "thresholds.entities_other": string;
|
|
28
34
|
}>;
|
|
29
35
|
|
|
30
36
|
/**
|
|
31
37
|
* Translation Resource for scorecard
|
|
32
38
|
* @public
|
|
33
39
|
*/
|
|
34
|
-
declare const scorecardTranslations:
|
|
40
|
+
declare const scorecardTranslations: _backstage_frontend_plugin_api.TranslationResource<"plugin.scorecard">;
|
|
35
41
|
|
|
36
42
|
export { scorecardTranslationRef, scorecardTranslations };
|
package/dist/api/index.esm.js
CHANGED
|
@@ -57,6 +57,36 @@ class ScorecardApiClient {
|
|
|
57
57
|
throw new Error(`Unexpected error fetching scorecards: ${String(error)}`);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
+
async getAggregatedScorecard(metricId) {
|
|
61
|
+
if (!metricId) {
|
|
62
|
+
throw new Error("Metric ID is required for aggregated scorecards");
|
|
63
|
+
}
|
|
64
|
+
const baseUrl = await this.getBaseUrl();
|
|
65
|
+
const url = new URL(`${baseUrl}/metrics/${metricId}/catalog/aggregations`);
|
|
66
|
+
try {
|
|
67
|
+
const response = await this.fetchApi.fetch(url.toString());
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
const errorText = await response.text();
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Failed to fetch aggregated scorecards: ${response.status} ${response.statusText}. ${errorText}`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const data = await response.json();
|
|
75
|
+
if (!Array.isArray(data)) {
|
|
76
|
+
throw new TypeError(
|
|
77
|
+
"Invalid response format from aggregated scorecard API"
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
return data;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (error instanceof Error) {
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Unexpected error fetching aggregated scorecards: ${String(error)}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
60
90
|
}
|
|
61
91
|
|
|
62
92
|
export { ScorecardApiClient, scorecardApiRef };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../../src/api/index.ts"],"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 createApiRef,\n FetchApi,\n DiscoveryApi,\n} from '@backstage/core-plugin-api';\nimport type { Entity } from '@backstage/catalog-model';\nimport type {
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../../src/api/index.ts"],"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 createApiRef,\n FetchApi,\n DiscoveryApi,\n} from '@backstage/core-plugin-api';\nimport type { Entity } from '@backstage/catalog-model';\nimport type {\n MetricResult,\n AggregatedMetricResult,\n} from '@red-hat-developer-hub/backstage-plugin-scorecard-common';\n\nexport interface ScorecardApi {\n /**\n * Retrieves scorecard metrics for a specific entity.\n * @param entity - The Backstage entity to get metrics for\n * @param metricIds - Optional array of specific metric IDs to retrieve\n * @returns Promise resolving to an array of metric results\n */\n getScorecards(entity: Entity, metricIds?: string[]): Promise<MetricResult[]>;\n getAggregatedScorecard(metricId: string): Promise<AggregatedMetricResult[]>;\n}\n\nexport const scorecardApiRef = createApiRef<ScorecardApi>({\n id: 'plugin.scorecard.service',\n});\n\nexport type ScorecardApiClientOptions = {\n fetchApi: FetchApi;\n discoveryApi: DiscoveryApi;\n};\n\n/**\n * Client implementation for the Scorecard API.\n * @public\n */\nexport class ScorecardApiClient implements ScorecardApi {\n private readonly fetchApi: FetchApi;\n private readonly discoveryApi: DiscoveryApi;\n\n constructor(options: ScorecardApiClientOptions) {\n this.fetchApi = options.fetchApi;\n this.discoveryApi = options.discoveryApi;\n }\n\n /**\n * Gets the base URL for the scorecard backend API.\n * @returns Promise resolving to the base URL\n */\n async getBaseUrl(): Promise<string> {\n return await this.discoveryApi.getBaseUrl('scorecard');\n }\n\n /**\n * Retrieves scorecard metrics for a specific entity.\n * @param entity - The Backstage entity to get metrics for\n * @param metricIds - Optional array of specific metric IDs to retrieve\n * @returns Promise resolving to an array of metric results\n * @throws Error if the request fails or returns invalid data\n */\n async getScorecards(\n entity: Entity,\n metricIds?: string[],\n ): Promise<MetricResult[]> {\n if (\n !entity?.kind ||\n !entity?.metadata?.namespace ||\n !entity?.metadata?.name\n ) {\n throw new Error(\n 'Entity missing required properties for scorecard lookup',\n );\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(\n `${baseUrl}/metrics/catalog/${entity.kind}/${entity.metadata.namespace}/${entity.metadata.name}`,\n );\n\n if (metricIds) {\n url.searchParams.set('metricIds', metricIds.join(','));\n }\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch scorecards: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (!Array.isArray(data)) {\n throw new Error('Invalid response format from scorecard API');\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error fetching scorecards: ${String(error)}`);\n }\n }\n\n async getAggregatedScorecard(\n metricId: string,\n ): Promise<AggregatedMetricResult[]> {\n if (!metricId) {\n throw new Error('Metric ID is required for aggregated scorecards');\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(`${baseUrl}/metrics/${metricId}/catalog/aggregations`);\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch aggregated scorecards: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (!Array.isArray(data)) {\n throw new TypeError(\n 'Invalid response format from aggregated scorecard API',\n );\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(\n `Unexpected error fetching aggregated scorecards: ${String(error)}`,\n );\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import Card from '@mui/material/Card';
|
|
3
|
+
import CardHeader from '@mui/material/CardHeader';
|
|
4
|
+
import CardContent from '@mui/material/CardContent';
|
|
5
|
+
import Divider from '@mui/material/Divider';
|
|
6
|
+
import Box from '@mui/material/Box';
|
|
7
|
+
import Typography from '@mui/material/Typography';
|
|
8
|
+
|
|
9
|
+
const CardWrapper = ({
|
|
10
|
+
children,
|
|
11
|
+
title,
|
|
12
|
+
subheader,
|
|
13
|
+
description,
|
|
14
|
+
width,
|
|
15
|
+
childrenWidth = "100%",
|
|
16
|
+
childrenHeight = "100%",
|
|
17
|
+
role = "article"
|
|
18
|
+
}) => {
|
|
19
|
+
return /* @__PURE__ */ jsxs(
|
|
20
|
+
Card,
|
|
21
|
+
{
|
|
22
|
+
elevation: 0,
|
|
23
|
+
sx: {
|
|
24
|
+
width: width ?? "100%",
|
|
25
|
+
border: (muiTheme) => `1px solid ${muiTheme.palette.grey[300]}`,
|
|
26
|
+
overflow: "auto"
|
|
27
|
+
},
|
|
28
|
+
role,
|
|
29
|
+
children: [
|
|
30
|
+
/* @__PURE__ */ jsx(
|
|
31
|
+
CardHeader,
|
|
32
|
+
{
|
|
33
|
+
title,
|
|
34
|
+
subheader: subheader ?? void 0,
|
|
35
|
+
sx: {
|
|
36
|
+
"& .v5-MuiCardHeader-title, & .v5-MuiCardHeader-subheader": {
|
|
37
|
+
fontSize: "1.25rem",
|
|
38
|
+
fontWeight: 500,
|
|
39
|
+
display: "-webkit-box",
|
|
40
|
+
WebkitBoxOrient: "vertical",
|
|
41
|
+
WebkitLineClamp: 1,
|
|
42
|
+
overflow: "hidden",
|
|
43
|
+
textOverflow: "ellipsis"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
),
|
|
48
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
49
|
+
/* @__PURE__ */ jsxs(
|
|
50
|
+
CardContent,
|
|
51
|
+
{
|
|
52
|
+
sx: {
|
|
53
|
+
flex: 1,
|
|
54
|
+
display: "flex",
|
|
55
|
+
flexDirection: "column",
|
|
56
|
+
overflow: "hidden"
|
|
57
|
+
},
|
|
58
|
+
children: [
|
|
59
|
+
description && /* @__PURE__ */ jsx(Box, { sx: { pb: 2, width: "100%", minWidth: 316 }, children: /* @__PURE__ */ jsx(
|
|
60
|
+
Typography,
|
|
61
|
+
{
|
|
62
|
+
variant: "body2",
|
|
63
|
+
color: "textSecondary",
|
|
64
|
+
sx: {
|
|
65
|
+
fontSize: "1rem",
|
|
66
|
+
fontWeight: 400,
|
|
67
|
+
display: "-webkit-box",
|
|
68
|
+
WebkitBoxOrient: "vertical",
|
|
69
|
+
WebkitLineClamp: 2,
|
|
70
|
+
overflow: "hidden",
|
|
71
|
+
textOverflow: "ellipsis"
|
|
72
|
+
},
|
|
73
|
+
children: description
|
|
74
|
+
}
|
|
75
|
+
) }),
|
|
76
|
+
/* @__PURE__ */ jsx(
|
|
77
|
+
Box,
|
|
78
|
+
{
|
|
79
|
+
sx: {
|
|
80
|
+
flex: 1,
|
|
81
|
+
minHeight: 0,
|
|
82
|
+
display: "flex",
|
|
83
|
+
justifyContent: "center",
|
|
84
|
+
alignItems: "center"
|
|
85
|
+
},
|
|
86
|
+
children: /* @__PURE__ */ jsx(
|
|
87
|
+
Box,
|
|
88
|
+
{
|
|
89
|
+
sx: {
|
|
90
|
+
width: childrenWidth,
|
|
91
|
+
height: childrenHeight,
|
|
92
|
+
flexShrink: 0
|
|
93
|
+
},
|
|
94
|
+
children
|
|
95
|
+
}
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export { CardWrapper };
|
|
108
|
+
//# sourceMappingURL=CardWrapper.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CardWrapper.esm.js","sources":["../../../src/components/Common/CardWrapper.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 { ReactNode, HTMLProps } from 'react';\n\nimport Card from '@mui/material/Card';\nimport CardHeader from '@mui/material/CardHeader';\nimport CardContent from '@mui/material/CardContent';\nimport Divider from '@mui/material/Divider';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\n\ninterface CardWrapperProps extends HTMLProps<HTMLDivElement> {\n children: ReactNode;\n title: string;\n subheader?: ReactNode;\n description?: string;\n width?: string;\n childrenWidth?: string | number;\n childrenHeight?: string | number;\n role?: string;\n}\n\nexport const CardWrapper = ({\n children,\n title,\n subheader,\n description,\n width,\n childrenWidth = '100%',\n childrenHeight = '100%',\n role = 'article',\n}: CardWrapperProps) => {\n return (\n <Card\n elevation={0}\n sx={{\n width: width ?? '100%',\n border: muiTheme => `1px solid ${muiTheme.palette.grey[300]}`,\n overflow: 'auto',\n }}\n role={role}\n >\n <CardHeader\n title={title}\n subheader={subheader ?? undefined}\n sx={{\n '& .v5-MuiCardHeader-title, & .v5-MuiCardHeader-subheader': {\n fontSize: '1.25rem',\n fontWeight: 500,\n display: '-webkit-box',\n WebkitBoxOrient: 'vertical',\n WebkitLineClamp: 1,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n },\n }}\n />\n <Divider />\n <CardContent\n sx={{\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n }}\n >\n {description && (\n <Box sx={{ pb: 2, width: '100%', minWidth: 316 }}>\n <Typography\n variant=\"body2\"\n color=\"textSecondary\"\n sx={{\n fontSize: '1rem',\n fontWeight: 400,\n display: '-webkit-box',\n WebkitBoxOrient: 'vertical',\n WebkitLineClamp: 2,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {description}\n </Typography>\n </Box>\n )}\n\n <Box\n sx={{\n flex: 1,\n minHeight: 0,\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n }}\n >\n <Box\n sx={{\n width: childrenWidth,\n height: childrenHeight,\n flexShrink: 0,\n }}\n >\n {children}\n </Box>\n </Box>\n </CardContent>\n </Card>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAoCO,MAAM,cAAc,CAAC;AAAA,EAC1B,QAAA;AAAA,EACA,KAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAA;AAAA,EACA,aAAgB,GAAA,MAAA;AAAA,EAChB,cAAiB,GAAA,MAAA;AAAA,EACjB,IAAO,GAAA;AACT,CAAwB,KAAA;AACtB,EACE,uBAAA,IAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,SAAW,EAAA,CAAA;AAAA,MACX,EAAI,EAAA;AAAA,QACF,OAAO,KAAS,IAAA,MAAA;AAAA,QAChB,QAAQ,CAAY,QAAA,KAAA,CAAA,UAAA,EAAa,SAAS,OAAQ,CAAA,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AAAA,QAC3D,QAAU,EAAA;AAAA,OACZ;AAAA,MACA,IAAA;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,KAAA;AAAA,YACA,WAAW,SAAa,IAAA,MAAA;AAAA,YACxB,EAAI,EAAA;AAAA,cACF,0DAA4D,EAAA;AAAA,gBAC1D,QAAU,EAAA,SAAA;AAAA,gBACV,UAAY,EAAA,GAAA;AAAA,gBACZ,OAAS,EAAA,aAAA;AAAA,gBACT,eAAiB,EAAA,UAAA;AAAA,gBACjB,eAAiB,EAAA,CAAA;AAAA,gBACjB,QAAU,EAAA,QAAA;AAAA,gBACV,YAAc,EAAA;AAAA;AAChB;AACF;AAAA,SACF;AAAA,4BACC,OAAQ,EAAA,EAAA,CAAA;AAAA,wBACT,IAAA;AAAA,UAAC,WAAA;AAAA,UAAA;AAAA,YACC,EAAI,EAAA;AAAA,cACF,IAAM,EAAA,CAAA;AAAA,cACN,OAAS,EAAA,MAAA;AAAA,cACT,aAAe,EAAA,QAAA;AAAA,cACf,QAAU,EAAA;AAAA,aACZ;AAAA,YAEC,QAAA,EAAA;AAAA,cACC,WAAA,oBAAA,GAAA,CAAC,GAAI,EAAA,EAAA,EAAA,EAAI,EAAE,EAAA,EAAI,GAAG,KAAO,EAAA,MAAA,EAAQ,QAAU,EAAA,GAAA,EACzC,EAAA,QAAA,kBAAA,GAAA;AAAA,gBAAC,UAAA;AAAA,gBAAA;AAAA,kBACC,OAAQ,EAAA,OAAA;AAAA,kBACR,KAAM,EAAA,eAAA;AAAA,kBACN,EAAI,EAAA;AAAA,oBACF,QAAU,EAAA,MAAA;AAAA,oBACV,UAAY,EAAA,GAAA;AAAA,oBACZ,OAAS,EAAA,aAAA;AAAA,oBACT,eAAiB,EAAA,UAAA;AAAA,oBACjB,eAAiB,EAAA,CAAA;AAAA,oBACjB,QAAU,EAAA,QAAA;AAAA,oBACV,YAAc,EAAA;AAAA,mBAChB;AAAA,kBAEC,QAAA,EAAA;AAAA;AAAA,eAEL,EAAA,CAAA;AAAA,8BAGF,GAAA;AAAA,gBAAC,GAAA;AAAA,gBAAA;AAAA,kBACC,EAAI,EAAA;AAAA,oBACF,IAAM,EAAA,CAAA;AAAA,oBACN,SAAW,EAAA,CAAA;AAAA,oBACX,OAAS,EAAA,MAAA;AAAA,oBACT,cAAgB,EAAA,QAAA;AAAA,oBAChB,UAAY,EAAA;AAAA,mBACd;AAAA,kBAEA,QAAA,kBAAA,GAAA;AAAA,oBAAC,GAAA;AAAA,oBAAA;AAAA,sBACC,EAAI,EAAA;AAAA,wBACF,KAAO,EAAA,aAAA;AAAA,wBACP,MAAQ,EAAA,cAAA;AAAA,wBACR,UAAY,EAAA;AAAA,uBACd;AAAA,sBAEC;AAAA;AAAA;AACH;AAAA;AACF;AAAA;AAAA;AACF;AAAA;AAAA,GACF;AAEJ;;;;"}
|
|
@@ -60,7 +60,7 @@ const PermissionRequiredState = () => {
|
|
|
60
60
|
{
|
|
61
61
|
variant: "outlined",
|
|
62
62
|
target: "_blank",
|
|
63
|
-
href: "https://
|
|
63
|
+
href: "https://docs.redhat.com/en/documentation/red_hat_developer_hub/latest/html-single/understand_and_visualize_red_hat_developer_hub_project_health_using_scorecards/index#proc-authenticating-and-managing-scorecard-plugins_assembly-setting-up-scorecards-to-monitor-your-rhdh-health",
|
|
64
64
|
sx: (theme) => ({
|
|
65
65
|
color: theme.palette.primary.main
|
|
66
66
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PermissionRequiredState.esm.js","sources":["../../../src/components/Common/PermissionRequiredState.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 Grid from '@mui/material/Grid';\nimport Button from '@mui/material/Button';\nimport Typography from '@mui/material/Typography';\nimport OpenInNewIcon from '@mui/icons-material/OpenInNew';\n\nimport { useTranslation } from '../../hooks/useTranslation';\nimport permissionRequiredSvg from '../../images/permission-required.svg';\n\nconst PermissionRequiredState = () => {\n const { t } = useTranslation();\n\n return (\n <Box sx={{ p: 4, height: '100%', maxWidth: '1592px', margin: 'auto' }}>\n <Grid\n container\n spacing={4}\n alignItems=\"center\"\n justifyContent=\"center\"\n height=\"100%\"\n >\n <Grid item xs={12} md={6} sx={{ textAlign: 'left' }}>\n <Typography\n sx={theme => ({\n fontSize: '2.5rem',\n fontWeight: 400,\n color: theme.palette.text.primary,\n mb: 2,\n })}\n >\n {t('permissionRequired.title')}\n </Typography>\n\n <Typography\n sx={theme => ({\n fontSize: '1rem',\n color: theme.palette.text.secondary,\n mb: 3,\n lineHeight: 1.5,\n })}\n >\n {t('permissionRequired.description' as any, {\n permission: (\n <Typography\n component=\"span\"\n sx={theme => ({\n fontWeight: 'bold',\n color: theme.palette.text.primary,\n })}\n >\n scorecard.metric.read\n </Typography>\n ),\n })}\n </Typography>\n\n <Button\n variant=\"outlined\"\n target=\"_blank\"\n href=\"https://
|
|
1
|
+
{"version":3,"file":"PermissionRequiredState.esm.js","sources":["../../../src/components/Common/PermissionRequiredState.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 Grid from '@mui/material/Grid';\nimport Button from '@mui/material/Button';\nimport Typography from '@mui/material/Typography';\nimport OpenInNewIcon from '@mui/icons-material/OpenInNew';\n\nimport { useTranslation } from '../../hooks/useTranslation';\nimport permissionRequiredSvg from '../../images/permission-required.svg';\n\nconst PermissionRequiredState = () => {\n const { t } = useTranslation();\n\n return (\n <Box sx={{ p: 4, height: '100%', maxWidth: '1592px', margin: 'auto' }}>\n <Grid\n container\n spacing={4}\n alignItems=\"center\"\n justifyContent=\"center\"\n height=\"100%\"\n >\n <Grid item xs={12} md={6} sx={{ textAlign: 'left' }}>\n <Typography\n sx={theme => ({\n fontSize: '2.5rem',\n fontWeight: 400,\n color: theme.palette.text.primary,\n mb: 2,\n })}\n >\n {t('permissionRequired.title')}\n </Typography>\n\n <Typography\n sx={theme => ({\n fontSize: '1rem',\n color: theme.palette.text.secondary,\n mb: 3,\n lineHeight: 1.5,\n })}\n >\n {t('permissionRequired.description' as any, {\n permission: (\n <Typography\n component=\"span\"\n sx={theme => ({\n fontWeight: 'bold',\n color: theme.palette.text.primary,\n })}\n >\n scorecard.metric.read\n </Typography>\n ),\n })}\n </Typography>\n\n <Button\n variant=\"outlined\"\n target=\"_blank\"\n href=\"https://docs.redhat.com/en/documentation/red_hat_developer_hub/latest/html-single/understand_and_visualize_red_hat_developer_hub_project_health_using_scorecards/index#proc-authenticating-and-managing-scorecard-plugins_assembly-setting-up-scorecards-to-monitor-your-rhdh-health\"\n sx={theme => ({\n color: theme.palette.primary.main,\n })}\n >\n {t('permissionRequired.button')} <OpenInNewIcon />\n </Button>\n </Grid>\n\n <Grid item xs={12} md={6} sx={{ textAlign: 'right' }}>\n <Box\n component=\"img\"\n src={permissionRequiredSvg}\n alt={t('permissionRequired.altText')}\n sx={{\n width: '100%',\n maxWidth: '600px',\n height: 'auto',\n }}\n />\n </Grid>\n </Grid>\n </Box>\n );\n};\n\nexport default PermissionRequiredState;\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import Box from '@mui/material/Box';
|
|
3
|
+
import Typography from '@mui/material/Typography';
|
|
4
|
+
import { useTheme, styled } from '@mui/material/styles';
|
|
5
|
+
import { useTranslation } from '../../hooks/useTranslation.esm.js';
|
|
6
|
+
|
|
7
|
+
const StyledLegend = styled(Box)(({ theme }) => ({
|
|
8
|
+
display: "flex",
|
|
9
|
+
flexDirection: "column",
|
|
10
|
+
gap: theme.spacing(1),
|
|
11
|
+
paddingLeft: theme.spacing(3.2)
|
|
12
|
+
}));
|
|
13
|
+
const StyledLegendItem = styled(Box)(({ theme }) => ({
|
|
14
|
+
display: "flex",
|
|
15
|
+
alignItems: "center",
|
|
16
|
+
gap: theme.spacing(1)
|
|
17
|
+
}));
|
|
18
|
+
const StyledLegendColorBox = styled(Box)(({ color }) => ({
|
|
19
|
+
width: "10px",
|
|
20
|
+
height: "10px",
|
|
21
|
+
backgroundColor: color,
|
|
22
|
+
flexShrink: 0
|
|
23
|
+
}));
|
|
24
|
+
const CustomLegend = (props) => {
|
|
25
|
+
const { thresholds } = props;
|
|
26
|
+
const theme = useTheme();
|
|
27
|
+
const { t } = useTranslation();
|
|
28
|
+
if (!thresholds || thresholds?.definition?.rules?.length === 0 || thresholds?.definition?.rules === void 0) {
|
|
29
|
+
return /* @__PURE__ */ jsx(StyledLegend, { children: /* @__PURE__ */ jsxs(StyledLegendItem, { children: [
|
|
30
|
+
/* @__PURE__ */ jsx(StyledLegendColorBox, { color: theme.palette.grey["400"] }),
|
|
31
|
+
" --"
|
|
32
|
+
] }) });
|
|
33
|
+
}
|
|
34
|
+
return /* @__PURE__ */ jsx(StyledLegend, { children: thresholds?.definition?.rules?.map(
|
|
35
|
+
({ key: ruleKey, expression: ruleExpression }) => {
|
|
36
|
+
return /* @__PURE__ */ jsxs(StyledLegendItem, { children: [
|
|
37
|
+
/* @__PURE__ */ jsx(
|
|
38
|
+
StyledLegendColorBox,
|
|
39
|
+
{
|
|
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
|
+
}
|
|
46
|
+
),
|
|
47
|
+
/* @__PURE__ */ jsxs(
|
|
48
|
+
Typography,
|
|
49
|
+
{
|
|
50
|
+
variant: "body2",
|
|
51
|
+
sx: { fontSize: "0.875rem", fontWeight: 400 },
|
|
52
|
+
children: [
|
|
53
|
+
(() => {
|
|
54
|
+
const translated = t(`thresholds.${ruleKey}`, {});
|
|
55
|
+
return translated === `thresholds.${ruleKey}` ? ruleKey.charAt(0).toUpperCase() + ruleKey.slice(1) : translated;
|
|
56
|
+
})(),
|
|
57
|
+
" ",
|
|
58
|
+
ruleExpression && `${ruleExpression}`
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
] }, `legend-${ruleKey}`);
|
|
63
|
+
}
|
|
64
|
+
) });
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export { CustomLegend as default };
|
|
68
|
+
//# sourceMappingURL=CustomLegend.esm.js.map
|
|
@@ -0,0 +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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"}
|
|
@@ -41,7 +41,7 @@ const EntityScorecardContent = () => {
|
|
|
41
41
|
gap: 2,
|
|
42
42
|
sx: { alignItems: "flex-start" },
|
|
43
43
|
children: scorecards?.map((metric) => {
|
|
44
|
-
const isMetricDataError = metric.status === "error" || metric.result?.value ===
|
|
44
|
+
const isMetricDataError = metric.status === "error" || metric.result?.value === null;
|
|
45
45
|
const isThresholdError = metric.result?.thresholdResult?.status === "error";
|
|
46
46
|
const statusConfig = getStatusConfig({
|
|
47
47
|
evaluation: metric.result?.thresholdResult?.evaluation,
|
|
@@ -59,7 +59,6 @@ const EntityScorecardContent = () => {
|
|
|
59
59
|
{
|
|
60
60
|
cardTitle: finalTitle,
|
|
61
61
|
description: finalDescription,
|
|
62
|
-
loading: false,
|
|
63
62
|
statusColor: statusConfig.color,
|
|
64
63
|
StatusIcon: statusConfig.icon ?? (() => null),
|
|
65
64
|
value: metric.result?.value,
|
|
@@ -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 ===
|
|
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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"}
|