@red-hat-developer-hub/backstage-plugin-scorecard 2.2.0 → 2.3.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 (52) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +2 -2
  3. package/dist/alpha.d.ts +9 -3
  4. package/dist/api/index.esm.js +30 -0
  5. package/dist/api/index.esm.js.map +1 -1
  6. package/dist/components/Common/CardWrapper.esm.js +108 -0
  7. package/dist/components/Common/CardWrapper.esm.js.map +1 -0
  8. package/dist/components/Common/PermissionRequiredState.esm.js +1 -1
  9. package/dist/components/Common/PermissionRequiredState.esm.js.map +1 -1
  10. package/dist/components/Scorecard/CustomLegend.esm.js +68 -0
  11. package/dist/components/Scorecard/CustomLegend.esm.js.map +1 -0
  12. package/dist/components/Scorecard/EntityScorecardContent.esm.js +1 -2
  13. package/dist/components/Scorecard/EntityScorecardContent.esm.js.map +1 -1
  14. package/dist/components/Scorecard/Scorecard.esm.js +161 -217
  15. package/dist/components/Scorecard/Scorecard.esm.js.map +1 -1
  16. package/dist/components/ScorecardHomepageSection/CustomLegend.esm.js +96 -0
  17. package/dist/components/ScorecardHomepageSection/CustomLegend.esm.js.map +1 -0
  18. package/dist/components/ScorecardHomepageSection/CustomTooltip.esm.js +69 -0
  19. package/dist/components/ScorecardHomepageSection/CustomTooltip.esm.js.map +1 -0
  20. package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js +110 -0
  21. package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js.map +1 -0
  22. package/dist/components/ScorecardHomepageSection/ResponsivePieChart.esm.js +50 -0
  23. package/dist/components/ScorecardHomepageSection/ResponsivePieChart.esm.js.map +1 -0
  24. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js +50 -0
  25. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js.map +1 -0
  26. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCardComponent.esm.js +105 -0
  27. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCardComponent.esm.js.map +1 -0
  28. package/dist/components/ScorecardHomepageSection/index.esm.js +2 -0
  29. package/dist/components/ScorecardHomepageSection/index.esm.js.map +1 -0
  30. package/dist/hooks/useAggregatedScorecard.esm.js +42 -0
  31. package/dist/hooks/useAggregatedScorecard.esm.js.map +1 -0
  32. package/dist/index.d.ts +8 -1
  33. package/dist/index.esm.js +1 -1
  34. package/dist/plugin.esm.js +13 -3
  35. package/dist/plugin.esm.js.map +1 -1
  36. package/dist/translations/de.esm.js +7 -1
  37. package/dist/translations/de.esm.js.map +1 -1
  38. package/dist/translations/es.esm.js +7 -1
  39. package/dist/translations/es.esm.js.map +1 -1
  40. package/dist/translations/fr.esm.js +22 -21
  41. package/dist/translations/fr.esm.js.map +1 -1
  42. package/dist/translations/index.esm.js +3 -1
  43. package/dist/translations/index.esm.js.map +1 -1
  44. package/dist/translations/it.esm.js +34 -0
  45. package/dist/translations/it.esm.js.map +1 -0
  46. package/dist/translations/ja.esm.js +34 -0
  47. package/dist/translations/ja.esm.js.map +1 -0
  48. package/dist/translations/ref.esm.js +8 -2
  49. package/dist/translations/ref.esm.js.map +1 -1
  50. package/dist/utils/utils.esm.js +8 -1
  51. package/dist/utils/utils.esm.js.map +1 -1
  52. package/package.json +5 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,56 @@
1
1
  # @red-hat-developer-hub/backstage-plugin-scorecard
2
2
 
3
+ ## 2.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 52b60ee: Added aggregated metric cards frontend
8
+ - 4e360d5: Implemented endpoint to aggregate metrics for scorecard metrics
9
+
10
+ **BREAKING** Update attribute `value` in the `MetricResult` type and update validation to support `null` instead `undefined` for the updated attribute
11
+
12
+ ```diff
13
+ export type MetricResult = {
14
+ id: string;
15
+ status: 'success' | 'error';
16
+ metadata: {
17
+ title: string;
18
+ description: string;
19
+ type: MetricType;
20
+ history?: boolean;
21
+ };
22
+ result: {
23
+ - value?: MetricValue;
24
+ + value: MetricValue | null;
25
+ timestamp: string;
26
+ thresholdResult: ThresholdResult;
27
+ };
28
+ error?: string;
29
+ };
30
+ ```
31
+
32
+ **BREAKING** Update attribute `evaluation` in the `ThresholdResult` type and update validation to support `null` instead `undefined` for the updated attribute
33
+
34
+ ```diff
35
+ export type ThresholdResult = {
36
+ status: 'success' | 'error';
37
+ - definition: ThresholdConfig | undefined;
38
+ + definition: ThresholdConfig | null;
39
+ evaluation: string | undefined; // threshold key the expression evaluated to
40
+ error?: string;
41
+ };
42
+ ```
43
+
44
+ ### Patch Changes
45
+
46
+ - 9dee966: Integrated UI with backend aggregated api
47
+ - f74564d: Added 'it' and 'ja' i18n translation support and updated 'fr' translations.
48
+ - 6318931: Updated dependency `@red-hat-developer-hub/backstage-plugin-theme` to `^0.12.0`.
49
+ - 61d0c34: Updated dependency `@red-hat-developer-hub/backstage-plugin-theme` to `^0.11.0`.
50
+ - Updated dependencies [52b60ee]
51
+ - Updated dependencies [4e360d5]
52
+ - @red-hat-developer-hub/backstage-plugin-scorecard-common@2.3.0
53
+
3
54
  ## 2.2.0
4
55
 
5
56
  ### 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 { ScorecardPage } from '@red-hat-developer-hub/backstage-plugin-scorecard';
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
- <ScorecardPage />
60
+ <EntityScorecardContent />
61
61
  </EntityLayout.Route>
62
62
  );
63
63
 
package/dist/alpha.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import * as _backstage_core_plugin_api_alpha from '@backstage/core-plugin-api/alpha';
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: _backstage_core_plugin_api_alpha.TranslationRef<"plugin.scorecard", {
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: _backstage_core_plugin_api_alpha.TranslationResource<"plugin.scorecard">;
40
+ declare const scorecardTranslations: _backstage_frontend_plugin_api.TranslationResource<"plugin.scorecard">;
35
41
 
36
42
  export { scorecardTranslationRef, scorecardTranslations };
@@ -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 { MetricResult } 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}\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"],"names":[],"mappings":";;AAkCO,MAAM,kBAAkB,YAA2B,CAAA;AAAA,EACxD,EAAI,EAAA;AACN,CAAC;AAWM,MAAM,kBAA2C,CAAA;AAAA,EACrC,QAAA;AAAA,EACA,YAAA;AAAA,EAEjB,YAAY,OAAoC,EAAA;AAC9C,IAAA,IAAA,CAAK,WAAW,OAAQ,CAAA,QAAA;AACxB,IAAA,IAAA,CAAK,eAAe,OAAQ,CAAA,YAAA;AAAA;AAC9B;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,UAA8B,GAAA;AAClC,IAAA,OAAO,MAAM,IAAA,CAAK,YAAa,CAAA,UAAA,CAAW,WAAW,CAAA;AAAA;AACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,aACJ,CAAA,MAAA,EACA,SACyB,EAAA;AACzB,IACE,IAAA,CAAC,MAAQ,EAAA,IAAA,IACT,CAAC,MAAA,EAAQ,UAAU,SACnB,IAAA,CAAC,MAAQ,EAAA,QAAA,EAAU,IACnB,EAAA;AACA,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA;AAGF,IAAM,MAAA,OAAA,GAAU,MAAM,IAAA,CAAK,UAAW,EAAA;AACtC,IAAA,MAAM,MAAM,IAAI,GAAA;AAAA,MACd,CAAG,EAAA,OAAO,CAAoB,iBAAA,EAAA,MAAA,CAAO,IAAI,CAAA,CAAA,EAAI,MAAO,CAAA,QAAA,CAAS,SAAS,CAAA,CAAA,EAAI,MAAO,CAAA,QAAA,CAAS,IAAI,CAAA;AAAA,KAChG;AAEA,IAAA,IAAI,SAAW,EAAA;AACb,MAAA,GAAA,CAAI,aAAa,GAAI,CAAA,WAAA,EAAa,SAAU,CAAA,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA;AAGvD,IAAI,IAAA;AACF,MAAA,MAAM,WAAW,MAAM,IAAA,CAAK,SAAS,KAAM,CAAA,GAAA,CAAI,UAAU,CAAA;AAEzD,MAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,QAAM,MAAA,SAAA,GAAY,MAAM,QAAA,CAAS,IAAK,EAAA;AACtC,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,+BAA+B,QAAS,CAAA,MAAM,IAAI,QAAS,CAAA,UAAU,KAAK,SAAS,CAAA;AAAA,SACrF;AAAA;AAGF,MAAM,MAAA,IAAA,GAAO,MAAM,QAAA,CAAS,IAAK,EAAA;AAEjC,MAAA,IAAI,CAAC,KAAA,CAAM,OAAQ,CAAA,IAAI,CAAG,EAAA;AACxB,QAAM,MAAA,IAAI,MAAM,4CAA4C,CAAA;AAAA;AAG9D,MAAO,OAAA,IAAA;AAAA,aACA,KAAO,EAAA;AACd,MAAA,IAAI,iBAAiB,KAAO,EAAA;AAC1B,QAAM,MAAA,KAAA;AAAA;AAER,MAAA,MAAM,IAAI,KAAM,CAAA,CAAA,sCAAA,EAAyC,MAAO,CAAA,KAAK,CAAC,CAAE,CAAA,CAAA;AAAA;AAC1E;AAEJ;;;;"}
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://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/scorecard/plugins/scorecard/README.md#permission-framework-support",
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://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/scorecard/plugins/scorecard/README.md#permission-framework-support\"\n sx={theme => ({\n color: theme.palette.primary.main,\n })}\n >\n {t('permissionRequired.button')} &nbsp; <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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"}
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')} &nbsp; <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 === void 0;
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 === undefined;\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 loading={false}\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/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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"}