@red-hat-developer-hub/backstage-plugin-scorecard 2.4.0 → 2.5.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.
Files changed (122) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +278 -25
  3. package/dist/alpha/extensions/api.esm.js +15 -0
  4. package/dist/alpha/extensions/api.esm.js.map +1 -0
  5. package/dist/alpha/extensions/entityTab.esm.js +42 -0
  6. package/dist/alpha/extensions/entityTab.esm.js.map +1 -0
  7. package/dist/alpha/extensions/homePageCards.esm.js +90 -0
  8. package/dist/alpha/extensions/homePageCards.esm.js.map +1 -0
  9. package/dist/alpha/extensions/scorecardPage.esm.js +14 -0
  10. package/dist/alpha/extensions/scorecardPage.esm.js.map +1 -0
  11. package/dist/alpha.d.ts +75 -37
  12. package/dist/alpha.esm.js +41 -1
  13. package/dist/alpha.esm.js.map +1 -1
  14. package/dist/api/ScorecardQueryProvider.esm.js +32 -0
  15. package/dist/api/ScorecardQueryProvider.esm.js.map +1 -0
  16. package/dist/api/index.esm.js +122 -14
  17. package/dist/api/index.esm.js.map +1 -1
  18. package/dist/components/Common/CardLoading.esm.js +20 -0
  19. package/dist/components/Common/CardLoading.esm.js.map +1 -0
  20. package/dist/components/Common/CardWrapper.esm.js +25 -18
  21. package/dist/components/Common/CardWrapper.esm.js.map +1 -1
  22. package/dist/components/Common/ErrorTooltip.esm.js +2 -2
  23. package/dist/components/Common/ErrorTooltip.esm.js.map +1 -1
  24. package/dist/components/Common/NoScorecardsState.esm.js +3 -1
  25. package/dist/components/Common/NoScorecardsState.esm.js.map +1 -1
  26. package/dist/components/Common/NotFoundState.esm.js +152 -0
  27. package/dist/components/Common/NotFoundState.esm.js.map +1 -0
  28. package/dist/components/Common/PermissionRequiredState.esm.js +3 -1
  29. package/dist/components/Common/PermissionRequiredState.esm.js.map +1 -1
  30. package/dist/components/Scorecard/CustomLegend.esm.js +3 -4
  31. package/dist/components/Scorecard/CustomLegend.esm.js.map +1 -1
  32. package/dist/components/Scorecard/EntityScorecardContent.esm.js +8 -16
  33. package/dist/components/Scorecard/EntityScorecardContent.esm.js.map +1 -1
  34. package/dist/components/Scorecard/Scorecard.esm.js +10 -8
  35. package/dist/components/Scorecard/Scorecard.esm.js.map +1 -1
  36. package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js +12 -9
  37. package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js.map +1 -1
  38. package/dist/components/ScorecardHomepageSection/ErrorStatePanel.esm.js +51 -22
  39. package/dist/components/ScorecardHomepageSection/ErrorStatePanel.esm.js.map +1 -1
  40. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js +48 -30
  41. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js.map +1 -1
  42. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCardComponent.esm.js +69 -6
  43. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCardComponent.esm.js.map +1 -1
  44. package/dist/components/ScorecardHomepageSection/index.esm.js +1 -1
  45. package/dist/components/ScorecardIcon/ScorecardIcon.esm.js +30 -0
  46. package/dist/components/ScorecardIcon/ScorecardIcon.esm.js.map +1 -0
  47. package/dist/components/ScorecardPage/EntitiesTable/EntitiesRow.esm.js +57 -0
  48. package/dist/components/ScorecardPage/EntitiesTable/EntitiesRow.esm.js.map +1 -0
  49. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTable.esm.js +155 -0
  50. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTable.esm.js.map +1 -0
  51. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableFooter.esm.js +111 -0
  52. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableFooter.esm.js.map +1 -0
  53. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableHeader.esm.js +31 -0
  54. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableHeader.esm.js.map +1 -0
  55. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTablePagination.esm.js +76 -0
  56. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTablePagination.esm.js.map +1 -0
  57. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableStateRow.esm.js +36 -0
  58. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableStateRow.esm.js.map +1 -0
  59. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableWrapper.esm.js +58 -0
  60. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableWrapper.esm.js.map +1 -0
  61. package/dist/components/ScorecardPage/EntitiesTable/cells/EntityNameCell.esm.js +36 -0
  62. package/dist/components/ScorecardPage/EntitiesTable/cells/EntityNameCell.esm.js.map +1 -0
  63. package/dist/components/ScorecardPage/EntitiesTable/cells/MetricStatusCell.esm.js +38 -0
  64. package/dist/components/ScorecardPage/EntitiesTable/cells/MetricStatusCell.esm.js.map +1 -0
  65. package/dist/components/ScorecardPage/EntitiesTable/cells/OwnerCell.esm.js +35 -0
  66. package/dist/components/ScorecardPage/EntitiesTable/cells/OwnerCell.esm.js.map +1 -0
  67. package/dist/components/ScorecardPage/ScorecardPage.esm.js +94 -0
  68. package/dist/components/ScorecardPage/ScorecardPage.esm.js.map +1 -0
  69. package/dist/components/ScorecardPage/ScorecardPageHeader.esm.js +9 -0
  70. package/dist/components/ScorecardPage/ScorecardPageHeader.esm.js.map +1 -0
  71. package/dist/hooks/useAggregatedScorecard.esm.js +28 -32
  72. package/dist/hooks/useAggregatedScorecard.esm.js.map +1 -1
  73. package/dist/hooks/useAggregatedScorecardEntities.esm.js +59 -0
  74. package/dist/hooks/useAggregatedScorecardEntities.esm.js.map +1 -0
  75. package/dist/hooks/useAggregationMetadata.esm.js +38 -0
  76. package/dist/hooks/useAggregationMetadata.esm.js.map +1 -0
  77. package/dist/hooks/useEntityMetadataMap.esm.js +87 -0
  78. package/dist/hooks/useEntityMetadataMap.esm.js.map +1 -0
  79. package/dist/hooks/useLanguage.esm.js +7 -0
  80. package/dist/hooks/useLanguage.esm.js.map +1 -0
  81. package/dist/hooks/useMetric.esm.js +38 -0
  82. package/dist/hooks/useMetric.esm.js.map +1 -0
  83. package/dist/hooks/useMetricDisplayLabels.esm.js +22 -0
  84. package/dist/hooks/useMetricDisplayLabels.esm.js.map +1 -0
  85. package/dist/hooks/useOwnershipEntityRefs.esm.js +21 -0
  86. package/dist/hooks/useOwnershipEntityRefs.esm.js.map +1 -0
  87. package/dist/hooks/useScorecards.esm.js +14 -7
  88. package/dist/hooks/useScorecards.esm.js.map +1 -1
  89. package/dist/images/not-found.svg +9 -0
  90. package/dist/index.d.ts +16 -5
  91. package/dist/index.esm.js +4 -1
  92. package/dist/index.esm.js.map +1 -1
  93. package/dist/pages/ScorecardPage.esm.js +2 -0
  94. package/dist/pages/ScorecardPage.esm.js.map +1 -0
  95. package/dist/plugin.esm.js +9 -2
  96. package/dist/plugin.esm.js.map +1 -1
  97. package/dist/routes.esm.js +5 -1
  98. package/dist/routes.esm.js.map +1 -1
  99. package/dist/translations/de.esm.js +55 -1
  100. package/dist/translations/de.esm.js.map +1 -1
  101. package/dist/translations/es.esm.js +55 -1
  102. package/dist/translations/es.esm.js.map +1 -1
  103. package/dist/translations/fr.esm.js +36 -1
  104. package/dist/translations/fr.esm.js.map +1 -1
  105. package/dist/translations/it.esm.js +37 -1
  106. package/dist/translations/it.esm.js.map +1 -1
  107. package/dist/translations/ja.esm.js +37 -1
  108. package/dist/translations/ja.esm.js.map +1 -1
  109. package/dist/translations/ref.esm.js +44 -2
  110. package/dist/translations/ref.esm.js.map +1 -1
  111. package/dist/types/index.d-N3BD4rEg.d.ts +75 -0
  112. package/dist/utils/constants.esm.js +39 -1
  113. package/dist/utils/constants.esm.js.map +1 -1
  114. package/dist/utils/entityTableUtils.esm.js +49 -0
  115. package/dist/utils/entityTableUtils.esm.js.map +1 -0
  116. package/dist/utils/statusUtils.esm.js +20 -12
  117. package/dist/utils/statusUtils.esm.js.map +1 -1
  118. package/dist/utils/thresholdUtils.esm.js +37 -0
  119. package/dist/utils/thresholdUtils.esm.js.map +1 -0
  120. package/package.json +35 -15
  121. package/dist/utils/colorUtils.esm.js +0 -38
  122. package/dist/utils/colorUtils.esm.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,53 @@
1
1
  # @red-hat-developer-hub/backstage-plugin-scorecard
2
2
 
3
+ ## 2.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - f6f7bcf: add threshold-based status colors to entities table
8
+ - 0fda0c7: fixed the scorecard-homepage-cards default layout for nfs
9
+ - @red-hat-developer-hub/backstage-plugin-scorecard-common@2.5.1
10
+
11
+ ## 2.5.0
12
+
13
+ ### Minor Changes
14
+
15
+ - d706601: Backstage version bump to v1.49.3
16
+ - 55226c2: Introduces custom threshold rule icons that can be configured in `app-config.yaml`.
17
+ - f13f583: Adding scorecardHomepage and metric page extension, also added e2e support in nfs
18
+ - 0d64361: Adds a Scorecard Entities page that allows users to drill down from aggregated scorecard KPIs to view the individual entities contributing to the overall score. The page displays entity-level metric values and status, enabling users to identify services impacting the metric and investigate issues more effectively.
19
+ - 243ad0a: Aggregated scorecards now use **aggregation IDs** and dedicated HTTP routes. The old catalog-aggregations URL still works but is **deprecated** (not removed).
20
+
21
+ **Backend (`@red-hat-developer-hub/backstage-plugin-scorecard-backend`)**
22
+
23
+ - **Deprecated:** `GET /metrics/:metricId/catalog/aggregations` — responses are unchanged, but the handler emits [RFC 8594](https://datatracker.ietf.org/doc/html/rfc8594) `Deprecation` and `Link` headers (alternate successor: `GET .../aggregations/:aggregationId`) and logs a warning. Prefer **`GET /aggregations/:aggregationId`** for new integrations.
24
+ - **Added:** `GET /aggregations/:aggregationId` for aggregated results using configured aggregation.
25
+ - **Added:** `GET /aggregations/:aggregationId/metadata` for KPI titles, descriptions, and aggregation metadata consumed by the UI.
26
+
27
+ **Common (`@red-hat-developer-hub/backstage-plugin-scorecard-common`)**
28
+
29
+ - Types and constants aligned with the aggregation config and new API shapes.
30
+
31
+ **Frontend (`@red-hat-developer-hub/backstage-plugin-scorecard`)**
32
+
33
+ - Homepage and aggregated flows resolve cards via **`aggregationId`**, fetch metadata from the new endpoint, and keep localized threshold and error strings where translation keys exist.
34
+
35
+ **Action for adopters:** Configure aggregated scorecards with `aggregationId` values that match backend aggregation config, replace direct calls to `GET /metrics/:metricId/catalog/aggregations` with `GET /aggregations/:aggregationId` (and metadata if you need the same labels as the plugin UI).
36
+
37
+ - 99aa8ff: Added support for the New Frontend System (NFS), including an alpha export for NFS apps and a new `app-next` package.
38
+
39
+ ### Patch Changes
40
+
41
+ - 6bd7c38: Enable sorting for all other columns in entities table
42
+ - ff005a3: add translation for the scorecard entities table status column
43
+ - afd7a1e: Update translations for Scorecard.
44
+ - 2667f70: Fix scorecard entity table column header Metric to Status
45
+ - Updated dependencies [d706601]
46
+ - Updated dependencies [55226c2]
47
+ - Updated dependencies [243ad0a]
48
+ - Updated dependencies [c83b206]
49
+ - @red-hat-developer-hub/backstage-plugin-scorecard-common@2.5.0
50
+
3
51
  ## 2.4.0
4
52
 
5
53
  ### Minor Changes
package/README.md CHANGED
@@ -1,7 +1,14 @@
1
- # 📊 Scorecard Plugin for Backstage
1
+ # Scorecard Plugin for Backstage
2
2
 
3
3
  The Scorecard plugin provides a configurable framework to visualize Key Performance Indicators (KPIs) in Backstage. This frontend plugin integrates with the Scorecard backend to deliver Scorecards.
4
4
 
5
+ The plugin supports both the **legacy** Backstage frontend and the **New Frontend System (NFS)**. Use the main package for legacy apps and the `/alpha` export for NFS apps. For NFS, the plugin currently provides three modules: a catalog module for the Scorecard entity tab, a home module for homepage widgets, and a translations module.
6
+ **Features:**
7
+
8
+ - **Entity scorecard tab** — View scorecard metrics on catalog entity pages (components, websites, etc.).
9
+ - **Scorecard homepage card** — Show aggregated KPIs on the home page (e.g. GitHub open PRs, Jira open issues).
10
+ - **Scorecard Entities page** — Drill down from an aggregated metric to see the list of entities contributing to that metric, with entity-level values and status, so you can identify services impacting the KPI and investigate issues.
11
+
5
12
  ## Getting started
6
13
 
7
14
  Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/scorecard](http://localhost:3000/scorecard).
@@ -16,43 +23,196 @@ It is only meant for local development, and the setup for it can be found inside
16
23
 
17
24
  Before installing the frontend plugin, ensure that the Scorecard backend is integrated into your Backstage instance. Follow the [Scorecard backend plugin README](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/scorecard/plugins/scorecard-backend/README.md) for setup instructions.
18
25
 
19
- ### Installation
26
+ ### Installation and usage
20
27
 
21
- To install the Scorecard plugin, run the following command:
28
+ Install the package in your frontend (use `app` for NFS or `app-legacy` for legacy):
22
29
 
23
30
  ```sh
24
31
  yarn workspace app add @red-hat-developer-hub/backstage-plugin-scorecard
32
+ # or for the legacy frontend:
33
+ yarn workspace app-legacy add @red-hat-developer-hub/backstage-plugin-scorecard
25
34
  ```
26
35
 
27
- **Note**
36
+ ### Procedure
28
37
 
29
- ### Permission Framework Support
38
+ #### NFS (New Frontend System) — app
30
39
 
31
- The Scorecard plugin has support for the permission framework.
40
+ 1. Install the Scorecard frontend plugin (see [Installation and usage](#installation-and-usage)) using `app`:
32
41
 
33
- - When [RBAC permission](https://github.com/backstage/community-plugins/tree/main/workspaces/rbac/plugins/rbac-backend#installation) framework is enabled, for non-admin users to access scorecard UI, the role associated with your user should have the following permission policies associated with it. Add the following in your permission policies configuration file named `rbac-policy.csv`:
42
+ ```console
43
+ yarn workspace app add @red-hat-developer-hub/backstage-plugin-scorecard
44
+ ```
34
45
 
35
- ```CSV
36
- p, role:default/team_a, scorecard.metric.read, read, allow
46
+ 2. Register the plugin in `packages/app/src/App.tsx` using the **alpha** export:
37
47
 
38
- g, user:default/<your-user-name>, role:default/team_a
48
+ ```tsx
49
+ // In packages/app/src/App.tsx
50
+ import { createApp } from '@backstage/frontend-defaults';
51
+ import {
52
+ scorecardHomeModule,
53
+ scorecardTranslationsModule,
54
+ scorecardCatalogModule,
55
+ } from '@red-hat-developer-hub/backstage-plugin-scorecard/alpha';
56
+
57
+ const app = createApp({
58
+ features: [
59
+ scorecardHomeModule,
60
+ scorecardCatalogModule,
61
+ scorecardTranslationsModule,
62
+ // ... other plugins
63
+ ],
64
+ });
65
+
66
+ export default app.createRoot();
67
+ ```
68
+
69
+ 3. (Optional) Configure which entities show the Scorecard tab in `app-config.yaml` under `app.extensions`. If you do not add this extension config, the tab is shown for all entity kinds. To restrict by kind and optionally by type:
70
+
71
+ ```yaml
72
+ app:
73
+ extensions:
74
+ - entity-content:catalog/entity-content-scorecard:
75
+ config:
76
+ allowedFilters:
77
+ - kind: component
78
+ - kind: template
79
+ - kind: resource
80
+ - kind: location
81
+ ```
82
+
83
+ Each filter can include optional `kind` and/or `type`. An entity shows the tab if it matches at least one filter. You can restrict by **kind only**, by **type only**, or by **kind and type**:
84
+
85
+ **By kind only:**
86
+
87
+ ```yaml
88
+ allowedFilters:
89
+ - kind: component
90
+ - kind: template
39
91
  ```
40
92
 
41
- You can specify the path to this configuration file in your application configuration:
93
+ **By type only** (e.g. any entity with `spec.type` equal to `service` or `website`):
42
94
 
43
95
  ```yaml
44
- permission:
45
- enabled: true
46
- rbac:
47
- policies-csv-file: /some/path/rbac-policy.csv
48
- policyFileReload: true
96
+ allowedFilters:
97
+ - type: service
98
+ - type: website
49
99
  ```
50
100
 
51
- **Note:** The backend also checks `catalog.entity.read` for each entity. Make sure your users/roles can read the catalog entities they want to view scorecards for.
101
+ **By kind and type** (e.g. only `component` with type `website` or type `service`):
52
102
 
53
- ### Configuration
103
+ ```yaml
104
+ allowedFilters:
105
+ - kind: component
106
+ type: website
107
+ - kind: component
108
+ type: service
109
+ ```
110
+
111
+ To align with the legacy EntityPage (Scorecard on component pages and default entity page, not on api/group/user/system/domain), use the first example (by kind only).
112
+
113
+ 4. Ensure the frontend can reach the Scorecard backend by configuring discovery in `app-config.yaml`:
114
+
115
+ ```yaml
116
+ discovery:
117
+ endpoints:
118
+ - target: http://localhost:7007/api/{{ pluginId }}
119
+ plugins:
120
+ - scorecard
121
+ ```
122
+
123
+ 5. Start the NFS app (e.g. `yarn start`), go to **Catalog**, open an entity. The **Scorecard** tab appears for entities that match your `allowedFilters` (or all entities if the extension config is omitted or empty).
124
+
125
+ 6. (Optional) Enable homepage Scorecard widgets by adding `scorecardHomeModule` to app features (see step 2) and configuring home page extensions in `app-config.yaml`:
126
+
127
+ ```yaml
128
+ app:
129
+ extensions:
130
+ - page:home:
131
+ config:
132
+ path: /
133
+ - api:home/visits: true
134
+ - app-root-element:home/visit-listener: true
135
+ - home-page-layout:home/dynamic-homepage-layout:
136
+ config:
137
+ customizable: true
138
+ widgetLayout:
139
+ AggregatedCardWithDeprecatedMetricId:
140
+ priority: 410
141
+ breakpoints:
142
+ xl: { w: 4, h: 6 }
143
+ lg: { w: 4, h: 6 }
144
+ md: { w: 4, h: 6 }
145
+ sm: { w: 4, h: 6 }
146
+ xs: { w: 4, h: 6 }
147
+ xxs: { w: 4, h: 6 }
148
+ AggregatedCardWithDefaultAggregation:
149
+ priority: 420
150
+ breakpoints:
151
+ xl: { w: 4, h: 6, x: 4 }
152
+ lg: { w: 4, h: 6, x: 4 }
153
+ md: { w: 4, h: 6, x: 4 }
154
+ sm: { w: 4, h: 6, x: 4 }
155
+ xs: { w: 4, h: 6, x: 4 }
156
+ xxs: { w: 4, h: 6, x: 4 }
157
+ AggregatedCardWithJiraOpenIssues:
158
+ priority: 430
159
+ breakpoints:
160
+ xl: { w: 4, h: 6 }
161
+ lg: { w: 4, h: 6 }
162
+ md: { w: 4, h: 6 }
163
+ sm: { w: 4, h: 6 }
164
+ xs: { w: 4, h: 6 }
165
+ xxs: { w: 4, h: 6 }
166
+ AggregatedCardWithGithubOpenPrs:
167
+ priority: 440
168
+ breakpoints:
169
+ xl: { w: 4, h: 6, x: 4 }
170
+ lg: { w: 4, h: 6, x: 4 }
171
+ md: { w: 4, h: 6, x: 4 }
172
+ sm: { w: 4, h: 6, x: 4 }
173
+ xs: { w: 4, h: 6, x: 4 }
174
+ xxs: { w: 4, h: 6, x: 4 }
175
+ ```
176
+
177
+ The home module contributes four widgets:
178
+
179
+ - `AggregatedCardWithDeprecatedMetricId` (title: **Scorecard: With deprecated metricId property (Jira)**)
180
+ - `AggregatedCardWithDefaultAggregation` (title: **Scorecard: With default aggregation config (GitHub)**)
181
+ - `AggregatedCardWithJiraOpenIssues` (title: **Scorecard: Jira open blocking tickets**)
182
+ - `AggregatedCardWithGithubOpenPrs` (title: **Scorecard: GitHub open PRs**)
183
+
184
+ These widgets render the `ScorecardHomepageCard` component used in legacy apps, preconfigured with different aggregation/metric configurations.
185
+
186
+ ##### Modules and extensions (NFS)
187
+
188
+ The following modules and extensions are available from `@red-hat-developer-hub/backstage-plugin-scorecard/alpha` for NFS apps:
54
189
 
55
- 1. Add the Scorecard page to you Entity overview page by modifying `packages/app/src/components/catalog/EntityPage.tsx`:
190
+ **Modules**
191
+
192
+ | Module | Description |
193
+ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
194
+ | `scorecardHomeModule` | Registers Scorecard homepage widgets for the home plugin (`AggregatedCardWithDeprecatedMetricId`, `AggregatedCardWithDefaultAggregation`, `AggregatedCardWithJiraOpenIssues`, and `AggregatedCardWithGithubOpenPrs`). |
195
+ | `scorecardCatalogModule` | Registers the Scorecard entity tab with the catalog plugin. Add to your app's `features`. Which entities show the tab is configured via `app.extensions` (see step 3). |
196
+ | `scorecardTranslationsModule` | Registers Scorecard translations with the app. Add to your app's `features`. |
197
+
198
+ **Extensions**
199
+
200
+ - `api:scorecard` — Scorecard API (provided by the plugin; auto-discovered when the plugin is installed).
201
+ - `entity-content:catalog/entity-content-scorecard` — Scorecard tab on catalog entity pages. Configure with `allowedFilters` in `app.extensions` to limit by kind and optionally type.
202
+ - `home-page-widget:home/scorecard-deprecated-metric-id` — Homepage widget using deprecated metricId property (Jira open issues).
203
+ - `home-page-widget:home/scorecard-default-aggregation` — Homepage widget using default aggregation config (GitHub open PRs).
204
+ - `home-page-widget:home/scorecard-jira-open-issues` — Homepage widget showing Jira open blocking tickets.
205
+ - `home-page-widget:home/scorecard-github-open-prs` — Homepage widget showing GitHub open PRs.
206
+
207
+ #### Legacy app
208
+
209
+ 1. Install the Scorecard frontend plugin (see [Installation and usage](#installation-and-usage)) using `app-legacy`:
210
+
211
+ ```console
212
+ yarn workspace app-legacy add @red-hat-developer-hub/backstage-plugin-scorecard
213
+ ```
214
+
215
+ 2. Add the Scorecard tab to the entity overview in `packages/app-legacy/src/components/catalog/EntityPage.tsx` (or your legacy app's equivalent):
56
216
 
57
217
  ```tsx
58
218
  import { EntityScorecardContent } from '@red-hat-developer-hub/backstage-plugin-scorecard';
@@ -82,7 +242,6 @@ permission:
82
242
  <EntitySwitch.Case if={isComponentType('service')}>
83
243
  {serviceEntityPage}
84
244
  </EntitySwitch.Case>
85
-
86
245
  <EntitySwitch.Case if={isComponentType('website')}>
87
246
  {websiteEntityPage}
88
247
  </EntitySwitch.Case>
@@ -98,11 +257,103 @@ permission:
98
257
  );
99
258
  ```
100
259
 
260
+ 3. (Optional) Add Scorecard homepage cards to your home page:
261
+
262
+ ```tsx
263
+ import { ScorecardHomepageCard } from '@red-hat-developer-hub/backstage-plugin-scorecard';
264
+
265
+ // GitHub open PRs
266
+ <ScorecardHomepageCard metricId="github.open_prs" />
267
+
268
+ // Jira open issues
269
+ <ScorecardHomepageCard metricId="jira.open_issues" />
270
+ ```
271
+
272
+ 4. Ensure the frontend can reach the Scorecard backend by configuring discovery in `app-config.yaml` (see discovery snippet under [NFS](#nfs-new-frontend-system--app)).
273
+
274
+ 5. Start the legacy app (e.g. `yarn start:legacy`) and open the **Scorecard** tab on catalog entity pages.
275
+
276
+ ### Permission Framework Support
277
+
278
+ The Scorecard plugin has support for the permission framework.
279
+
280
+ - When [RBAC permission](https://github.com/backstage/community-plugins/tree/main/workspaces/rbac/plugins/rbac-backend#installation) framework is enabled, for non-admin users to access scorecard UI, the role associated with your user should have the following permission policies associated with it. Add the following in your permission policies configuration file named `rbac-policy.csv`:
281
+
282
+ ```CSV
283
+ p, role:default/team_a, scorecard.metric.read, read, allow
284
+
285
+ g, user:default/<your-user-name>, role:default/team_a
286
+ ```
287
+
288
+ You can specify the path to this configuration file in your application configuration:
289
+
290
+ ```yaml
291
+ permission:
292
+ enabled: true
293
+ rbac:
294
+ policies-csv-file: /some/path/rbac-policy.csv
295
+ policyFileReload: true
296
+ ```
297
+
298
+ **Note:** The backend also checks `catalog.entity.read` for each entity. Make sure your users/roles can read the catalog entities they want to view scorecards for.
299
+
101
300
  ### Accessing the Plugin
102
301
 
103
- 1. Open your Backstage application.
104
- 2. Navigate to the Entity overview page from catalog.
105
- 3. Explore and analyze scorecard metrics using the scorecards tab.
302
+ - **app (NFS):** Open your Backstage app, go to **Catalog**, open an entity. The **Scorecard** tab appears when the entity matches your `allowedFilters` in app-config (or for all entities if the extension config is omitted).
303
+ - **app-legacy:** Open your Backstage app, go to the entity overview from the catalog, and open the **Scorecard** tab to view and analyze scorecard metrics.
304
+
305
+ ### Homepage scorecard cards
306
+
307
+ The plugin exports **`ScorecardHomepageCard`** (see [`plugin.ts`](./src/plugin.ts)) for use on customizable home pages (for example **Dynamic Home Page** mount points such as `home.page/cards`).
308
+
309
+ #### Backend configuration
310
+
311
+ Define KPI ids and optional labels under **`scorecard.aggregationKPIs`** so each card can call **`GET /aggregations/<aggregationId>`** with a stable id. See [Scorecard backend README — Aggregation KPIs](../scorecard-backend/README.md#aggregation-kpis-homepage-and-get-aggregations). If you omit a KPI entry, use the **metric id** as `aggregationId` (default status-grouped aggregation).
312
+
313
+ #### Card props
314
+
315
+ The supported model is **a single `aggregationId` string** whose value is either:
316
+
317
+ - a **KPI key** from **`scorecard.aggregationKPIs`** in app-config (custom title, description, type, backing metric), or
318
+ - a **metric id** when you have no KPI row for that card (default **statusGrouped** aggregation and metric-defined metadata).
319
+
320
+ | Prop | Status | Description |
321
+ | ------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
322
+ | **`aggregationId`** | **Use this** | KPI id from **`scorecard.aggregationKPIs`** _or_ **metric id** for the default case. Sent to **`GET /aggregations/:aggregationId`**. |
323
+ | **`metricId`** | **Legacy** | Default aggregated card metadata: resolved as **`aggregationId ?? metricId`**. |
324
+
325
+ **Migrating**
326
+
327
+ - **Homepage `props`:** set **`aggregationId`** to your KPI key or metric id - drop **`metricId`** when your plugin version no longer requires it.
328
+ - **Custom HTTP clients:** replace **`GET .../metrics/<metricId>/catalog/aggregations`** with **`GET .../aggregations/<aggregationId>`** (same segment value when you used the metric id before). Deprecation **`Link`** headers point at the successor URL.
329
+ - **User-editable home cards:** if your **`settings.schema`** still exposes **`metricId`**, plan to rename or replace it with **`aggregationId`** using the same KPI vs metric-id rules once the frontend supports it.
330
+
331
+ Example (Dynamic Home Page–style mount point): register **`ScorecardHomepageCard`** and pass **`props.aggregationId`** (and **`metricId`** only if you still run an older card API):
332
+
333
+ ```tsx
334
+ import { ScorecardHomepageCard } from '@red-hat-developer-hub/backstage-plugin-scorecard';
335
+ import { ComponentType } from 'react';
336
+
337
+ // Inside your home page cards config:
338
+ {
339
+ Component: ScorecardHomepageCard as ComponentType,
340
+ config: {
341
+ id: 'scorecard-jira-open-issues',
342
+ title: 'Scorecard: Jira open issues',
343
+ layouts: { /* … */ },
344
+ props: {
345
+ aggregationId: 'openIssuesKpi',
346
+ // metricId: 'jira.open_issues', // legacy only; remove when only aggregationId is supported
347
+ },
348
+ },
349
+ },
350
+ ```
351
+
352
+ #### Default labels and translations
353
+
354
+ - The API returns **title** and **description** in **`metadata`** (from **`aggregationKPIs`** or from the metric definition).
355
+ - The homepage card applies **plugin translations** when keys exist for **`metric.<id>.title`** and **`metric.<id>.description`**, where **`<id>`** is the value passed into the translation hook (**`aggregationId ?? metricId`**). If no translation key matches, the UI shows the **metadata** strings from the API.
356
+ - **Custom `title` / `description` in `aggregationKPIs`** are returned as-is from the backend; add matching translation keys for **`metric.<yourKpiId>.*`** if you want those strings localized.
106
357
 
107
358
  ## Adding Translations
108
359
 
@@ -139,14 +390,16 @@ const scorecardTranslationDe = createTranslationMessages({
139
390
  });
140
391
  ```
141
392
 
142
- ### 3. Translation Key Format
393
+ ### 2. Translation Key Format
143
394
 
144
395
  Translation keys follow this pattern:
145
396
 
146
397
  - **Metric titles**: `metric.{metric-id}.title`
147
398
  - **Metric descriptions**: `metric.{metric-id}.description`
148
399
 
149
- ### 4. Fallback Behavior
400
+ Use the same pattern with a **KPI id** as `{metric-id}` when localizing **`aggregationKPIs`** titles (for example **`metric.openIssuesKpi.title`**).
401
+
402
+ ### 3. Fallback Behavior
150
403
 
151
404
  If a translation key is not found, the plugin will automatically fall back to:
152
405
 
@@ -0,0 +1,15 @@
1
+ import { ApiBlueprint, createApiFactory, discoveryApiRef, fetchApiRef } from '@backstage/frontend-plugin-api';
2
+ import { ScorecardApiClient, scorecardApiRef } from '../../api/index.esm.js';
3
+
4
+ const scorecardApi = ApiBlueprint.make({
5
+ params: (defineParams) => defineParams(
6
+ createApiFactory({
7
+ api: scorecardApiRef,
8
+ deps: { fetchApi: fetchApiRef, discoveryApi: discoveryApiRef },
9
+ factory: ({ fetchApi, discoveryApi }) => new ScorecardApiClient({ fetchApi, discoveryApi })
10
+ })
11
+ )
12
+ });
13
+
14
+ export { scorecardApi };
15
+ //# sourceMappingURL=api.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.esm.js","sources":["../../../src/alpha/extensions/api.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 ApiBlueprint,\n createApiFactory,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { ScorecardApiClient, scorecardApiRef } from '../../api';\n\n/** Scorecard API extension. */\nexport const scorecardApi = ApiBlueprint.make({\n params: defineParams =>\n defineParams(\n createApiFactory({\n api: scorecardApiRef,\n deps: { fetchApi: fetchApiRef, discoveryApi: discoveryApiRef },\n factory: ({ fetchApi, discoveryApi }) =>\n new ScorecardApiClient({ fetchApi, discoveryApi }),\n }),\n ),\n});\n"],"names":[],"mappings":";;;AAyBa,MAAA,YAAA,GAAe,aAAa,IAAK,CAAA;AAAA,EAC5C,QAAQ,CACN,YAAA,KAAA,YAAA;AAAA,IACE,gBAAiB,CAAA;AAAA,MACf,GAAK,EAAA,eAAA;AAAA,MACL,IAAM,EAAA,EAAE,QAAU,EAAA,WAAA,EAAa,cAAc,eAAgB,EAAA;AAAA,MAC7D,OAAA,EAAS,CAAC,EAAE,QAAU,EAAA,YAAA,EACpB,KAAA,IAAI,kBAAmB,CAAA,EAAE,QAAU,EAAA,YAAA,EAAc;AAAA,KACpD;AAAA;AAEP,CAAC;;;;"}
@@ -0,0 +1,42 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
3
+ import { rootRouteRef } from '../../routes.esm.js';
4
+
5
+ const scorecardEntityContent = EntityContentBlueprint.makeWithOverrides({
6
+ name: "entity-content-scorecard",
7
+ config: {
8
+ schema: {
9
+ // Allows flexible filtering: { kind: 'Component', type: 'service' }
10
+ // or just { type: 'service' } for all services.
11
+ allowedFilters: (schema) => schema.array(
12
+ schema.object({
13
+ kind: schema.string().optional(),
14
+ type: schema.string().optional()
15
+ })
16
+ ).optional()
17
+ }
18
+ },
19
+ factory(original, { config }) {
20
+ return original({
21
+ path: "/scorecard",
22
+ title: "Scorecard",
23
+ routeRef: rootRouteRef,
24
+ filter: (entity) => {
25
+ const filters = config.allowedFilters;
26
+ if (!filters || filters.length === 0) return true;
27
+ return filters.some((f) => {
28
+ const kindMatch = !f.kind || f.kind.toLowerCase() === entity.kind.toLowerCase();
29
+ const typeMatch = !f.type || f.type.toLowerCase() === entity.spec?.type?.toLowerCase();
30
+ return kindMatch && typeMatch;
31
+ });
32
+ },
33
+ loader: async () => {
34
+ const { EntityScorecardContent } = await import('../../components/Scorecard/index.esm.js');
35
+ return /* @__PURE__ */ jsx(EntityScorecardContent, {});
36
+ }
37
+ });
38
+ }
39
+ });
40
+
41
+ export { scorecardEntityContent };
42
+ //# sourceMappingURL=entityTab.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entityTab.esm.js","sources":["../../../src/alpha/extensions/entityTab.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 { Entity } from '@backstage/catalog-model';\nimport { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';\nimport { rootRouteRef } from '../../routes';\n\n/**\n * Extension for the Scorecard tab on Entity pages.\n * @alpha\n */\nexport const scorecardEntityContent = EntityContentBlueprint.makeWithOverrides({\n name: 'entity-content-scorecard',\n config: {\n schema: {\n // Allows flexible filtering: { kind: 'Component', type: 'service' }\n // or just { type: 'service' } for all services.\n allowedFilters: schema =>\n schema\n .array(\n schema.object({\n kind: schema.string().optional(),\n type: schema.string().optional(),\n }),\n )\n .optional(),\n },\n },\n factory(original, { config }) {\n return original({\n path: '/scorecard',\n title: 'Scorecard',\n routeRef: rootRouteRef,\n filter: (entity: Entity): boolean => {\n const filters = config.allowedFilters;\n\n if (!filters || filters.length === 0) return true;\n\n return filters.some(f => {\n const kindMatch =\n !f.kind || f.kind.toLowerCase() === entity.kind.toLowerCase();\n const typeMatch =\n !f.type ||\n f.type.toLowerCase() ===\n (entity.spec?.type as string)?.toLowerCase();\n\n return kindMatch && typeMatch;\n });\n },\n loader: async () => {\n const { EntityScorecardContent } = await import(\n '../../components/Scorecard'\n );\n return <EntityScorecardContent />;\n },\n });\n },\n});\n"],"names":[],"mappings":";;;;AAwBa,MAAA,sBAAA,GAAyB,uBAAuB,iBAAkB,CAAA;AAAA,EAC7E,IAAM,EAAA,0BAAA;AAAA,EACN,MAAQ,EAAA;AAAA,IACN,MAAQ,EAAA;AAAA;AAAA;AAAA,MAGN,cAAA,EAAgB,YACd,MACG,CAAA,KAAA;AAAA,QACC,OAAO,MAAO,CAAA;AAAA,UACZ,IAAM,EAAA,MAAA,CAAO,MAAO,EAAA,CAAE,QAAS,EAAA;AAAA,UAC/B,IAAM,EAAA,MAAA,CAAO,MAAO,EAAA,CAAE,QAAS;AAAA,SAChC;AAAA,QAEF,QAAS;AAAA;AAChB,GACF;AAAA,EACA,OAAQ,CAAA,QAAA,EAAU,EAAE,MAAA,EAAU,EAAA;AAC5B,IAAA,OAAO,QAAS,CAAA;AAAA,MACd,IAAM,EAAA,YAAA;AAAA,MACN,KAAO,EAAA,WAAA;AAAA,MACP,QAAU,EAAA,YAAA;AAAA,MACV,MAAA,EAAQ,CAAC,MAA4B,KAAA;AACnC,QAAA,MAAM,UAAU,MAAO,CAAA,cAAA;AAEvB,QAAA,IAAI,CAAC,OAAA,IAAW,OAAQ,CAAA,MAAA,KAAW,GAAU,OAAA,IAAA;AAE7C,QAAO,OAAA,OAAA,CAAQ,KAAK,CAAK,CAAA,KAAA;AACvB,UAAM,MAAA,SAAA,GACJ,CAAC,CAAA,CAAE,IAAQ,IAAA,CAAA,CAAE,KAAK,WAAY,EAAA,KAAM,MAAO,CAAA,IAAA,CAAK,WAAY,EAAA;AAC9D,UAAM,MAAA,SAAA,GACJ,CAAC,CAAA,CAAE,IACH,IAAA,CAAA,CAAE,IAAK,CAAA,WAAA,EACJ,KAAA,MAAA,CAAO,IAAM,EAAA,IAAA,EAAiB,WAAY,EAAA;AAE/C,UAAA,OAAO,SAAa,IAAA,SAAA;AAAA,SACrB,CAAA;AAAA,OACH;AAAA,MACA,QAAQ,YAAY;AAClB,QAAA,MAAM,EAAE,sBAAA,EAA2B,GAAA,MAAM,OACvC,yCACF,CAAA;AACA,QAAA,2BAAQ,sBAAuB,EAAA,EAAA,CAAA;AAAA;AACjC,KACD,CAAA;AAAA;AAEL,CAAC;;;;"}
@@ -0,0 +1,90 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { HomePageWidgetBlueprint } from '@backstage/plugin-home-react/alpha';
3
+ import { ScorecardHomepageCardWithProvider } from '../../components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js';
4
+
5
+ const defaultCardLayout = {
6
+ width: {
7
+ minColumns: 3,
8
+ maxColumns: 12,
9
+ defaultColumns: 4
10
+ },
11
+ height: {
12
+ minRows: 5,
13
+ maxRows: 12,
14
+ defaultRows: 6
15
+ }
16
+ };
17
+ function AggregatedCardWithDeprecatedMetricIdContent() {
18
+ return /* @__PURE__ */ jsx(ScorecardHomepageCardWithProvider, { metricId: "jira.open_issues" });
19
+ }
20
+ function AggregatedCardWithDefaultAggregationContent() {
21
+ return /* @__PURE__ */ jsx(ScorecardHomepageCardWithProvider, { aggregationId: "github.open_prs" });
22
+ }
23
+ function AggregatedCardWithJiraOpenIssuesContent() {
24
+ return /* @__PURE__ */ jsx(ScorecardHomepageCardWithProvider, { aggregationId: "openIssuesKpi" });
25
+ }
26
+ function AggregatedCardWithGithubOpenPrsContent() {
27
+ return /* @__PURE__ */ jsx(ScorecardHomepageCardWithProvider, { aggregationId: "openPrsKpi" });
28
+ }
29
+ function BorderlessHomeWidgetRenderer({ Content }) {
30
+ return /* @__PURE__ */ jsx(Content, {});
31
+ }
32
+ const aggregatedCardWithDeprecatedMetricIdWidget = HomePageWidgetBlueprint.make({
33
+ name: "scorecard-deprecated-metric-id",
34
+ params: {
35
+ name: "AggregatedCardWithDeprecatedMetricId",
36
+ title: "Scorecard: With deprecated metricId property (Jira)",
37
+ layout: defaultCardLayout,
38
+ componentProps: {
39
+ Renderer: BorderlessHomeWidgetRenderer
40
+ },
41
+ components: () => Promise.resolve({
42
+ Content: AggregatedCardWithDeprecatedMetricIdContent
43
+ })
44
+ }
45
+ });
46
+ const aggregatedCardWithDefaultAggregationWidget = HomePageWidgetBlueprint.make({
47
+ name: "scorecard-default-aggregation",
48
+ params: {
49
+ name: "AggregatedCardWithDefaultAggregation",
50
+ title: "Scorecard: With default aggregation config (GitHub)",
51
+ layout: defaultCardLayout,
52
+ componentProps: {
53
+ Renderer: BorderlessHomeWidgetRenderer
54
+ },
55
+ components: () => Promise.resolve({
56
+ Content: AggregatedCardWithDefaultAggregationContent
57
+ })
58
+ }
59
+ });
60
+ const aggregatedCardWithJiraOpenIssuesWidget = HomePageWidgetBlueprint.make({
61
+ name: "scorecard-jira-open-issues",
62
+ params: {
63
+ name: "AggregatedCardWithJiraOpenIssues",
64
+ title: "Scorecard: Jira open blocking tickets",
65
+ layout: defaultCardLayout,
66
+ componentProps: {
67
+ Renderer: BorderlessHomeWidgetRenderer
68
+ },
69
+ components: () => Promise.resolve({
70
+ Content: AggregatedCardWithJiraOpenIssuesContent
71
+ })
72
+ }
73
+ });
74
+ const aggregatedCardWithGithubOpenPrsWidget = HomePageWidgetBlueprint.make({
75
+ name: "scorecard-github-open-prs",
76
+ params: {
77
+ name: "AggregatedCardWithGithubOpenPrs",
78
+ title: "Scorecard: GitHub open PRs",
79
+ layout: defaultCardLayout,
80
+ componentProps: {
81
+ Renderer: BorderlessHomeWidgetRenderer
82
+ },
83
+ components: () => Promise.resolve({
84
+ Content: AggregatedCardWithGithubOpenPrsContent
85
+ })
86
+ }
87
+ });
88
+
89
+ export { aggregatedCardWithDefaultAggregationWidget, aggregatedCardWithDeprecatedMetricIdWidget, aggregatedCardWithGithubOpenPrsWidget, aggregatedCardWithJiraOpenIssuesWidget };
90
+ //# sourceMappingURL=homePageCards.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"homePageCards.esm.js","sources":["../../../src/alpha/extensions/homePageCards.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 { HomePageWidgetBlueprint } from '@backstage/plugin-home-react/alpha';\nimport type { RendererProps } from '@backstage/plugin-home-react';\nimport { ScorecardHomepageCardWithProvider } from '../../components/ScorecardHomepageSection';\n\nconst defaultCardLayout = {\n width: {\n minColumns: 3,\n maxColumns: 12,\n defaultColumns: 4,\n },\n height: {\n minRows: 5,\n maxRows: 12,\n defaultRows: 6,\n },\n} as const;\n\nfunction AggregatedCardWithDeprecatedMetricIdContent() {\n return <ScorecardHomepageCardWithProvider metricId=\"jira.open_issues\" />;\n}\n\nfunction AggregatedCardWithDefaultAggregationContent() {\n return <ScorecardHomepageCardWithProvider aggregationId=\"github.open_prs\" />;\n}\n\nfunction AggregatedCardWithJiraOpenIssuesContent() {\n return <ScorecardHomepageCardWithProvider aggregationId=\"openIssuesKpi\" />;\n}\n\nfunction AggregatedCardWithGithubOpenPrsContent() {\n return <ScorecardHomepageCardWithProvider aggregationId=\"openPrsKpi\" />;\n}\n\nfunction BorderlessHomeWidgetRenderer({ Content }: RendererProps) {\n return <Content />;\n}\n\n/**\n * NFS widget: AggregatedCardWithDeprecatedMetricId.\n * @alpha\n */\nexport const aggregatedCardWithDeprecatedMetricIdWidget =\n HomePageWidgetBlueprint.make({\n name: 'scorecard-deprecated-metric-id',\n params: {\n name: 'AggregatedCardWithDeprecatedMetricId',\n title: 'Scorecard: With deprecated metricId property (Jira)',\n layout: defaultCardLayout,\n componentProps: {\n Renderer: BorderlessHomeWidgetRenderer,\n },\n components: () =>\n Promise.resolve({\n Content: AggregatedCardWithDeprecatedMetricIdContent,\n }),\n },\n });\n\n/**\n * NFS widget: AggregatedCardWithDefaultAggregation.\n * @alpha\n */\nexport const aggregatedCardWithDefaultAggregationWidget =\n HomePageWidgetBlueprint.make({\n name: 'scorecard-default-aggregation',\n params: {\n name: 'AggregatedCardWithDefaultAggregation',\n title: 'Scorecard: With default aggregation config (GitHub)',\n layout: defaultCardLayout,\n componentProps: {\n Renderer: BorderlessHomeWidgetRenderer,\n },\n components: () =>\n Promise.resolve({\n Content: AggregatedCardWithDefaultAggregationContent,\n }),\n },\n });\n\n/**\n * NFS widget: AggregatedCardWithJiraOpenIssues.\n * @alpha\n */\nexport const aggregatedCardWithJiraOpenIssuesWidget =\n HomePageWidgetBlueprint.make({\n name: 'scorecard-jira-open-issues',\n params: {\n name: 'AggregatedCardWithJiraOpenIssues',\n title: 'Scorecard: Jira open blocking tickets',\n layout: defaultCardLayout,\n componentProps: {\n Renderer: BorderlessHomeWidgetRenderer,\n },\n components: () =>\n Promise.resolve({\n Content: AggregatedCardWithJiraOpenIssuesContent,\n }),\n },\n });\n\n/**\n * NFS widget: AggregatedCardWithGithubOpenPrs.\n * @alpha\n */\nexport const aggregatedCardWithGithubOpenPrsWidget =\n HomePageWidgetBlueprint.make({\n name: 'scorecard-github-open-prs',\n params: {\n name: 'AggregatedCardWithGithubOpenPrs',\n title: 'Scorecard: GitHub open PRs',\n layout: defaultCardLayout,\n componentProps: {\n Renderer: BorderlessHomeWidgetRenderer,\n },\n components: () =>\n Promise.resolve({\n Content: AggregatedCardWithGithubOpenPrsContent,\n }),\n },\n });\n"],"names":[],"mappings":";;;;AAoBA,MAAM,iBAAoB,GAAA;AAAA,EACxB,KAAO,EAAA;AAAA,IACL,UAAY,EAAA,CAAA;AAAA,IACZ,UAAY,EAAA,EAAA;AAAA,IACZ,cAAgB,EAAA;AAAA,GAClB;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,OAAS,EAAA,CAAA;AAAA,IACT,OAAS,EAAA,EAAA;AAAA,IACT,WAAa,EAAA;AAAA;AAEjB,CAAA;AAEA,SAAS,2CAA8C,GAAA;AACrD,EAAO,uBAAA,GAAA,CAAC,iCAAkC,EAAA,EAAA,QAAA,EAAS,kBAAmB,EAAA,CAAA;AACxE;AAEA,SAAS,2CAA8C,GAAA;AACrD,EAAO,uBAAA,GAAA,CAAC,iCAAkC,EAAA,EAAA,aAAA,EAAc,iBAAkB,EAAA,CAAA;AAC5E;AAEA,SAAS,uCAA0C,GAAA;AACjD,EAAO,uBAAA,GAAA,CAAC,iCAAkC,EAAA,EAAA,aAAA,EAAc,eAAgB,EAAA,CAAA;AAC1E;AAEA,SAAS,sCAAyC,GAAA;AAChD,EAAO,uBAAA,GAAA,CAAC,iCAAkC,EAAA,EAAA,aAAA,EAAc,YAAa,EAAA,CAAA;AACvE;AAEA,SAAS,4BAAA,CAA6B,EAAE,OAAA,EAA0B,EAAA;AAChE,EAAA,2BAAQ,OAAQ,EAAA,EAAA,CAAA;AAClB;AAMa,MAAA,0CAAA,GACX,wBAAwB,IAAK,CAAA;AAAA,EAC3B,IAAM,EAAA,gCAAA;AAAA,EACN,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,sCAAA;AAAA,IACN,KAAO,EAAA,qDAAA;AAAA,IACP,MAAQ,EAAA,iBAAA;AAAA,IACR,cAAgB,EAAA;AAAA,MACd,QAAU,EAAA;AAAA,KACZ;AAAA,IACA,UAAA,EAAY,MACV,OAAA,CAAQ,OAAQ,CAAA;AAAA,MACd,OAAS,EAAA;AAAA,KACV;AAAA;AAEP,CAAC;AAMU,MAAA,0CAAA,GACX,wBAAwB,IAAK,CAAA;AAAA,EAC3B,IAAM,EAAA,+BAAA;AAAA,EACN,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,sCAAA;AAAA,IACN,KAAO,EAAA,qDAAA;AAAA,IACP,MAAQ,EAAA,iBAAA;AAAA,IACR,cAAgB,EAAA;AAAA,MACd,QAAU,EAAA;AAAA,KACZ;AAAA,IACA,UAAA,EAAY,MACV,OAAA,CAAQ,OAAQ,CAAA;AAAA,MACd,OAAS,EAAA;AAAA,KACV;AAAA;AAEP,CAAC;AAMU,MAAA,sCAAA,GACX,wBAAwB,IAAK,CAAA;AAAA,EAC3B,IAAM,EAAA,4BAAA;AAAA,EACN,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,kCAAA;AAAA,IACN,KAAO,EAAA,uCAAA;AAAA,IACP,MAAQ,EAAA,iBAAA;AAAA,IACR,cAAgB,EAAA;AAAA,MACd,QAAU,EAAA;AAAA,KACZ;AAAA,IACA,UAAA,EAAY,MACV,OAAA,CAAQ,OAAQ,CAAA;AAAA,MACd,OAAS,EAAA;AAAA,KACV;AAAA;AAEP,CAAC;AAMU,MAAA,qCAAA,GACX,wBAAwB,IAAK,CAAA;AAAA,EAC3B,IAAM,EAAA,2BAAA;AAAA,EACN,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,iCAAA;AAAA,IACN,KAAO,EAAA,4BAAA;AAAA,IACP,MAAQ,EAAA,iBAAA;AAAA,IACR,cAAgB,EAAA;AAAA,MACd,QAAU,EAAA;AAAA,KACZ;AAAA,IACA,UAAA,EAAY,MACV,OAAA,CAAQ,OAAQ,CAAA;AAAA,MACd,OAAS,EAAA;AAAA,KACV;AAAA;AAEP,CAAC;;;;"}
@@ -0,0 +1,14 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { PageBlueprint } from '@backstage/frontend-plugin-api';
3
+ import { scorecardDrillDownRouteRef } from '../../routes.esm.js';
4
+
5
+ const scorecardPage = PageBlueprint.make({
6
+ params: {
7
+ path: "/scorecard/aggregations/:aggregationId/metrics/:metricId",
8
+ routeRef: scorecardDrillDownRouteRef,
9
+ loader: () => import('../../pages/ScorecardPage.esm.js').then((m) => /* @__PURE__ */ jsx(m.ScorecardPageWithProvider, {}))
10
+ }
11
+ });
12
+
13
+ export { scorecardPage };
14
+ //# sourceMappingURL=scorecardPage.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorecardPage.esm.js","sources":["../../../src/alpha/extensions/scorecardPage.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 { PageBlueprint } from '@backstage/frontend-plugin-api';\nimport { scorecardDrillDownRouteRef } from '../../routes';\n\n/**\n * NFS page extension for the Scorecard drill-down page.\n * @alpha\n */\nexport const scorecardPage = PageBlueprint.make({\n params: {\n path: '/scorecard/aggregations/:aggregationId/metrics/:metricId',\n routeRef: scorecardDrillDownRouteRef,\n loader: () =>\n import('../../pages/ScorecardPage').then(m => (\n <m.ScorecardPageWithProvider />\n )),\n },\n});\n"],"names":[],"mappings":";;;;AAuBa,MAAA,aAAA,GAAgB,cAAc,IAAK,CAAA;AAAA,EAC9C,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,0DAAA;AAAA,IACN,QAAU,EAAA,0BAAA;AAAA,IACV,MAAA,EAAQ,MACN,OAAO,kCAA2B,CAAA,CAAE,IAAK,CAAA,CAAA,CAAA,qBACtC,GAAA,CAAA,CAAA,CAAE,yBAAF,EAAA,EAA4B,CAC9B;AAAA;AAEP,CAAC;;;;"}