@red-hat-developer-hub/backstage-plugin-scorecard 2.3.5 → 2.5.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 (126) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +256 -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/index.esm.js +119 -14
  15. package/dist/api/index.esm.js.map +1 -1
  16. package/dist/components/Common/CardLoading.esm.js +20 -0
  17. package/dist/components/Common/CardLoading.esm.js.map +1 -0
  18. package/dist/components/Common/CardWrapper.esm.js +25 -18
  19. package/dist/components/Common/CardWrapper.esm.js.map +1 -1
  20. package/dist/components/Common/ErrorTooltip.esm.js +25 -0
  21. package/dist/components/Common/ErrorTooltip.esm.js.map +1 -0
  22. package/dist/components/Common/NoScorecardsState.esm.js +3 -1
  23. package/dist/components/Common/NoScorecardsState.esm.js.map +1 -1
  24. package/dist/components/Common/NotFoundState.esm.js +152 -0
  25. package/dist/components/Common/NotFoundState.esm.js.map +1 -0
  26. package/dist/components/Common/PermissionRequiredState.esm.js +3 -1
  27. package/dist/components/Common/PermissionRequiredState.esm.js.map +1 -1
  28. package/dist/components/Scorecard/CustomLegend.esm.js +12 -5
  29. package/dist/components/Scorecard/CustomLegend.esm.js.map +1 -1
  30. package/dist/components/Scorecard/EntityScorecardContent.esm.js +11 -17
  31. package/dist/components/Scorecard/EntityScorecardContent.esm.js.map +1 -1
  32. package/dist/components/Scorecard/Scorecard.esm.js +158 -73
  33. package/dist/components/Scorecard/Scorecard.esm.js.map +1 -1
  34. package/dist/components/ScorecardHomepageSection/CustomLegend.esm.js +7 -1
  35. package/dist/components/ScorecardHomepageSection/CustomLegend.esm.js.map +1 -1
  36. package/dist/components/ScorecardHomepageSection/CustomTooltip.esm.js.map +1 -1
  37. package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js +52 -56
  38. package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js.map +1 -1
  39. package/dist/components/ScorecardHomepageSection/ErrorStatePanel.esm.js +51 -22
  40. package/dist/components/ScorecardHomepageSection/ErrorStatePanel.esm.js.map +1 -1
  41. package/dist/components/ScorecardHomepageSection/ResponsivePieChart.esm.js +27 -1
  42. package/dist/components/ScorecardHomepageSection/ResponsivePieChart.esm.js.map +1 -1
  43. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js +43 -30
  44. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js.map +1 -1
  45. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCardComponent.esm.js +74 -7
  46. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCardComponent.esm.js.map +1 -1
  47. package/dist/components/ScorecardIcon/ScorecardIcon.esm.js +30 -0
  48. package/dist/components/ScorecardIcon/ScorecardIcon.esm.js.map +1 -0
  49. package/dist/components/ScorecardPage/EntitiesTable/EntitiesRow.esm.js +47 -0
  50. package/dist/components/ScorecardPage/EntitiesTable/EntitiesRow.esm.js.map +1 -0
  51. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTable.esm.js +144 -0
  52. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTable.esm.js.map +1 -0
  53. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableFooter.esm.js +111 -0
  54. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableFooter.esm.js.map +1 -0
  55. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableHeader.esm.js +31 -0
  56. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableHeader.esm.js.map +1 -0
  57. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTablePagination.esm.js +76 -0
  58. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTablePagination.esm.js.map +1 -0
  59. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableStateRow.esm.js +36 -0
  60. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableStateRow.esm.js.map +1 -0
  61. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableWrapper.esm.js +58 -0
  62. package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableWrapper.esm.js.map +1 -0
  63. package/dist/components/ScorecardPage/EntitiesTable/cells/EntityNameCell.esm.js +36 -0
  64. package/dist/components/ScorecardPage/EntitiesTable/cells/EntityNameCell.esm.js.map +1 -0
  65. package/dist/components/ScorecardPage/EntitiesTable/cells/MetricStatusCell.esm.js +31 -0
  66. package/dist/components/ScorecardPage/EntitiesTable/cells/MetricStatusCell.esm.js.map +1 -0
  67. package/dist/components/ScorecardPage/EntitiesTable/cells/OwnerCell.esm.js +35 -0
  68. package/dist/components/ScorecardPage/EntitiesTable/cells/OwnerCell.esm.js.map +1 -0
  69. package/dist/components/ScorecardPage/ScorecardPage.esm.js +89 -0
  70. package/dist/components/ScorecardPage/ScorecardPage.esm.js.map +1 -0
  71. package/dist/components/ScorecardPage/ScorecardPageHeader.esm.js +9 -0
  72. package/dist/components/ScorecardPage/ScorecardPageHeader.esm.js.map +1 -0
  73. package/dist/hooks/useAggregatedScorecard.esm.js +15 -15
  74. package/dist/hooks/useAggregatedScorecard.esm.js.map +1 -1
  75. package/dist/hooks/useAggregatedScorecardEntities.esm.js +63 -0
  76. package/dist/hooks/useAggregatedScorecardEntities.esm.js.map +1 -0
  77. package/dist/hooks/useAggregationMetadata.esm.js +42 -0
  78. package/dist/hooks/useAggregationMetadata.esm.js.map +1 -0
  79. package/dist/hooks/useEntityMetadataMap.esm.js +87 -0
  80. package/dist/hooks/useEntityMetadataMap.esm.js.map +1 -0
  81. package/dist/hooks/useLanguage.esm.js +7 -0
  82. package/dist/hooks/useLanguage.esm.js.map +1 -0
  83. package/dist/hooks/useMetric.esm.js +42 -0
  84. package/dist/hooks/useMetric.esm.js.map +1 -0
  85. package/dist/hooks/useMetricDisplayLabels.esm.js +22 -0
  86. package/dist/hooks/useMetricDisplayLabels.esm.js.map +1 -0
  87. package/dist/hooks/useOwnershipEntityRefs.esm.js +16 -0
  88. package/dist/hooks/useOwnershipEntityRefs.esm.js.map +1 -0
  89. package/dist/hooks/useScorecards.esm.js +14 -7
  90. package/dist/hooks/useScorecards.esm.js.map +1 -1
  91. package/dist/images/not-found.svg +9 -0
  92. package/dist/index.d.ts +16 -3
  93. package/dist/index.esm.js +6 -1
  94. package/dist/index.esm.js.map +1 -1
  95. package/dist/pages/ScorecardPage.esm.js +2 -0
  96. package/dist/pages/ScorecardPage.esm.js.map +1 -0
  97. package/dist/plugin.esm.js +8 -1
  98. package/dist/plugin.esm.js.map +1 -1
  99. package/dist/routes.esm.js +5 -1
  100. package/dist/routes.esm.js.map +1 -1
  101. package/dist/translations/de.esm.js +48 -18
  102. package/dist/translations/de.esm.js.map +1 -1
  103. package/dist/translations/es.esm.js +45 -15
  104. package/dist/translations/es.esm.js.map +1 -1
  105. package/dist/translations/fr.esm.js +36 -1
  106. package/dist/translations/fr.esm.js.map +1 -1
  107. package/dist/translations/it.esm.js +37 -1
  108. package/dist/translations/it.esm.js.map +1 -1
  109. package/dist/translations/ja.esm.js +37 -1
  110. package/dist/translations/ja.esm.js.map +1 -1
  111. package/dist/translations/ref.esm.js +44 -2
  112. package/dist/translations/ref.esm.js.map +1 -1
  113. package/dist/types/index.d-N3BD4rEg.d.ts +75 -0
  114. package/dist/utils/chartLabelUtils.esm.js +23 -0
  115. package/dist/utils/chartLabelUtils.esm.js.map +1 -0
  116. package/dist/utils/constants.esm.js +42 -0
  117. package/dist/utils/constants.esm.js.map +1 -0
  118. package/dist/utils/entityTableUtils.esm.js +49 -0
  119. package/dist/utils/entityTableUtils.esm.js.map +1 -0
  120. package/dist/utils/statusUtils.esm.js +40 -0
  121. package/dist/utils/statusUtils.esm.js.map +1 -0
  122. package/dist/utils/thresholdUtils.esm.js +37 -0
  123. package/dist/utils/thresholdUtils.esm.js.map +1 -0
  124. package/package.json +34 -15
  125. package/dist/utils/utils.esm.js +0 -31
  126. package/dist/utils/utils.esm.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,59 @@
1
1
  # @red-hat-developer-hub/backstage-plugin-scorecard
2
2
 
3
+ ## 2.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d706601: Backstage version bump to v1.49.3
8
+ - 55226c2: Introduces custom threshold rule icons that can be configured in `app-config.yaml`.
9
+ - f13f583: Adding scorecardHomepage and metric page extension, also added e2e support in nfs
10
+ - 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.
11
+ - 243ad0a: Aggregated scorecards now use **aggregation IDs** and dedicated HTTP routes. The old catalog-aggregations URL still works but is **deprecated** (not removed).
12
+
13
+ **Backend (`@red-hat-developer-hub/backstage-plugin-scorecard-backend`)**
14
+
15
+ - **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.
16
+ - **Added:** `GET /aggregations/:aggregationId` for aggregated results using configured aggregation.
17
+ - **Added:** `GET /aggregations/:aggregationId/metadata` for KPI titles, descriptions, and aggregation metadata consumed by the UI.
18
+
19
+ **Common (`@red-hat-developer-hub/backstage-plugin-scorecard-common`)**
20
+
21
+ - Types and constants aligned with the aggregation config and new API shapes.
22
+
23
+ **Frontend (`@red-hat-developer-hub/backstage-plugin-scorecard`)**
24
+
25
+ - 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.
26
+
27
+ **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).
28
+
29
+ - 99aa8ff: Added support for the New Frontend System (NFS), including an alpha export for NFS apps and a new `app-next` package.
30
+
31
+ ### Patch Changes
32
+
33
+ - 6bd7c38: Enable sorting for all other columns in entities table
34
+ - ff005a3: add translation for the scorecard entities table status column
35
+ - afd7a1e: Update translations for Scorecard.
36
+ - 2667f70: Fix scorecard entity table column header Metric to Status
37
+ - Updated dependencies [d706601]
38
+ - Updated dependencies [55226c2]
39
+ - Updated dependencies [243ad0a]
40
+ - Updated dependencies [c83b206]
41
+ - @red-hat-developer-hub/backstage-plugin-scorecard-common@2.5.0
42
+
43
+ ## 2.4.0
44
+
45
+ ### Minor Changes
46
+
47
+ - 7062658: Introduces custom threshold rule keys and colors that can be configured in `app-config.yaml`.
48
+
49
+ ### Patch Changes
50
+
51
+ - 10aabb3: Fix tooltip display and error title clipping for some languages
52
+ - f6d5102: Translation updated for German and Spanish
53
+ - 34fc6c4: Fix Scorecard translations not working in cluster
54
+ - Updated dependencies [7062658]
55
+ - @red-hat-developer-hub/backstage-plugin-scorecard-common@2.4.0
56
+
3
57
  ## 2.3.5
4
58
 
5
59
  ### Patch 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,174 @@ 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
+ ScorecardJiraHomepage:
140
+ priority: 240
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
+ ScorecardGithubHomepage:
149
+ priority: 250
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
+ ```
158
+
159
+ The home module contributes two widgets:
160
+
161
+ - `ScorecardGithubHomepage` (title: **Scorecard: GitHub open PRs**)
162
+ - `ScorecardJiraHomepage` (title: **Scorecard: Jira open blocking tickets**)
163
+
164
+ These widgets render the same `ScorecardHomepageCard` component used in legacy apps, preconfigured for `github.open_prs` and `jira.open_issues`.
165
+
166
+ ##### Modules and extensions (NFS)
167
+
168
+ The following modules and extensions are available from `@red-hat-developer-hub/backstage-plugin-scorecard/alpha` for NFS apps:
54
169
 
55
- 1. Add the Scorecard page to you Entity overview page by modifying `packages/app/src/components/catalog/EntityPage.tsx`:
170
+ **Modules**
171
+
172
+ | Module | Description |
173
+ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
174
+ | `scorecardHomeModule` | Registers Scorecard homepage widgets for the home plugin (`ScorecardGithubHomepage` and `ScorecardJiraHomepage`). |
175
+ | `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). |
176
+ | `scorecardTranslationsModule` | Registers Scorecard translations with the app. Add to your app's `features`. |
177
+
178
+ **Extensions**
179
+
180
+ - `api:scorecard` — Scorecard API (provided by the plugin; auto-discovered when the plugin is installed).
181
+ - `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.
182
+ - `home-page-widget:home/scorecard-github-homepage` — Homepage widget showing GitHub open PR metric.
183
+ - `home-page-widget:home/scorecard-jira-homepage` — Homepage widget showing Jira open issues metric.
184
+
185
+ #### Legacy app
186
+
187
+ 1. Install the Scorecard frontend plugin (see [Installation and usage](#installation-and-usage)) using `app-legacy`:
188
+
189
+ ```console
190
+ yarn workspace app-legacy add @red-hat-developer-hub/backstage-plugin-scorecard
191
+ ```
192
+
193
+ 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
194
 
57
195
  ```tsx
58
196
  import { EntityScorecardContent } from '@red-hat-developer-hub/backstage-plugin-scorecard';
@@ -82,7 +220,6 @@ permission:
82
220
  <EntitySwitch.Case if={isComponentType('service')}>
83
221
  {serviceEntityPage}
84
222
  </EntitySwitch.Case>
85
-
86
223
  <EntitySwitch.Case if={isComponentType('website')}>
87
224
  {websiteEntityPage}
88
225
  </EntitySwitch.Case>
@@ -98,11 +235,103 @@ permission:
98
235
  );
99
236
  ```
100
237
 
238
+ 3. (Optional) Add Scorecard homepage cards to your home page:
239
+
240
+ ```tsx
241
+ import { ScorecardHomepageCard } from '@red-hat-developer-hub/backstage-plugin-scorecard';
242
+
243
+ // GitHub open PRs
244
+ <ScorecardHomepageCard metricId="github.open_prs" />
245
+
246
+ // Jira open issues
247
+ <ScorecardHomepageCard metricId="jira.open_issues" />
248
+ ```
249
+
250
+ 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)).
251
+
252
+ 5. Start the legacy app (e.g. `yarn start:legacy`) and open the **Scorecard** tab on catalog entity pages.
253
+
254
+ ### Permission Framework Support
255
+
256
+ The Scorecard plugin has support for the permission framework.
257
+
258
+ - 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`:
259
+
260
+ ```CSV
261
+ p, role:default/team_a, scorecard.metric.read, read, allow
262
+
263
+ g, user:default/<your-user-name>, role:default/team_a
264
+ ```
265
+
266
+ You can specify the path to this configuration file in your application configuration:
267
+
268
+ ```yaml
269
+ permission:
270
+ enabled: true
271
+ rbac:
272
+ policies-csv-file: /some/path/rbac-policy.csv
273
+ policyFileReload: true
274
+ ```
275
+
276
+ **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.
277
+
101
278
  ### Accessing the Plugin
102
279
 
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.
280
+ - **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).
281
+ - **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.
282
+
283
+ ### Homepage scorecard cards
284
+
285
+ 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`).
286
+
287
+ #### Backend configuration
288
+
289
+ 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).
290
+
291
+ #### Card props
292
+
293
+ The supported model is **a single `aggregationId` string** whose value is either:
294
+
295
+ - a **KPI key** from **`scorecard.aggregationKPIs`** in app-config (custom title, description, type, backing metric), or
296
+ - a **metric id** when you have no KPI row for that card (default **statusGrouped** aggregation and metric-defined metadata).
297
+
298
+ | Prop | Status | Description |
299
+ | ------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
300
+ | **`aggregationId`** | **Use this** | KPI id from **`scorecard.aggregationKPIs`** _or_ **metric id** for the default case. Sent to **`GET /aggregations/:aggregationId`**. |
301
+ | **`metricId`** | **Legacy** | Default aggregated card metadata: resolved as **`aggregationId ?? metricId`**. |
302
+
303
+ **Migrating**
304
+
305
+ - **Homepage `props`:** set **`aggregationId`** to your KPI key or metric id - drop **`metricId`** when your plugin version no longer requires it.
306
+ - **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.
307
+ - **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.
308
+
309
+ Example (Dynamic Home Page–style mount point): register **`ScorecardHomepageCard`** and pass **`props.aggregationId`** (and **`metricId`** only if you still run an older card API):
310
+
311
+ ```tsx
312
+ import { ScorecardHomepageCard } from '@red-hat-developer-hub/backstage-plugin-scorecard';
313
+ import { ComponentType } from 'react';
314
+
315
+ // Inside your home page cards config:
316
+ {
317
+ Component: ScorecardHomepageCard as ComponentType,
318
+ config: {
319
+ id: 'scorecard-jira-open-issues',
320
+ title: 'Scorecard: Jira open issues',
321
+ layouts: { /* … */ },
322
+ props: {
323
+ aggregationId: 'openIssuesKpi',
324
+ // metricId: 'jira.open_issues', // legacy only; remove when only aggregationId is supported
325
+ },
326
+ },
327
+ },
328
+ ```
329
+
330
+ #### Default labels and translations
331
+
332
+ - The API returns **title** and **description** in **`metadata`** (from **`aggregationKPIs`** or from the metric definition).
333
+ - 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.
334
+ - **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
335
 
107
336
  ## Adding Translations
108
337
 
@@ -139,14 +368,16 @@ const scorecardTranslationDe = createTranslationMessages({
139
368
  });
140
369
  ```
141
370
 
142
- ### 3. Translation Key Format
371
+ ### 2. Translation Key Format
143
372
 
144
373
  Translation keys follow this pattern:
145
374
 
146
375
  - **Metric titles**: `metric.{metric-id}.title`
147
376
  - **Metric descriptions**: `metric.{metric-id}.description`
148
377
 
149
- ### 4. Fallback Behavior
378
+ Use the same pattern with a **KPI id** as `{metric-id}` when localizing **`aggregationKPIs`** titles (for example **`metric.openIssuesKpi.title`**).
379
+
380
+ ### 3. Fallback Behavior
150
381
 
151
382
  If a translation key is not found, the plugin will automatically fall back to:
152
383
 
@@ -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 { ScorecardHomepageCard } 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(ScorecardHomepageCard, { metricId: "jira.open_issues" });
19
+ }
20
+ function AggregatedCardWithDefaultAggregationContent() {
21
+ return /* @__PURE__ */ jsx(ScorecardHomepageCard, { aggregationId: "github.open_prs" });
22
+ }
23
+ function AggregatedCardWithJiraOpenIssuesContent() {
24
+ return /* @__PURE__ */ jsx(ScorecardHomepageCard, { aggregationId: "openIssuesKpi" });
25
+ }
26
+ function AggregatedCardWithGithubOpenPrsContent() {
27
+ return /* @__PURE__ */ jsx(ScorecardHomepageCard, { 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 { ScorecardHomepageCard } 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 <ScorecardHomepageCard metricId=\"jira.open_issues\" />;\n}\n\nfunction AggregatedCardWithDefaultAggregationContent() {\n return <ScorecardHomepageCard aggregationId=\"github.open_prs\" />;\n}\n\nfunction AggregatedCardWithJiraOpenIssuesContent() {\n return <ScorecardHomepageCard aggregationId=\"openIssuesKpi\" />;\n}\n\nfunction AggregatedCardWithGithubOpenPrsContent() {\n return <ScorecardHomepageCard 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,qBAAsB,EAAA,EAAA,QAAA,EAAS,kBAAmB,EAAA,CAAA;AAC5D;AAEA,SAAS,2CAA8C,GAAA;AACrD,EAAO,uBAAA,GAAA,CAAC,qBAAsB,EAAA,EAAA,aAAA,EAAc,iBAAkB,EAAA,CAAA;AAChE;AAEA,SAAS,uCAA0C,GAAA;AACjD,EAAO,uBAAA,GAAA,CAAC,qBAAsB,EAAA,EAAA,aAAA,EAAc,eAAgB,EAAA,CAAA;AAC9D;AAEA,SAAS,sCAAyC,GAAA;AAChD,EAAO,uBAAA,GAAA,CAAC,qBAAsB,EAAA,EAAA,aAAA,EAAc,YAAa,EAAA,CAAA;AAC3D;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.ScorecardPage, {}))
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 => <m.ScorecardPage />),\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,qBAAM,GAAA,CAAA,CAAA,CAAE,aAAF,EAAA,EAAgB,CAAE;AAAA;AAEvE,CAAC;;;;"}