Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions workspaces/scorecard/.changeset/shy-parts-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@red-hat-developer-hub/backstage-plugin-scorecard': minor
---

Introduce a MetricGroupCard component that aggregates related metrics into threshold-based bucket tiles with a filterable data sources dialog. ScorecardEntityContentGridView to render grouped metrics as MetricGroupCards and ungrouped metrics as individual Scorecard cards using a Masonry layout. Add i18n keys across all supported locales and comprehensive unit tests for all new components.
45 changes: 43 additions & 2 deletions workspaces/scorecard/plugins/scorecard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The plugin supports both the **legacy** Backstage frontend and the **New Fronten
- **Entity scorecard tab** β€” View scorecard metrics on catalog entity pages (components, websites, etc.).
- **Scorecard homepage card** β€” Show aggregated KPIs on the home page (e.g. GitHub open PRs, Jira open issues). Supports **`statusGrouped`** (multi-slice pie) and **`average`** (weighted health donut) KPI types configured under **`scorecard.aggregationKPIs`**.
- **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.
- **Metric group cards (grid layout)** β€” Group related metrics into collapsible cards with threshold bucket tiles, a filterable/sortable data sources dialog, and a Masonry grid layout. Enabled via app-config.yaml.

## Getting started

Expand Down Expand Up @@ -122,7 +123,46 @@ To align with the legacy EntityPage (Scorecard on component pages and default en

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).

6. (Optional) Enable homepage Scorecard widgets by adding `scorecardHomeModule` to app features (see step 2) and configuring home page extensions in `app-config.yaml`:
6. (Optional) Enable the **grid layout** with metric group cards. The grid layout extension is disabled by default. Enable it and define `groups` in `app-config.yaml` to organize metrics into themed cards:

```yaml
app:
extensions:
- scorecard-layout:catalog/scorecard-entity-layout-grid:
config:
groups:
codeQuality:
title: 'Code Quality'
description: 'SonarQube code quality metrics'
metrics:
- sonarqube.reliability_issues
- sonarqube.code_coverage
- sonarqube.security_issues
operations:
title: 'Operations'
metrics:
- github.open_prs
- jira.open_issues
```

**Groups config schema:**

| Field | Type | Required | Description |
| ------------- | ---------- | -------- | ---------------------------------------------------- |
| `title` | `string` | Yes | Display title for the group card. |
| `description` | `string` | No | Optional description shown below the title. |
| `metrics` | `string[]` | Yes | Ordered list of metric IDs to include in this group. |

**Behavior:**

- Metrics listed in `groups` are rendered as **MetricGroupCard** components. Each card shows threshold bucket tiles (e.g. Passing, Warning, Failing) with counts. Clicking a tile opens a **data sources dialog** pre-filtered to that status.
- The data sources dialog displays a sortable, filterable table with columns: Plugin, Check, Value, Status, and Last Synced. A threshold legend allows toggling visibility by status.
- Metrics **not** listed in any group are rendered as individual Scorecard cards below the group cards.
- All cards are arranged in a responsive **Masonry** grid (1 column on mobile, 2 on tablet, 3 on desktop).
- If `groups` is empty or omitted, the grid layout falls back to the default `EntityScorecardContent` view (individual cards for all metrics).
- When multiple layout extensions are enabled, the Scorecard tab renders a toggle to switch between them.

7. (Optional) Enable homepage Scorecard widgets by adding `scorecardHomeModule` to app features (see step 2) and configuring home page extensions in `app-config.yaml`:

```yaml
app:
Expand Down Expand Up @@ -222,13 +262,14 @@ The following modules and extensions are available from `@red-hat-developer-hub/
| Module | Description |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scorecardHomeModule` | Registers Scorecard homepage widgets for the home plugin (`AggregatedCardWithDeprecatedMetricId`, `AggregatedCardWithDefaultAggregation`, `AggregatedCardWithJiraOpenIssues`, `AggregatedCardWithGithubOpenPrs`, `AggregatedCardWithGithubFilecheckLicense`, `AggregatedCardWithGithubFilecheckCodeowners` and `AggregatedCardWithGithubOpenPrsWeighted`). |
| `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). |
| `scorecardCatalogModule` | Registers the Scorecard entity tab and the grid layout extension with the catalog plugin. Add to your app's `features`. Which entities show the tab is configured via `app.extensions` (see step 3). The grid layout is disabled by default; enable and configure it with `groups` (see step 6). |
| `scorecardTranslationsModule` | Registers Scorecard translations with the app. Add to your app's `features`. |

**Extensions**

- `api:scorecard` β€” Scorecard API (provided by the plugin; auto-discovered when the plugin is installed).
- `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.
- `scorecard-layout:catalog/scorecard-entity-layout-grid` β€” Grid layout with metric group cards (disabled by default). Enable via `app.extensions` and define `groups` to organize metrics into themed cards (see step 6).
- `home-page-widget:home/scorecard-deprecated-metric-id` β€” Homepage widget using deprecated metricId property (Jira open issues).
- `home-page-widget:home/scorecard-default-aggregation` β€” Homepage widget using default aggregation config (GitHub open PRs).
- `home-page-widget:home/scorecard-jira-open-issues` β€” Homepage widget showing Jira open blocking tickets.
Expand Down
3 changes: 2 additions & 1 deletion workspaces/scorecard/plugins/scorecard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@
"@backstage/plugin-permission-react": "^0.4.41",
"@backstage/plugin-user-settings": "^0.9.1",
"@backstage/theme": "^0.7.2",
"@backstage/ui": "^0.13.2",
"@mui/icons-material": "5.18.0",
"@mui/lab": "5.0.0-alpha.177",
"@mui/material": "5.18.0",
"@mui/styles": "5.18.0",
"@red-hat-developer-hub/backstage-plugin-scorecard-common": "workspace:^",
Expand All @@ -85,7 +87,6 @@
"@backstage/plugin-catalog": "^2.0.1",
"@backstage/plugin-user-settings": "^0.9.1",
"@backstage/test-utils": "^1.7.16",
"@backstage/ui": "^0.13.2",
"@red-hat-developer-hub/backstage-plugin-theme": "^0.13.0",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^14.0.0",
Expand Down
13 changes: 12 additions & 1 deletion workspaces/scorecard/plugins/scorecard/report-alpha.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,17 @@ export const scorecardTranslationRef: TranslationRef<
readonly 'thresholds.noEntities': string;
readonly 'thresholds.entities_one': string;
readonly 'thresholds.entities_other': string;
readonly 'dataSourcesDialog.title': string;
readonly 'dataSourcesDialog.close': string;
readonly 'dataSourcesDialog.unknownPlugin': string;
readonly 'dataSourcesDialog.statusTooltip': string;
readonly 'dataSourcesDialog.columns.plugin': string;
readonly 'dataSourcesDialog.columns.check': string;
readonly 'dataSourcesDialog.columns.value': string;
readonly 'dataSourcesDialog.columns.status': string;
readonly 'dataSourcesDialog.columns.lastSynced': string;
readonly 'metricGroupCard.menuAriaLabel': string;
readonly 'metricGroupCard.viewDataSources': string;
readonly 'entitiesPage.missingPermission': string;
readonly 'entitiesPage.noDataFound': string;
readonly 'entitiesPage.unknownMetric': string;
Expand All @@ -224,8 +235,8 @@ export const scorecardTranslationRef: TranslationRef<
readonly 'entitiesPage.entitiesTable.unavailable': string;
readonly 'entitiesPage.entitiesTable.titleWithCount': string;
readonly 'entitiesPage.entitiesTable.header.lastUpdated': string;
readonly 'entitiesPage.entitiesTable.header.status': string;
readonly 'entitiesPage.entitiesTable.header.value': string;
readonly 'entitiesPage.entitiesTable.header.status': string;
readonly 'entitiesPage.entitiesTable.header.entity': string;
readonly 'entitiesPage.entitiesTable.header.owner': string;
readonly 'entitiesPage.entitiesTable.header.kind': string;
Expand Down
13 changes: 12 additions & 1 deletion workspaces/scorecard/plugins/scorecard/report.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@ export const scorecardTranslationRef: TranslationRef<
readonly 'thresholds.noEntities': string;
readonly 'thresholds.entities_one': string;
readonly 'thresholds.entities_other': string;
readonly 'dataSourcesDialog.title': string;
readonly 'dataSourcesDialog.close': string;
readonly 'dataSourcesDialog.unknownPlugin': string;
readonly 'dataSourcesDialog.statusTooltip': string;
readonly 'dataSourcesDialog.columns.plugin': string;
readonly 'dataSourcesDialog.columns.check': string;
readonly 'dataSourcesDialog.columns.value': string;
readonly 'dataSourcesDialog.columns.status': string;
readonly 'dataSourcesDialog.columns.lastSynced': string;
readonly 'metricGroupCard.menuAriaLabel': string;
readonly 'metricGroupCard.viewDataSources': string;
readonly 'entitiesPage.missingPermission': string;
readonly 'entitiesPage.noDataFound': string;
readonly 'entitiesPage.unknownMetric': string;
Expand All @@ -124,8 +135,8 @@ export const scorecardTranslationRef: TranslationRef<
readonly 'entitiesPage.entitiesTable.unavailable': string;
readonly 'entitiesPage.entitiesTable.titleWithCount': string;
readonly 'entitiesPage.entitiesTable.header.lastUpdated': string;
readonly 'entitiesPage.entitiesTable.header.status': string;
readonly 'entitiesPage.entitiesTable.header.value': string;
readonly 'entitiesPage.entitiesTable.header.status': string;
readonly 'entitiesPage.entitiesTable.header.entity': string;
readonly 'entitiesPage.entitiesTable.header.owner': string;
readonly 'entitiesPage.entitiesTable.header.kind': string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,3 @@ export const scorecardEntityLayoutGrid =
).then(m => m.ScorecardEntityContentGridView),
},
});

/**
* List view layout extension for the Scorecard entity tab.
*
* Extension ID: scorecard-layout:catalog/scorecard-entity-layout-list
* In UI Epic RHIDP-13950, this will be replaced with ScorecardEntityListView
* @alpha
*/
export const scorecardEntityLayoutList =
ScorecardEntityContentLayoutBlueprint.make({
name: 'scorecard-entity-layout-list',
disabled: true,
params: {
title: 'List',
loader: () =>
import(
'../../components/Scorecard/ScorecardEntityContentGridView'
).then(m => m.ScorecardEntityContentGridView),
},
});
17 changes: 5 additions & 12 deletions workspaces/scorecard/plugins/scorecard/src/alpha/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ import {
aggregatedCardWithGithubOpenPrsWeightedWidget,
} from './extensions/homePageCards';
import { scorecardPage } from './extensions/scorecardPage';
import {
scorecardEntityLayoutGrid,
scorecardEntityLayoutList,
} from './extensions/scorecardLayoutExtensions';
import { scorecardEntityLayoutGrid } from './extensions/scorecardLayoutExtensions';

/**
* Extension for Scorecard translations.
Expand All @@ -61,20 +58,16 @@ export default createFrontendPlugin({
});

/**
* Catalog module that injects the Scorecard tab and into Catalog entity pages.
* Catalog module that injects the Scorecard tab into Catalog entity pages.
*
* Also ships grid and list layout extensions (disabled by default).
* Enable them in app-config.yaml to get a layout toggle in the entity tab.
* Also ships a grid layout extension (disabled by default).
* Enable it in app-config.yaml to get a layout toggle in the entity tab.
*
* @alpha
*/
export const scorecardCatalogModule = createFrontendModule({
pluginId: 'catalog',
extensions: [
scorecardEntityContent,
scorecardEntityLayoutGrid,
scorecardEntityLayoutList,
],
extensions: [scorecardEntityContent, scorecardEntityLayoutGrid],
});

/**
Expand Down
Loading
Loading