@red-hat-developer-hub/backstage-plugin-scorecard 2.4.0 → 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.
- package/CHANGELOG.md +40 -0
- package/README.md +256 -25
- package/dist/alpha/extensions/api.esm.js +15 -0
- package/dist/alpha/extensions/api.esm.js.map +1 -0
- package/dist/alpha/extensions/entityTab.esm.js +42 -0
- package/dist/alpha/extensions/entityTab.esm.js.map +1 -0
- package/dist/alpha/extensions/homePageCards.esm.js +90 -0
- package/dist/alpha/extensions/homePageCards.esm.js.map +1 -0
- package/dist/alpha/extensions/scorecardPage.esm.js +14 -0
- package/dist/alpha/extensions/scorecardPage.esm.js.map +1 -0
- package/dist/alpha.d.ts +75 -37
- package/dist/alpha.esm.js +41 -1
- package/dist/alpha.esm.js.map +1 -1
- package/dist/api/index.esm.js +119 -14
- package/dist/api/index.esm.js.map +1 -1
- package/dist/components/Common/CardLoading.esm.js +20 -0
- package/dist/components/Common/CardLoading.esm.js.map +1 -0
- package/dist/components/Common/CardWrapper.esm.js +25 -18
- package/dist/components/Common/CardWrapper.esm.js.map +1 -1
- package/dist/components/Common/ErrorTooltip.esm.js +2 -2
- package/dist/components/Common/ErrorTooltip.esm.js.map +1 -1
- package/dist/components/Common/NoScorecardsState.esm.js +3 -1
- package/dist/components/Common/NoScorecardsState.esm.js.map +1 -1
- package/dist/components/Common/NotFoundState.esm.js +152 -0
- package/dist/components/Common/NotFoundState.esm.js.map +1 -0
- package/dist/components/Common/PermissionRequiredState.esm.js +3 -1
- package/dist/components/Common/PermissionRequiredState.esm.js.map +1 -1
- package/dist/components/Scorecard/CustomLegend.esm.js +3 -4
- package/dist/components/Scorecard/CustomLegend.esm.js.map +1 -1
- package/dist/components/Scorecard/EntityScorecardContent.esm.js +8 -16
- package/dist/components/Scorecard/EntityScorecardContent.esm.js.map +1 -1
- package/dist/components/Scorecard/Scorecard.esm.js +10 -8
- package/dist/components/Scorecard/Scorecard.esm.js.map +1 -1
- package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js +12 -9
- package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js.map +1 -1
- package/dist/components/ScorecardHomepageSection/ErrorStatePanel.esm.js +51 -22
- package/dist/components/ScorecardHomepageSection/ErrorStatePanel.esm.js.map +1 -1
- package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js +43 -30
- package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js.map +1 -1
- package/dist/components/ScorecardHomepageSection/ScorecardHomepageCardComponent.esm.js +69 -6
- package/dist/components/ScorecardHomepageSection/ScorecardHomepageCardComponent.esm.js.map +1 -1
- package/dist/components/ScorecardIcon/ScorecardIcon.esm.js +30 -0
- package/dist/components/ScorecardIcon/ScorecardIcon.esm.js.map +1 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesRow.esm.js +47 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesRow.esm.js.map +1 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTable.esm.js +144 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTable.esm.js.map +1 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableFooter.esm.js +111 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableFooter.esm.js.map +1 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableHeader.esm.js +31 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableHeader.esm.js.map +1 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTablePagination.esm.js +76 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTablePagination.esm.js.map +1 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableStateRow.esm.js +36 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableStateRow.esm.js.map +1 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableWrapper.esm.js +58 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableWrapper.esm.js.map +1 -0
- package/dist/components/ScorecardPage/EntitiesTable/cells/EntityNameCell.esm.js +36 -0
- package/dist/components/ScorecardPage/EntitiesTable/cells/EntityNameCell.esm.js.map +1 -0
- package/dist/components/ScorecardPage/EntitiesTable/cells/MetricStatusCell.esm.js +31 -0
- package/dist/components/ScorecardPage/EntitiesTable/cells/MetricStatusCell.esm.js.map +1 -0
- package/dist/components/ScorecardPage/EntitiesTable/cells/OwnerCell.esm.js +35 -0
- package/dist/components/ScorecardPage/EntitiesTable/cells/OwnerCell.esm.js.map +1 -0
- package/dist/components/ScorecardPage/ScorecardPage.esm.js +89 -0
- package/dist/components/ScorecardPage/ScorecardPage.esm.js.map +1 -0
- package/dist/components/ScorecardPage/ScorecardPageHeader.esm.js +9 -0
- package/dist/components/ScorecardPage/ScorecardPageHeader.esm.js.map +1 -0
- package/dist/hooks/useAggregatedScorecard.esm.js +15 -15
- package/dist/hooks/useAggregatedScorecard.esm.js.map +1 -1
- package/dist/hooks/useAggregatedScorecardEntities.esm.js +63 -0
- package/dist/hooks/useAggregatedScorecardEntities.esm.js.map +1 -0
- package/dist/hooks/useAggregationMetadata.esm.js +42 -0
- package/dist/hooks/useAggregationMetadata.esm.js.map +1 -0
- package/dist/hooks/useEntityMetadataMap.esm.js +87 -0
- package/dist/hooks/useEntityMetadataMap.esm.js.map +1 -0
- package/dist/hooks/useLanguage.esm.js +7 -0
- package/dist/hooks/useLanguage.esm.js.map +1 -0
- package/dist/hooks/useMetric.esm.js +42 -0
- package/dist/hooks/useMetric.esm.js.map +1 -0
- package/dist/hooks/useMetricDisplayLabels.esm.js +22 -0
- package/dist/hooks/useMetricDisplayLabels.esm.js.map +1 -0
- package/dist/hooks/useOwnershipEntityRefs.esm.js +16 -0
- package/dist/hooks/useOwnershipEntityRefs.esm.js.map +1 -0
- package/dist/hooks/useScorecards.esm.js +14 -7
- package/dist/hooks/useScorecards.esm.js.map +1 -1
- package/dist/images/not-found.svg +9 -0
- package/dist/index.d.ts +15 -4
- package/dist/index.esm.js +4 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/pages/ScorecardPage.esm.js +2 -0
- package/dist/pages/ScorecardPage.esm.js.map +1 -0
- package/dist/plugin.esm.js +8 -1
- package/dist/plugin.esm.js.map +1 -1
- package/dist/routes.esm.js +5 -1
- package/dist/routes.esm.js.map +1 -1
- package/dist/translations/de.esm.js +55 -1
- package/dist/translations/de.esm.js.map +1 -1
- package/dist/translations/es.esm.js +55 -1
- package/dist/translations/es.esm.js.map +1 -1
- package/dist/translations/fr.esm.js +36 -1
- package/dist/translations/fr.esm.js.map +1 -1
- package/dist/translations/it.esm.js +37 -1
- package/dist/translations/it.esm.js.map +1 -1
- package/dist/translations/ja.esm.js +37 -1
- package/dist/translations/ja.esm.js.map +1 -1
- package/dist/translations/ref.esm.js +44 -2
- package/dist/translations/ref.esm.js.map +1 -1
- package/dist/types/index.d-N3BD4rEg.d.ts +75 -0
- package/dist/utils/constants.esm.js +39 -1
- package/dist/utils/constants.esm.js.map +1 -1
- package/dist/utils/entityTableUtils.esm.js +49 -0
- package/dist/utils/entityTableUtils.esm.js.map +1 -0
- package/dist/utils/statusUtils.esm.js +20 -12
- package/dist/utils/statusUtils.esm.js.map +1 -1
- package/dist/utils/thresholdUtils.esm.js +37 -0
- package/dist/utils/thresholdUtils.esm.js.map +1 -0
- package/package.json +34 -15
- package/dist/utils/colorUtils.esm.js +0 -38
- package/dist/utils/colorUtils.esm.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
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
|
+
|
|
3
43
|
## 2.4.0
|
|
4
44
|
|
|
5
45
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
36
|
+
### Procedure
|
|
28
37
|
|
|
29
|
-
|
|
38
|
+
#### NFS (New Frontend System) — app
|
|
30
39
|
|
|
31
|
-
|
|
40
|
+
1. Install the Scorecard frontend plugin (see [Installation and usage](#installation-and-usage)) using `app`:
|
|
32
41
|
|
|
33
|
-
|
|
42
|
+
```console
|
|
43
|
+
yarn workspace app add @red-hat-developer-hub/backstage-plugin-scorecard
|
|
44
|
+
```
|
|
34
45
|
|
|
35
|
-
|
|
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
|
-
|
|
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
|
-
|
|
93
|
+
**By type only** (e.g. any entity with `spec.type` equal to `service` or `website`):
|
|
42
94
|
|
|
43
95
|
```yaml
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
**
|
|
101
|
+
**By kind and type** (e.g. only `component` with type `website` or type `service`):
|
|
52
102
|
|
|
53
|
-
|
|
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
|
-
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
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;;;;"}
|