@red-hat-developer-hub/backstage-plugin-scorecard 4.2.0 → 4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/README.md +74 -10
- package/dist/alpha.d.ts +16 -0
- package/dist/blueprints/ScorecardLayoutBlueprint.esm.js +12 -10
- package/dist/blueprints/ScorecardLayoutBlueprint.esm.js.map +1 -1
- package/dist/components/AggregatedMetricCards/AggregatedMetricCard.esm.js +12 -5
- package/dist/components/AggregatedMetricCards/AggregatedMetricCard.esm.js.map +1 -1
- package/dist/components/AggregatedMetricCards/ScalarStatCard/ScalarStatCard.esm.js +76 -0
- package/dist/components/AggregatedMetricCards/ScalarStatCard/ScalarStatCard.esm.js.map +1 -0
- package/dist/components/AggregatedMetricCards/ScalarStatCard/ScalarStatTile.esm.js +66 -0
- package/dist/components/AggregatedMetricCards/ScalarStatCard/ScalarStatTile.esm.js.map +1 -0
- package/dist/components/AggregatedMetricCards/StatusGroupedCard/StatusGroupedCardComponent.esm.js +1 -0
- package/dist/components/AggregatedMetricCards/StatusGroupedCard/StatusGroupedCardComponent.esm.js.map +1 -1
- package/dist/components/AggregatedMetricCards/WeightedStatusScoreCard/DonutChartTooltipContent.esm.js +1 -1
- package/dist/components/AggregatedMetricCards/WeightedStatusScoreCard/WeightedStatusScoreCardComponent.esm.js +2 -5
- package/dist/components/AggregatedMetricCards/WeightedStatusScoreCard/WeightedStatusScoreCardComponent.esm.js.map +1 -1
- package/dist/components/Common/CardWrapper.esm.js +2 -2
- package/dist/components/Common/CardWrapper.esm.js.map +1 -1
- package/dist/components/MetricGroupCard/DataSourcesDialog.esm.js +3 -2
- package/dist/components/MetricGroupCard/DataSourcesDialog.esm.js.map +1 -1
- package/dist/components/MetricGroupCard/DataSourcesDialogColumns.esm.js +7 -1
- package/dist/components/MetricGroupCard/DataSourcesDialogColumns.esm.js.map +1 -1
- package/dist/components/MetricGroupCard/StatusIcon.esm.js +1 -1
- package/dist/components/MetricGroupCard/ThresholdBucketTile.esm.js +1 -1
- package/dist/components/MetricGroupCard/ThresholdLegend.esm.js +1 -1
- package/dist/components/MetricGroupCard/thresholdBucketUtils.esm.js +1 -0
- package/dist/components/MetricGroupCard/thresholdBucketUtils.esm.js.map +1 -1
- package/dist/components/Scorecard/CustomLegend.esm.js +4 -2
- package/dist/components/Scorecard/CustomLegend.esm.js.map +1 -1
- package/dist/components/Scorecard/EntityScorecardContent.esm.js +2 -1
- package/dist/components/Scorecard/EntityScorecardContent.esm.js.map +1 -1
- package/dist/components/Scorecard/Scorecard.esm.js +3 -2
- package/dist/components/Scorecard/Scorecard.esm.js.map +1 -1
- package/dist/components/Scorecard/ScorecardEntityContentGridView.esm.js +13 -4
- package/dist/components/Scorecard/ScorecardEntityContentGridView.esm.js.map +1 -1
- package/dist/components/ScorecardHomepageSection/CustomLegend.esm.js +1 -1
- package/dist/components/ScorecardHomepageSection/CustomTooltip.esm.js +1 -1
- package/dist/components/ScorecardHomepageSection/EmptyStatePanel.esm.js +1 -1
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesRow.esm.js +1 -0
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesRow.esm.js.map +1 -1
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTable.esm.js +25 -16
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTable.esm.js.map +1 -1
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableWrapper.esm.js +8 -1
- package/dist/components/ScorecardPage/EntitiesTable/EntitiesTableWrapper.esm.js.map +1 -1
- package/dist/components/ScorecardPage/EntitiesTable/cells/MetricStatusCell.esm.js +1 -1
- package/dist/extensions/entityTab.esm.js +8 -11
- package/dist/extensions/entityTab.esm.js.map +1 -1
- package/dist/extensions/homePageCards.esm.js +79 -1
- package/dist/extensions/homePageCards.esm.js.map +1 -1
- package/dist/index.d.ts +60 -0
- package/dist/index.esm.js +8 -2
- package/dist/index.esm.js.map +1 -1
- package/dist/translations/de.esm.js +16 -0
- package/dist/translations/de.esm.js.map +1 -1
- package/dist/translations/es.esm.js +16 -0
- package/dist/translations/es.esm.js.map +1 -1
- package/dist/translations/fr.esm.js +16 -0
- package/dist/translations/fr.esm.js.map +1 -1
- package/dist/translations/it.esm.js +16 -0
- package/dist/translations/it.esm.js.map +1 -1
- package/dist/translations/ja.esm.js +16 -0
- package/dist/translations/ja.esm.js.map +1 -1
- package/dist/translations/ref.esm.js +26 -0
- package/dist/translations/ref.esm.js.map +1 -1
- package/dist/utils/formatMetricUnit.esm.js +12 -0
- package/dist/utils/formatMetricUnit.esm.js.map +1 -0
- package/dist/utils/getDefaultEntitiesTableSort.esm.js +19 -0
- package/dist/utils/getDefaultEntitiesTableSort.esm.js.map +1 -0
- package/dist/utils/isScalarAggregation.esm.js +14 -0
- package/dist/utils/isScalarAggregation.esm.js.map +1 -0
- package/dist/utils/translationUtils.esm.js +6 -1
- package/dist/utils/translationUtils.esm.js.map +1 -1
- package/package.json +26 -33
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# @red-hat-developer-hub/backstage-plugin-scorecard
|
|
2
2
|
|
|
3
|
+
## 4.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @red-hat-developer-hub/backstage-plugin-scorecard-common@4.3.1
|
|
8
|
+
|
|
9
|
+
## 4.3.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- c380e6b: Skip scalar aggregation threshold coloring when no successful samples contributed (`total` is 0). Return a null display color and keep the card grey fallback. Scalar aggregation responses now include `aggregationChartDisplayColor` (threshold-derived chart color, or `null` when `total` is 0).
|
|
14
|
+
|
|
15
|
+
**BREAKING**: Changed types in `scorecard-common` module:
|
|
16
|
+
|
|
17
|
+
- `WeightedStatusScoreAggregationResult.aggregationChartDisplayColor` widened from `string` to `string | null`.
|
|
18
|
+
- `ScalarAggregationResult` gained a required `aggregationChartDisplayColor: string | null` property.
|
|
19
|
+
|
|
20
|
+
These changes are intentional: the API can return `null` when no samples contribute, and scalar KPI results now expose the same display-color field as weighted status score aggregations.
|
|
21
|
+
|
|
22
|
+
- 628533c: Add optional `titleKey` and `descriptionKey` on Scorecard layout groups so group titles and descriptions from app-config can be translated, with fallback to the configured English strings.
|
|
23
|
+
- a1c3eb3: Updated DORA Mean Time to Restore to Median Time to Restore.
|
|
24
|
+
- ff6683f: Add DORA metrics and a collectors framework for composing datasource data into metrics.
|
|
25
|
+
|
|
26
|
+
- New `@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dora` with Deployment Frequency, Median Lead Time for Changes, Mean Time to Restore, and Change Failure Rate
|
|
27
|
+
- New data collectors used by DORA: GitHub deployments, deployment workflow runs, and deployment pull requests; Jira incidents
|
|
28
|
+
- Metric time-series API `/metrics/catalog/:kind/:namespace/:name/time-series`
|
|
29
|
+
- Adds `defaultVisualization` to Metric metadata for sparkline
|
|
30
|
+
|
|
31
|
+
- 08e6312: Render scalar aggregation KPI cards from result shape (`ScalarStatCard`) for sum, average, min, max, and count, including threshold status and an unsupported-shape fallback.
|
|
32
|
+
- f3f71a5: Add unit to metric and display it in threshold legend
|
|
33
|
+
- a7a1b4a: Backstage version bump to v1.54.6
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- 1e93f4e: Add `HomePageWidgetBlueprint` for the README filecheck aggregated card so it appears in the NFS homepage add-widget dialog alongside the existing LICENSE and CODEOWNERS widgets.
|
|
38
|
+
- 0754805: Scalar aggregation KPI cards now use `result.aggregationChartDisplayColor` from the backend instead of re-evaluating threshold expressions on the frontend. Min/max scalar drill-down pages now default-sort the entities table by metric value (ascending for min, descending for max).
|
|
39
|
+
- 47ac76d: Export public `ScalarAggregationType` for scalar aggregation KPI types (`sum`, `average`, `count`, `min`, `max`).
|
|
40
|
+
|
|
41
|
+
Add legacy app E2E coverage for scalar and statusGrouped homepage aggregation KPI cards, including reusable Playwright registration helpers and legacy homepage widget entries for scalar KPIs.
|
|
42
|
+
|
|
43
|
+
- Updated dependencies [9c1936e]
|
|
44
|
+
- Updated dependencies [2bb0ec5]
|
|
45
|
+
- Updated dependencies [485fadb]
|
|
46
|
+
- Updated dependencies [befccc2]
|
|
47
|
+
- Updated dependencies [c380e6b]
|
|
48
|
+
- Updated dependencies [fea86e8]
|
|
49
|
+
- Updated dependencies [ff6683f]
|
|
50
|
+
- Updated dependencies [ecb789b]
|
|
51
|
+
- Updated dependencies [47ac76d]
|
|
52
|
+
- Updated dependencies [f3f71a5]
|
|
53
|
+
- Updated dependencies [a7a1b4a]
|
|
54
|
+
- @red-hat-developer-hub/backstage-plugin-scorecard-common@4.3.0
|
|
55
|
+
|
|
3
56
|
## 4.2.0
|
|
4
57
|
|
|
5
58
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ For NFS, register the default `scorecardPlugin` plus `scorecardTranslationsModul
|
|
|
9
9
|
**Features:**
|
|
10
10
|
|
|
11
11
|
- **Entity scorecard tab** — View scorecard metrics on catalog entity pages (components, websites, etc.).
|
|
12
|
-
- **Scorecard homepage card** — Show aggregated KPIs on the home page (e.g. GitHub open PRs, Jira open issues). Supports **`statusGrouped`** (multi-slice pie)
|
|
12
|
+
- **Scorecard homepage card** — Show aggregated KPIs on the home page (e.g. GitHub open PRs, Jira open issues). Supports **`statusGrouped`** (multi-slice pie), **`weightedStatusScore`** (weighted health donut), and scalar types (`sum`, `average`, `max`, `min`, `count`) configured under **`scorecard.aggregationKPIs`**.
|
|
13
13
|
- **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.
|
|
14
14
|
- **Metric group cards (grid layout)** — Group related metrics into cards with threshold bucket tiles, a filterable/sortable data sources dialog, and a Masonry grid layout. Enabled via app-config.yaml.
|
|
15
15
|
|
|
@@ -133,7 +133,9 @@ To align with the legacy EntityPage (Scorecard on component pages and default en
|
|
|
133
133
|
groups:
|
|
134
134
|
codeQuality:
|
|
135
135
|
title: 'Code Quality'
|
|
136
|
+
titleKey: groups.codeQuality.title
|
|
136
137
|
description: 'SonarQube code quality metrics'
|
|
138
|
+
descriptionKey: groups.codeQuality.description
|
|
137
139
|
metrics:
|
|
138
140
|
- sonarqube.reliabilityIssues
|
|
139
141
|
- sonarqube.codeCoverage
|
|
@@ -147,11 +149,13 @@ To align with the legacy EntityPage (Scorecard on component pages and default en
|
|
|
147
149
|
|
|
148
150
|
**Groups config schema:**
|
|
149
151
|
|
|
150
|
-
| Field
|
|
151
|
-
|
|
|
152
|
-
| `title`
|
|
153
|
-
| `
|
|
154
|
-
| `
|
|
152
|
+
| Field | Type | Required | Description |
|
|
153
|
+
| ---------------- | ---------- | -------- | ------------------------------------------------------------------------------------------------ |
|
|
154
|
+
| `title` | `string` | Yes | Display title for the group card. Used when `titleKey` is omitted or the translation is missing. |
|
|
155
|
+
| `titleKey` | `string` | No | Translation key under `plugin.scorecard` (for example `groups.codeQuality.title`). |
|
|
156
|
+
| `description` | `string` | No | Optional description shown below the title. Used when `descriptionKey` is omitted or missing. |
|
|
157
|
+
| `descriptionKey` | `string` | No | Translation key under `plugin.scorecard` (for example `groups.codeQuality.description`). |
|
|
158
|
+
| `metrics` | `string[]` | Yes | Ordered list of metric IDs to include in this group. |
|
|
155
159
|
|
|
156
160
|
**Behavior:**
|
|
157
161
|
|
|
@@ -239,9 +243,54 @@ To align with the legacy EntityPage (Scorecard on component pages and default en
|
|
|
239
243
|
sm: { w: 4, h: 6, x: 8 }
|
|
240
244
|
xs: { w: 4, h: 6, x: 8 }
|
|
241
245
|
xxs: { w: 4, h: 6, x: 8 }
|
|
246
|
+
AggregatedCardWithMaxOpenPrs:
|
|
247
|
+
priority: 480
|
|
248
|
+
breakpoints:
|
|
249
|
+
xl: { w: 4, h: 6 }
|
|
250
|
+
lg: { w: 4, h: 6 }
|
|
251
|
+
md: { w: 4, h: 6 }
|
|
252
|
+
sm: { w: 4, h: 6 }
|
|
253
|
+
xs: { w: 4, h: 6 }
|
|
254
|
+
xxs: { w: 4, h: 6 }
|
|
255
|
+
AggregatedCardWithMinOpenPrs:
|
|
256
|
+
priority: 490
|
|
257
|
+
breakpoints:
|
|
258
|
+
xl: { w: 4, h: 6, x: 4 }
|
|
259
|
+
lg: { w: 4, h: 6, x: 4 }
|
|
260
|
+
md: { w: 4, h: 6, x: 4 }
|
|
261
|
+
sm: { w: 4, h: 6, x: 4 }
|
|
262
|
+
xs: { w: 4, h: 6, x: 4 }
|
|
263
|
+
xxs: { w: 4, h: 6, x: 4 }
|
|
264
|
+
AggregatedCardWithTotalOpenBugs:
|
|
265
|
+
priority: 500
|
|
266
|
+
breakpoints:
|
|
267
|
+
xl: { w: 4, h: 6, x: 8 }
|
|
268
|
+
lg: { w: 4, h: 6, x: 8 }
|
|
269
|
+
md: { w: 4, h: 6, x: 8 }
|
|
270
|
+
sm: { w: 4, h: 6, x: 8 }
|
|
271
|
+
xs: { w: 4, h: 6, x: 8 }
|
|
272
|
+
xxs: { w: 4, h: 6, x: 8 }
|
|
273
|
+
AggregatedCardWithEntitiesWithOpenPrs:
|
|
274
|
+
priority: 510
|
|
275
|
+
breakpoints:
|
|
276
|
+
xl: { w: 4, h: 6 }
|
|
277
|
+
lg: { w: 4, h: 6 }
|
|
278
|
+
md: { w: 4, h: 6 }
|
|
279
|
+
sm: { w: 4, h: 6 }
|
|
280
|
+
xs: { w: 4, h: 6 }
|
|
281
|
+
xxs: { w: 4, h: 6 }
|
|
282
|
+
AggregatedCardWithAvgOpenPrs:
|
|
283
|
+
priority: 520
|
|
284
|
+
breakpoints:
|
|
285
|
+
xl: { w: 4, h: 6, x: 4 }
|
|
286
|
+
lg: { w: 4, h: 6, x: 4 }
|
|
287
|
+
md: { w: 4, h: 6, x: 4 }
|
|
288
|
+
sm: { w: 4, h: 6, x: 4 }
|
|
289
|
+
xs: { w: 4, h: 6, x: 4 }
|
|
290
|
+
xxs: { w: 4, h: 6, x: 4 }
|
|
242
291
|
```
|
|
243
292
|
|
|
244
|
-
The home module contributes
|
|
293
|
+
The home module contributes twelve widgets:
|
|
245
294
|
|
|
246
295
|
- `AggregatedCardWithDeprecatedMetricId` (title: **Scorecard: With deprecated metricId property (Jira)**)
|
|
247
296
|
- `AggregatedCardWithDefaultAggregation` (title: **Scorecard: With default aggregation config (GitHub)**)
|
|
@@ -250,6 +299,11 @@ To align with the legacy EntityPage (Scorecard on component pages and default en
|
|
|
250
299
|
- `AggregatedCardWithGithubFilecheckLicense` (title: **Scorecard: LICENSE file exists**)
|
|
251
300
|
- `AggregatedCardWithGithubFilecheckCodeowners` (title: **Scorecard: CODEOWNERS file exists**)
|
|
252
301
|
- `AggregatedCardWithGithubOpenPrsWeighted` (title: **Scorecard: GitHub open PRs (weighted health)**)
|
|
302
|
+
- `AggregatedCardWithMaxOpenPrs` (title: **Scorecard: Maximum open PRs**)
|
|
303
|
+
- `AggregatedCardWithMinOpenPrs` (title: **Scorecard: Minimum open PRs**)
|
|
304
|
+
- `AggregatedCardWithTotalOpenBugs` (title: **Scorecard: Total open bugs**)
|
|
305
|
+
- `AggregatedCardWithEntitiesWithOpenPrs` (title: **Scorecard: Entities with open PRs**)
|
|
306
|
+
- `AggregatedCardWithAvgOpenPrs` (title: **Scorecard: Average open PRs**)
|
|
253
307
|
|
|
254
308
|
These widgets render the `ScorecardHomepageCard` component used in legacy apps, preconfigured with different aggregation/metric configurations.
|
|
255
309
|
|
|
@@ -280,6 +334,11 @@ The default `scorecardPlugin` registers the Scorecard page, API, entity tab, lay
|
|
|
280
334
|
| `home-page-widget:scorecard/scorecard-github-filecheck-license` | Homepage widget for file check "License". |
|
|
281
335
|
| `home-page-widget:scorecard/scorecard-github-filecheck-codeowners` | Homepage widget for file check "Codeowners". |
|
|
282
336
|
| `home-page-widget:scorecard/scorecard-github-open-prs-weighted` | Homepage widget for weighted GitHub open PRs health. |
|
|
337
|
+
| `home-page-widget:scorecard/scorecard-max-open-prs` | Homepage widget for scalar max open PRs. |
|
|
338
|
+
| `home-page-widget:scorecard/scorecard-min-open-prs` | Homepage widget for scalar min open PRs. |
|
|
339
|
+
| `home-page-widget:scorecard/scorecard-total-open-bugs` | Homepage widget for scalar sum of open bugs. |
|
|
340
|
+
| `home-page-widget:scorecard/scorecard-entities-with-open-prs` | Homepage widget for scalar count of entities with open PRs. |
|
|
341
|
+
| `home-page-widget:scorecard/scorecard-avg-open-prs` | Homepage widget for scalar average open PRs. |
|
|
283
342
|
|
|
284
343
|
##### Migration notes (NFS graduation)
|
|
285
344
|
|
|
@@ -458,11 +517,11 @@ Supported scorecard aggregation types (see [Entity Aggregation — Aggregation t
|
|
|
458
517
|
- [`weightedStatusScore`](../scorecard-backend/docs/aggregation.md#weighted-status-score-type) — weighted portfolio health percentage (donut); requires `options.statusScores`.
|
|
459
518
|
- Scalar types ([`sum`](../scorecard-backend/docs/aggregation.md#sum-type), [`average`](../scorecard-backend/docs/aggregation.md#average-type), [`max`](../scorecard-backend/docs/aggregation.md#max-type), [`min`](../scorecard-backend/docs/aggregation.md#min-type), [`count`](../scorecard-backend/docs/aggregation.md#count-type)) — roll up latest numeric metric values; number metrics only. Optional [`filter.status`](../scorecard-backend/docs/aggregation.md#status-filter-scalar-types) limits the rollup to a threshold status.
|
|
460
519
|
|
|
461
|
-
**Scalar KPI types** (`sum`, `average`, `max`, `min`, `count`) are fully supported by **`GET /aggregations/:aggregationId`**, including optional **`filter.status`** and **`options.thresholds`**.
|
|
520
|
+
**Scalar KPI types** (`sum`, `average`, `max`, `min`, `count`) are fully supported by **`GET /aggregations/:aggregationId`**, including optional **`filter.status`** and **`options.thresholds`**. **`AggregatedMetricCard`** chooses the UI from the **result shape**: a numeric `value` renders **`ScalarStatCard`** (large number, optional description, aggregation-type label, tile color from **`result.aggregationChartDisplayColor`**); a `values` array renders the existing pie/donut cards; anything else shows **`UnsupportedAggregationType`**. Unknown scalar type names still render **`ScalarStatCard`** when the payload is scalar-shaped.
|
|
462
521
|
|
|
463
522
|
**Terminology:** Scalar **`average`** (mean of numeric metric values) is distinct from the former weighted KPI type also named `average`, which was renamed to **`weightedStatusScore`**. Update app-config **`type: average`** entries for weighted health scoring to **`type: weightedStatusScore`** and migrate API consumers from **`result.averageScore`** to **`result.weightedStatusScore`**.
|
|
464
523
|
|
|
465
|
-
|
|
524
|
+
Configure a scalar KPI such as **`maxOpenPrs`** under **`scorecard.aggregationKPIs`** and pass that id as **`aggregationId`** to **`ScorecardHomepageCard`** to render the aggregated value.
|
|
466
525
|
|
|
467
526
|
#### Card props
|
|
468
527
|
|
|
@@ -550,14 +609,19 @@ Translation keys follow this pattern:
|
|
|
550
609
|
|
|
551
610
|
- **Metric titles**: `metric.{metric-id}.title`
|
|
552
611
|
- **Metric descriptions**: `metric.{metric-id}.description`
|
|
612
|
+
- **Layout group titles**: set `titleKey` on the group in app-config (for example `groups.codeQuality.title`)
|
|
613
|
+
- **Layout group descriptions**: set `descriptionKey` on the group (for example `groups.codeQuality.description`)
|
|
614
|
+
|
|
615
|
+
Use the same `metric.{id}.{field}` pattern with a **KPI id** as `{metric-id}` when localizing **`aggregationKPIs`** titles (for example **`metric.openIssuesKpi.title`**).
|
|
553
616
|
|
|
554
|
-
|
|
617
|
+
Group titles and descriptions do **not** use the `metric.{id}.{field}` convention. They are customer-defined in `scorecard-layout` config, so you pass explicit `titleKey` / `descriptionKey` values. Provide translations in plugin locale files or via RHDH `i18n.overrides` under `plugin.scorecard`. If a key is omitted or not found, the UI shows the group's `title` / `description` strings and never the raw key.
|
|
555
618
|
|
|
556
619
|
### 3. Fallback Behavior
|
|
557
620
|
|
|
558
621
|
If a translation key is not found, the plugin will automatically fall back to:
|
|
559
622
|
|
|
560
623
|
- The original `title` and `description` values from the metric definition
|
|
624
|
+
- For layout groups: the `title` and `description` values from app-config
|
|
561
625
|
- For thresholds: capitalized versions of the threshold keys
|
|
562
626
|
|
|
563
627
|
### Example: Adding GitHub Open PRs Translation
|
package/dist/alpha.d.ts
CHANGED
|
@@ -34,6 +34,14 @@ declare const scorecardTranslationRef: _backstage_frontend_plugin_api.Translatio
|
|
|
34
34
|
readonly "errors.noDataFoundMessage": string;
|
|
35
35
|
readonly "errors.unsupportedAggregationType": string;
|
|
36
36
|
readonly "errors.authenticationErrorMessage": string;
|
|
37
|
+
readonly "metric.dora.deploymentFrequency.title": string;
|
|
38
|
+
readonly "metric.dora.deploymentFrequency.description": string;
|
|
39
|
+
readonly "metric.dora.medianLeadTimeForChanges.title": string;
|
|
40
|
+
readonly "metric.dora.medianLeadTimeForChanges.description": string;
|
|
41
|
+
readonly "metric.dora.changeFailureRate.title": string;
|
|
42
|
+
readonly "metric.dora.changeFailureRate.description": string;
|
|
43
|
+
readonly "metric.dora.medianTimeToRestore.title": string;
|
|
44
|
+
readonly "metric.dora.medianTimeToRestore.description": string;
|
|
37
45
|
readonly "metric.github.openPRs.title": string;
|
|
38
46
|
readonly "metric.github.openPRs.description": string;
|
|
39
47
|
readonly "metric.jira.openIssues.title": string;
|
|
@@ -77,9 +85,17 @@ declare const scorecardTranslationRef: _backstage_frontend_plugin_api.Translatio
|
|
|
77
85
|
readonly "metric.drillDownCalculationFailures": string;
|
|
78
86
|
readonly "metric.homepageEntityHealthRatio": string;
|
|
79
87
|
readonly "metric.homepageEntityCalculationHealth": string;
|
|
88
|
+
readonly "aggregation.min": string;
|
|
89
|
+
readonly "aggregation.max": string;
|
|
90
|
+
readonly "aggregation.sum": string;
|
|
91
|
+
readonly "aggregation.count": string;
|
|
92
|
+
readonly "aggregation.average": string;
|
|
80
93
|
readonly "thresholds.success": string;
|
|
81
94
|
readonly "thresholds.warning": string;
|
|
82
95
|
readonly "thresholds.error": string;
|
|
96
|
+
readonly "thresholds.elite": string;
|
|
97
|
+
readonly "thresholds.medium": string;
|
|
98
|
+
readonly "thresholds.low": string;
|
|
83
99
|
readonly "thresholds.exist": string;
|
|
84
100
|
readonly "thresholds.missing": string;
|
|
85
101
|
readonly "thresholds.noEntities": string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createElement } from 'react';
|
|
2
2
|
import { createExtensionDataRef, createExtensionBlueprint, coreExtensionData, ExtensionBoundary } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import { z } from 'zod';
|
|
3
4
|
|
|
4
5
|
const scorecardLayoutTitleDataRef = createExtensionDataRef().with({ id: "scorecard.layout-title" });
|
|
5
6
|
const ScorecardEntityContentLayoutBlueprint = createExtensionBlueprint({
|
|
@@ -12,16 +13,17 @@ const ScorecardEntityContentLayoutBlueprint = createExtensionBlueprint({
|
|
|
12
13
|
dataRefs: {
|
|
13
14
|
title: scorecardLayoutTitleDataRef
|
|
14
15
|
},
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
configSchema: {
|
|
17
|
+
groups: z.record(
|
|
18
|
+
z.string(),
|
|
19
|
+
z.object({
|
|
20
|
+
title: z.string(),
|
|
21
|
+
titleKey: z.string().optional(),
|
|
22
|
+
description: z.string().optional(),
|
|
23
|
+
descriptionKey: z.string().optional(),
|
|
24
|
+
metrics: z.array(z.string())
|
|
25
|
+
})
|
|
26
|
+
).optional().default({})
|
|
25
27
|
},
|
|
26
28
|
*factory(params, { config, node }) {
|
|
27
29
|
yield scorecardLayoutTitleDataRef(params.title);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScorecardLayoutBlueprint.esm.js","sources":["../../src/blueprints/ScorecardLayoutBlueprint.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 { ComponentType, createElement } from 'react';\nimport {\n coreExtensionData,\n createExtensionBlueprint,\n createExtensionDataRef,\n ExtensionBoundary,\n} from '@backstage/frontend-plugin-api';\n\n/**\n * Props for custom Scorecard entity-tab layout components.\n *\n * @public\n */\nexport interface ScorecardLayoutProps {\n /**\n * Metric groups to render, keyed by group id.\n */\n groups: Record<\n string,\n {
|
|
1
|
+
{"version":3,"file":"ScorecardLayoutBlueprint.esm.js","sources":["../../src/blueprints/ScorecardLayoutBlueprint.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 { ComponentType, createElement } from 'react';\nimport {\n coreExtensionData,\n createExtensionBlueprint,\n createExtensionDataRef,\n ExtensionBoundary,\n} from '@backstage/frontend-plugin-api';\nimport { z } from 'zod';\n\n/**\n * Props for custom Scorecard entity-tab layout components.\n *\n * @public\n */\nexport interface ScorecardLayoutProps {\n /**\n * Metric groups to render, keyed by group id.\n */\n groups: Record<\n string,\n {\n title: string;\n titleKey?: string;\n description?: string;\n descriptionKey?: string;\n metrics: string[];\n }\n >;\n}\n\n/**\n * Extension data ref carrying the human-readable layout title\n * (e.g. \"Grid\", \"List\") so the entity tab can build a toggle.\n *\n * @public\n */\nexport const scorecardLayoutTitleDataRef =\n createExtensionDataRef<string>().with({ id: 'scorecard.layout-title' });\n\n/**\n * Blueprint for creating scorecard layout extensions.\n *\n * Each layout is a separate extension that attaches to the Scorecard entity tab.\n * Platform engineers enable/disable individual layouts via app-config.yaml;\n * when multiple layouts are enabled the tab renders a toggle to switch between them.\n *\n * @public\n */\nexport const ScorecardEntityContentLayoutBlueprint = createExtensionBlueprint({\n kind: 'scorecard-layout',\n attachTo: {\n id: 'entity-content:scorecard/entity-content-scorecard',\n input: 'layouts',\n },\n output: [coreExtensionData.reactElement, scorecardLayoutTitleDataRef],\n dataRefs: {\n title: scorecardLayoutTitleDataRef,\n },\n configSchema: {\n groups: z\n .record(\n z.string(),\n z.object({\n title: z.string(),\n titleKey: z.string().optional(),\n description: z.string().optional(),\n descriptionKey: z.string().optional(),\n metrics: z.array(z.string()),\n }),\n )\n .optional()\n .default({}),\n },\n *factory(\n params: {\n title: string;\n loader: () => Promise<ComponentType<ScorecardLayoutProps>>;\n },\n { config, node },\n ) {\n yield scorecardLayoutTitleDataRef(params.title);\n yield coreExtensionData.reactElement(\n ExtensionBoundary.lazy(node, async () => {\n const Component = await params.loader();\n return createElement(Component, {\n groups: config.groups,\n });\n }),\n );\n },\n});\n"],"names":[],"mappings":";;;;AAoDO,MAAM,8BACX,sBAAA,EAA+B,CAAE,KAAK,EAAE,EAAA,EAAI,0BAA0B;AAWjE,MAAM,wCAAwC,wBAAA,CAAyB;AAAA,EAC5E,IAAA,EAAM,kBAAA;AAAA,EACN,QAAA,EAAU;AAAA,IACR,EAAA,EAAI,mDAAA;AAAA,IACJ,KAAA,EAAO;AAAA,GACT;AAAA,EACA,MAAA,EAAQ,CAAC,iBAAA,CAAkB,YAAA,EAAc,2BAA2B,CAAA;AAAA,EACpE,QAAA,EAAU;AAAA,IACR,KAAA,EAAO;AAAA,GACT;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,QAAQ,CAAA,CACL,MAAA;AAAA,MACC,EAAE,MAAA,EAAO;AAAA,MACT,EAAE,MAAA,CAAO;AAAA,QACP,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,QAChB,QAAA,EAAU,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,QAC9B,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,QACjC,cAAA,EAAgB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,QACpC,OAAA,EAAS,CAAA,CAAE,KAAA,CAAM,CAAA,CAAE,QAAQ;AAAA,OAC5B;AAAA,KACH,CACC,QAAA,EAAS,CACT,OAAA,CAAQ,EAAE;AAAA,GACf;AAAA,EACA,CAAC,OAAA,CACC,MAAA,EAIA,EAAE,MAAA,EAAQ,MAAK,EACf;AACA,IAAA,MAAM,2BAAA,CAA4B,OAAO,KAAK,CAAA;AAC9C,IAAA,MAAM,iBAAA,CAAkB,YAAA;AAAA,MACtB,iBAAA,CAAkB,IAAA,CAAK,IAAA,EAAM,YAAY;AACvC,QAAA,MAAM,SAAA,GAAY,MAAM,MAAA,CAAO,MAAA,EAAO;AACtC,QAAA,OAAO,cAAc,SAAA,EAAW;AAAA,UAC9B,QAAQ,MAAA,CAAO;AAAA,SAChB,CAAA;AAAA,MACH,CAAC;AAAA,KACH;AAAA,EACF;AACF,CAAC;;;;"}
|
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { aggregationTypes } from '@red-hat-developer-hub/backstage-plugin-scorecard-common';
|
|
3
2
|
import { StatusGroupedCardComponent } from './StatusGroupedCard/StatusGroupedCardComponent.esm.js';
|
|
4
3
|
import { WeightedStatusScoreCardComponent } from './WeightedStatusScoreCard/WeightedStatusScoreCardComponent.esm.js';
|
|
4
|
+
import { ScalarStatCard } from './ScalarStatCard/ScalarStatCard.esm.js';
|
|
5
5
|
import { UnsupportedAggregationType } from './UnsupportedAggregationType.esm.js';
|
|
6
|
+
import 'date-fns';
|
|
7
|
+
import { isScalarAggregationResult, isWeightedStatusScoreResult, isDistributionAggregationResult } from '../../utils/isScalarAggregation.esm.js';
|
|
8
|
+
import '@red-hat-developer-hub/backstage-plugin-scorecard-common';
|
|
6
9
|
|
|
7
|
-
const
|
|
8
|
-
const isWeightedStatusScoreCardProps = (props) => props.scorecard.
|
|
10
|
+
const isScalarStatCardProps = (props) => isScalarAggregationResult(props.scorecard.result);
|
|
11
|
+
const isWeightedStatusScoreCardProps = (props) => isWeightedStatusScoreResult(props.scorecard.result);
|
|
12
|
+
const isStatusGroupedCardProps = (props) => isDistributionAggregationResult(props.scorecard.result);
|
|
9
13
|
const AggregatedMetricCard = (props) => {
|
|
10
14
|
const { cardTitle, description, dataTestId, scorecard } = props;
|
|
11
|
-
if (
|
|
12
|
-
return /* @__PURE__ */ jsx(
|
|
15
|
+
if (isScalarStatCardProps(props)) {
|
|
16
|
+
return /* @__PURE__ */ jsx(ScalarStatCard, { ...props });
|
|
13
17
|
}
|
|
14
18
|
if (isWeightedStatusScoreCardProps(props)) {
|
|
15
19
|
return /* @__PURE__ */ jsx(WeightedStatusScoreCardComponent, { ...props });
|
|
16
20
|
}
|
|
21
|
+
if (isStatusGroupedCardProps(props)) {
|
|
22
|
+
return /* @__PURE__ */ jsx(StatusGroupedCardComponent, { ...props });
|
|
23
|
+
}
|
|
17
24
|
return /* @__PURE__ */ jsx(
|
|
18
25
|
UnsupportedAggregationType,
|
|
19
26
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AggregatedMetricCard.esm.js","sources":["../../../src/components/AggregatedMetricCards/AggregatedMetricCard.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
|
|
1
|
+
{"version":3,"file":"AggregatedMetricCard.esm.js","sources":["../../../src/components/AggregatedMetricCards/AggregatedMetricCard.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { AggregatedMetricResult } from '@red-hat-developer-hub/backstage-plugin-scorecard-common';\nimport { StatusGroupedCardComponent } from './StatusGroupedCard/StatusGroupedCardComponent';\nimport { WeightedStatusScoreCardComponent } from './WeightedStatusScoreCard/WeightedStatusScoreCardComponent';\nimport { ScalarStatCard } from './ScalarStatCard/ScalarStatCard';\nimport { UnsupportedAggregationType } from './UnsupportedAggregationType';\nimport {\n isDistributionAggregationResult,\n isScalarAggregationResult,\n isWeightedStatusScoreResult,\n} from '../../utils';\n\nimport type { WeightedStatusScoreCardComponentProps } from './WeightedStatusScoreCard/types';\nimport type { StatusGroupedCardComponentProps } from './StatusGroupedCard/types';\nimport type { ScalarStatCardProps } from './ScalarStatCard/types';\nimport type { AggregatedMetricCardBaseProps } from './types';\n\ntype AggregatedMetricCardProps = AggregatedMetricCardBaseProps & {\n scorecard: AggregatedMetricResult;\n};\n\nconst isScalarStatCardProps = (\n props: AggregatedMetricCardProps,\n): props is ScalarStatCardProps =>\n isScalarAggregationResult(props.scorecard.result);\n\nconst isWeightedStatusScoreCardProps = (\n props: AggregatedMetricCardProps,\n): props is WeightedStatusScoreCardComponentProps =>\n isWeightedStatusScoreResult(props.scorecard.result);\n\nconst isStatusGroupedCardProps = (\n props: AggregatedMetricCardProps,\n): props is StatusGroupedCardComponentProps =>\n isDistributionAggregationResult(props.scorecard.result);\n\nexport const AggregatedMetricCard = (props: AggregatedMetricCardProps) => {\n const { cardTitle, description, dataTestId, scorecard } = props;\n\n if (isScalarStatCardProps(props)) {\n return <ScalarStatCard {...props} />;\n }\n if (isWeightedStatusScoreCardProps(props)) {\n return <WeightedStatusScoreCardComponent {...props} />;\n }\n if (isStatusGroupedCardProps(props)) {\n return <StatusGroupedCardComponent {...props} />;\n }\n return (\n <UnsupportedAggregationType\n cardTitle={cardTitle}\n description={description}\n dataTestId={dataTestId}\n aggregationType={String(scorecard.metadata.aggregationType)}\n />\n );\n};\n"],"names":[],"mappings":";;;;;;;;;AAoCA,MAAM,wBAAwB,CAC5B,KAAA,KAEA,yBAAA,CAA0B,KAAA,CAAM,UAAU,MAAM,CAAA;AAElD,MAAM,iCAAiC,CACrC,KAAA,KAEA,2BAAA,CAA4B,KAAA,CAAM,UAAU,MAAM,CAAA;AAEpD,MAAM,2BAA2B,CAC/B,KAAA,KAEA,+BAAA,CAAgC,KAAA,CAAM,UAAU,MAAM,CAAA;AAEjD,MAAM,oBAAA,GAAuB,CAAC,KAAA,KAAqC;AACxE,EAAA,MAAM,EAAE,SAAA,EAAW,WAAA,EAAa,UAAA,EAAY,WAAU,GAAI,KAAA;AAE1D,EAAA,IAAI,qBAAA,CAAsB,KAAK,CAAA,EAAG;AAChC,IAAA,uBAAO,GAAA,CAAC,cAAA,EAAA,EAAgB,GAAG,KAAA,EAAO,CAAA;AAAA,EACpC;AACA,EAAA,IAAI,8BAAA,CAA+B,KAAK,CAAA,EAAG;AACzC,IAAA,uBAAO,GAAA,CAAC,gCAAA,EAAA,EAAkC,GAAG,KAAA,EAAO,CAAA;AAAA,EACtD;AACA,EAAA,IAAI,wBAAA,CAAyB,KAAK,CAAA,EAAG;AACnC,IAAA,uBAAO,GAAA,CAAC,0BAAA,EAAA,EAA4B,GAAG,KAAA,EAAO,CAAA;AAAA,EAChD;AACA,EAAA,uBACE,GAAA;AAAA,IAAC,0BAAA;AAAA,IAAA;AAAA,MACC,SAAA;AAAA,MACA,WAAA;AAAA,MACA,UAAA;AAAA,MACA,eAAA,EAAiB,MAAA,CAAO,SAAA,CAAU,QAAA,CAAS,eAAe;AAAA;AAAA,GAC5D;AAEJ;;;;"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useTheme } from '@mui/material/styles';
|
|
3
|
+
import { CardWrapper } from '../../Common/CardWrapper.esm.js';
|
|
4
|
+
import 'date-fns';
|
|
5
|
+
import { formatWithMetricUnit } from '../../../utils/formatMetricUnit.esm.js';
|
|
6
|
+
import '@red-hat-developer-hub/backstage-plugin-scorecard-common';
|
|
7
|
+
import { resolveStatusColor } from '../../../utils/statusUtils.esm.js';
|
|
8
|
+
import { useTranslation } from '../../../hooks/useTranslation.esm.js';
|
|
9
|
+
import { CardInfoButton } from '../components/CardInfoButton.esm.js';
|
|
10
|
+
import { CardSubheader } from '../components/CardSubheader.esm.js';
|
|
11
|
+
import { CardChartContainer } from '../components/CardChartContainer.esm.js';
|
|
12
|
+
import { formatAggregationScoreDetail } from '../WeightedStatusScoreCard/TooltipContent.esm.js';
|
|
13
|
+
import { ScalarStatTile } from './ScalarStatTile.esm.js';
|
|
14
|
+
|
|
15
|
+
function getAggregationTypeLabel(aggregationType, t) {
|
|
16
|
+
if (!aggregationType) {
|
|
17
|
+
return "";
|
|
18
|
+
}
|
|
19
|
+
const key = `aggregation.${aggregationType}`;
|
|
20
|
+
const translated = t(key, {});
|
|
21
|
+
if (translated !== key) {
|
|
22
|
+
return translated;
|
|
23
|
+
}
|
|
24
|
+
return aggregationType.charAt(0).toUpperCase() + aggregationType.slice(1);
|
|
25
|
+
}
|
|
26
|
+
const ScalarStatCard = ({
|
|
27
|
+
scorecard,
|
|
28
|
+
cardTitle,
|
|
29
|
+
description,
|
|
30
|
+
aggregationId,
|
|
31
|
+
showSubheader = true,
|
|
32
|
+
showInfo = true,
|
|
33
|
+
dataTestId
|
|
34
|
+
}) => {
|
|
35
|
+
const theme = useTheme();
|
|
36
|
+
const { t } = useTranslation();
|
|
37
|
+
const { result, metadata, id: scorecardId } = scorecard;
|
|
38
|
+
const resolvedColor = result.aggregationChartDisplayColor ? resolveStatusColor(theme, result.aggregationChartDisplayColor) : theme.palette.grey[300];
|
|
39
|
+
const displayValue = formatWithMetricUnit(
|
|
40
|
+
formatAggregationScoreDetail(result.value),
|
|
41
|
+
metadata.unit
|
|
42
|
+
);
|
|
43
|
+
const aggregationLabel = getAggregationTypeLabel(metadata.aggregationType, t);
|
|
44
|
+
const subheader = showSubheader ? /* @__PURE__ */ jsx(
|
|
45
|
+
CardSubheader,
|
|
46
|
+
{
|
|
47
|
+
aggregationId,
|
|
48
|
+
scorecardId,
|
|
49
|
+
entitiesCount: result.total,
|
|
50
|
+
entitiesConsidered: result.entitiesConsidered,
|
|
51
|
+
calculationErrorCount: result.calculationErrorCount
|
|
52
|
+
}
|
|
53
|
+
) : null;
|
|
54
|
+
const info = showInfo ? /* @__PURE__ */ jsx(CardInfoButton, { timestamp: result.timestamp }) : null;
|
|
55
|
+
return /* @__PURE__ */ jsx(
|
|
56
|
+
CardWrapper,
|
|
57
|
+
{
|
|
58
|
+
title: cardTitle,
|
|
59
|
+
dataTestId,
|
|
60
|
+
subheader,
|
|
61
|
+
description,
|
|
62
|
+
info,
|
|
63
|
+
children: /* @__PURE__ */ jsx(CardChartContainer, { children: /* @__PURE__ */ jsx(
|
|
64
|
+
ScalarStatTile,
|
|
65
|
+
{
|
|
66
|
+
displayValue,
|
|
67
|
+
label: aggregationLabel,
|
|
68
|
+
resolvedColor
|
|
69
|
+
}
|
|
70
|
+
) })
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export { ScalarStatCard };
|
|
76
|
+
//# sourceMappingURL=ScalarStatCard.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScalarStatCard.esm.js","sources":["../../../../src/components/AggregatedMetricCards/ScalarStatCard/ScalarStatCard.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 { useTheme } from '@mui/material/styles';\nimport type { TranslationFunction } from '@backstage/core-plugin-api/alpha';\n\nimport { CardWrapper } from '../../Common/CardWrapper';\nimport { formatWithMetricUnit, resolveStatusColor } from '../../../utils';\nimport { useTranslation } from '../../../hooks/useTranslation';\nimport { scorecardTranslationRef } from '../../../translations';\nimport { CardInfoButton } from '../components/CardInfoButton';\nimport { CardSubheader } from '../components/CardSubheader';\nimport { CardChartContainer } from '../components/CardChartContainer';\nimport { formatAggregationScoreDetail } from '../WeightedStatusScoreCard/TooltipContent';\nimport { ScalarStatTile } from './ScalarStatTile';\nimport type { ScalarStatCardProps } from './types';\n\nfunction getAggregationTypeLabel(\n aggregationType: string,\n t: TranslationFunction<typeof scorecardTranslationRef.T>,\n): string {\n if (!aggregationType) {\n return '';\n }\n\n const key = `aggregation.${aggregationType}`;\n const translated = t(key as any, {});\n if (translated !== key) {\n return translated;\n }\n\n return aggregationType.charAt(0).toUpperCase() + aggregationType.slice(1);\n}\n\nexport const ScalarStatCard = ({\n scorecard,\n cardTitle,\n description,\n aggregationId,\n showSubheader = true,\n showInfo = true,\n dataTestId,\n}: ScalarStatCardProps) => {\n const theme = useTheme();\n const { t } = useTranslation();\n const { result, metadata, id: scorecardId } = scorecard;\n\n const resolvedColor = result.aggregationChartDisplayColor\n ? resolveStatusColor(theme, result.aggregationChartDisplayColor)\n : theme.palette.grey[300];\n const displayValue = formatWithMetricUnit(\n formatAggregationScoreDetail(result.value),\n metadata.unit,\n );\n const aggregationLabel = getAggregationTypeLabel(metadata.aggregationType, t);\n\n const subheader = showSubheader ? (\n <CardSubheader\n aggregationId={aggregationId}\n scorecardId={scorecardId}\n entitiesCount={result.total}\n entitiesConsidered={result.entitiesConsidered}\n calculationErrorCount={result.calculationErrorCount}\n />\n ) : null;\n\n const info = showInfo ? (\n <CardInfoButton timestamp={result.timestamp} />\n ) : null;\n\n return (\n <CardWrapper\n title={cardTitle}\n dataTestId={dataTestId}\n subheader={subheader}\n description={description}\n info={info}\n >\n <CardChartContainer>\n <ScalarStatTile\n displayValue={displayValue}\n label={aggregationLabel}\n resolvedColor={resolvedColor}\n />\n </CardChartContainer>\n </CardWrapper>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;AA8BA,SAAS,uBAAA,CACP,iBACA,CAAA,EACQ;AACR,EAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,MAAM,GAAA,GAAM,eAAe,eAAe,CAAA,CAAA;AAC1C,EAAA,MAAM,UAAA,GAAa,CAAA,CAAE,GAAA,EAAY,EAAE,CAAA;AACnC,EAAA,IAAI,eAAe,GAAA,EAAK;AACtB,IAAA,OAAO,UAAA;AAAA,EACT;AAEA,EAAA,OAAO,eAAA,CAAgB,OAAO,CAAC,CAAA,CAAE,aAAY,GAAI,eAAA,CAAgB,MAAM,CAAC,CAAA;AAC1E;AAEO,MAAM,iBAAiB,CAAC;AAAA,EAC7B,SAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA,GAAgB,IAAA;AAAA,EAChB,QAAA,GAAW,IAAA;AAAA,EACX;AACF,CAAA,KAA2B;AACzB,EAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,cAAA,EAAe;AAC7B,EAAA,MAAM,EAAE,MAAA,EAAQ,QAAA,EAAU,EAAA,EAAI,aAAY,GAAI,SAAA;AAE9C,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,4BAAA,GACzB,kBAAA,CAAmB,KAAA,EAAO,MAAA,CAAO,4BAA4B,CAAA,GAC7D,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,GAAG,CAAA;AAC1B,EAAA,MAAM,YAAA,GAAe,oBAAA;AAAA,IACnB,4BAAA,CAA6B,OAAO,KAAK,CAAA;AAAA,IACzC,QAAA,CAAS;AAAA,GACX;AACA,EAAA,MAAM,gBAAA,GAAmB,uBAAA,CAAwB,QAAA,CAAS,eAAA,EAAiB,CAAC,CAAA;AAE5E,EAAA,MAAM,YAAY,aAAA,mBAChB,GAAA;AAAA,IAAC,aAAA;AAAA,IAAA;AAAA,MACC,aAAA;AAAA,MACA,WAAA;AAAA,MACA,eAAe,MAAA,CAAO,KAAA;AAAA,MACtB,oBAAoB,MAAA,CAAO,kBAAA;AAAA,MAC3B,uBAAuB,MAAA,CAAO;AAAA;AAAA,GAChC,GACE,IAAA;AAEJ,EAAA,MAAM,OAAO,QAAA,mBACX,GAAA,CAAC,kBAAe,SAAA,EAAW,MAAA,CAAO,WAAW,CAAA,GAC3C,IAAA;AAEJ,EAAA,uBACE,GAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,SAAA;AAAA,MACP,UAAA;AAAA,MACA,SAAA;AAAA,MACA,WAAA;AAAA,MACA,IAAA;AAAA,MAEA,8BAAC,kBAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,QAAC,cAAA;AAAA,QAAA;AAAA,UACC,YAAA;AAAA,UACA,KAAA,EAAO,gBAAA;AAAA,UACP;AAAA;AAAA,OACF,EACF;AAAA;AAAA,GACF;AAEJ;;;;"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import Box from '@mui/material/Box';
|
|
3
|
+
import Typography from '@mui/material/Typography';
|
|
4
|
+
import { darken, alpha } from '@mui/material/styles';
|
|
5
|
+
|
|
6
|
+
const ScalarStatTile = ({
|
|
7
|
+
displayValue,
|
|
8
|
+
label,
|
|
9
|
+
resolvedColor
|
|
10
|
+
}) => {
|
|
11
|
+
const textColor = darken(resolvedColor, 0.3);
|
|
12
|
+
return /* @__PURE__ */ jsxs(
|
|
13
|
+
Box,
|
|
14
|
+
{
|
|
15
|
+
"data-testid": "scalar-stat-tile",
|
|
16
|
+
"aria-label": `${label} ${displayValue}`,
|
|
17
|
+
sx: {
|
|
18
|
+
width: "100%",
|
|
19
|
+
minHeight: 140,
|
|
20
|
+
py: 4,
|
|
21
|
+
px: 2,
|
|
22
|
+
borderRadius: 2,
|
|
23
|
+
backgroundColor: alpha(resolvedColor, 0.16),
|
|
24
|
+
textAlign: "center",
|
|
25
|
+
display: "flex",
|
|
26
|
+
flexDirection: "column",
|
|
27
|
+
alignItems: "center",
|
|
28
|
+
justifyContent: "center"
|
|
29
|
+
},
|
|
30
|
+
children: [
|
|
31
|
+
/* @__PURE__ */ jsx(
|
|
32
|
+
Typography,
|
|
33
|
+
{
|
|
34
|
+
"data-testid": "scalar-stat-value",
|
|
35
|
+
variant: "h3",
|
|
36
|
+
sx: {
|
|
37
|
+
fontSize: "2.5rem",
|
|
38
|
+
fontWeight: 700,
|
|
39
|
+
color: textColor,
|
|
40
|
+
lineHeight: 1.2
|
|
41
|
+
},
|
|
42
|
+
children: displayValue
|
|
43
|
+
}
|
|
44
|
+
),
|
|
45
|
+
/* @__PURE__ */ jsx(
|
|
46
|
+
Typography,
|
|
47
|
+
{
|
|
48
|
+
"data-testid": "scalar-stat-label",
|
|
49
|
+
variant: "body1",
|
|
50
|
+
sx: {
|
|
51
|
+
fontSize: "1rem",
|
|
52
|
+
fontWeight: 500,
|
|
53
|
+
color: textColor,
|
|
54
|
+
lineHeight: 1.3,
|
|
55
|
+
mt: 0.5
|
|
56
|
+
},
|
|
57
|
+
children: label
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export { ScalarStatTile };
|
|
66
|
+
//# sourceMappingURL=ScalarStatTile.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScalarStatTile.esm.js","sources":["../../../../src/components/AggregatedMetricCards/ScalarStatCard/ScalarStatTile.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport { alpha, darken } from '@mui/material/styles';\n\ntype ScalarStatTileProps = {\n displayValue: string;\n label: string;\n resolvedColor: string;\n};\n\nexport const ScalarStatTile = ({\n displayValue,\n label,\n resolvedColor,\n}: ScalarStatTileProps) => {\n const textColor = darken(resolvedColor, 0.3);\n\n return (\n <Box\n data-testid=\"scalar-stat-tile\"\n aria-label={`${label} ${displayValue}`}\n sx={{\n width: '100%',\n minHeight: 140,\n py: 4,\n px: 2,\n borderRadius: 2,\n backgroundColor: alpha(resolvedColor, 0.16),\n textAlign: 'center',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <Typography\n data-testid=\"scalar-stat-value\"\n variant=\"h3\"\n sx={{\n fontSize: '2.5rem',\n fontWeight: 700,\n color: textColor,\n lineHeight: 1.2,\n }}\n >\n {displayValue}\n </Typography>\n <Typography\n data-testid=\"scalar-stat-label\"\n variant=\"body1\"\n sx={{\n fontSize: '1rem',\n fontWeight: 500,\n color: textColor,\n lineHeight: 1.3,\n mt: 0.5,\n }}\n >\n {label}\n </Typography>\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;AA0BO,MAAM,iBAAiB,CAAC;AAAA,EAC7B,YAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,KAA2B;AACzB,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,aAAA,EAAe,GAAG,CAAA;AAE3C,EAAA,uBACE,IAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,aAAA,EAAY,kBAAA;AAAA,MACZ,YAAA,EAAY,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA;AAAA,MACpC,EAAA,EAAI;AAAA,QACF,KAAA,EAAO,MAAA;AAAA,QACP,SAAA,EAAW,GAAA;AAAA,QACX,EAAA,EAAI,CAAA;AAAA,QACJ,EAAA,EAAI,CAAA;AAAA,QACJ,YAAA,EAAc,CAAA;AAAA,QACd,eAAA,EAAiB,KAAA,CAAM,aAAA,EAAe,IAAI,CAAA;AAAA,QAC1C,SAAA,EAAW,QAAA;AAAA,QACX,OAAA,EAAS,MAAA;AAAA,QACT,aAAA,EAAe,QAAA;AAAA,QACf,UAAA,EAAY,QAAA;AAAA,QACZ,cAAA,EAAgB;AAAA,OAClB;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,aAAA,EAAY,mBAAA;AAAA,YACZ,OAAA,EAAQ,IAAA;AAAA,YACR,EAAA,EAAI;AAAA,cACF,QAAA,EAAU,QAAA;AAAA,cACV,UAAA,EAAY,GAAA;AAAA,cACZ,KAAA,EAAO,SAAA;AAAA,cACP,UAAA,EAAY;AAAA,aACd;AAAA,YAEC,QAAA,EAAA;AAAA;AAAA,SACH;AAAA,wBACA,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,aAAA,EAAY,mBAAA;AAAA,YACZ,OAAA,EAAQ,OAAA;AAAA,YACR,EAAA,EAAI;AAAA,cACF,QAAA,EAAU,MAAA;AAAA,cACV,UAAA,EAAY,GAAA;AAAA,cACZ,KAAA,EAAO,SAAA;AAAA,cACP,UAAA,EAAY,GAAA;AAAA,cACZ,EAAA,EAAI;AAAA,aACN;AAAA,YAEC,QAAA,EAAA;AAAA;AAAA;AACH;AAAA;AAAA,GACF;AAEJ;;;;"}
|
package/dist/components/AggregatedMetricCards/StatusGroupedCard/StatusGroupedCardComponent.esm.js
CHANGED
|
@@ -3,6 +3,7 @@ import { useTheme } from '@mui/material/styles';
|
|
|
3
3
|
import { useState } from 'react';
|
|
4
4
|
import { SCORECARD_ERROR_STATE_COLOR } from '../../../utils/constants.esm.js';
|
|
5
5
|
import 'date-fns';
|
|
6
|
+
import '@red-hat-developer-hub/backstage-plugin-scorecard-common';
|
|
6
7
|
import { resolveStatusColor } from '../../../utils/statusUtils.esm.js';
|
|
7
8
|
import { getThresholdRuleColor } from '../../../utils/thresholdUtils.esm.js';
|
|
8
9
|
import { CardWrapper } from '../../Common/CardWrapper.esm.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusGroupedCardComponent.esm.js","sources":["../../../../src/components/AggregatedMetricCards/StatusGroupedCard/StatusGroupedCardComponent.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 { useTheme } from '@mui/material/styles';\nimport { useState } from 'react';\nimport { PieData } from '../../types';\nimport type { TooltipPosition } from '../types';\nimport {\n getThresholdRuleColor,\n SCORECARD_ERROR_STATE_COLOR,\n resolveStatusColor,\n} from '../../../utils';\nimport { CardWrapper } from '../../Common/CardWrapper';\nimport { CardInfoButton } from '../components/CardInfoButton';\nimport { ResponsivePieChart } from '../../ScorecardHomepageSection/ResponsivePieChart';\nimport { CardLegendContent } from '../components/CardLegendContent';\nimport { CardPieTooltipContent } from '../components/CardPieTooltipContent';\nimport { CardChartContainer } from '../components/CardChartContainer';\nimport { CardSubheader } from '../components/CardSubheader';\nimport { CardTooltip } from '../components/CardTooltip';\nimport { StatusGroupedCardComponentProps } from './types';\n\nexport const StatusGroupedCardComponent = ({\n scorecard,\n cardTitle,\n description,\n aggregationId,\n showSubheader = true,\n showInfo = true,\n dataTestId,\n}: StatusGroupedCardComponentProps) => {\n const theme = useTheme();\n\n const [activeIndex, setActiveIndex] = useState<number | null>(null);\n const [tooltipPosition, setTooltipPosition] =\n useState<TooltipPosition | null>(null);\n\n const { id: scorecardId, result } = scorecard;\n\n const pieData: PieData[] =\n result.values?.map(value => ({\n name: value.name,\n value: value.count,\n color: resolveStatusColor(\n theme,\n getThresholdRuleColor(result.thresholds.rules, value.name) ??\n SCORECARD_ERROR_STATE_COLOR,\n ),\n })) ?? [];\n\n const subheader = showSubheader ? (\n <CardSubheader\n aggregationId={aggregationId}\n scorecardId={scorecardId}\n entitiesCount={result.total}\n entitiesConsidered={result.entitiesConsidered}\n calculationErrorCount={result.calculationErrorCount}\n />\n ) : null;\n\n const info = showInfo ? (\n <CardInfoButton timestamp={result.timestamp} />\n ) : null;\n\n return (\n <CardWrapper\n title={cardTitle}\n dataTestId={dataTestId}\n subheader={subheader}\n description={description}\n info={info}\n >\n <CardChartContainer>\n <ResponsivePieChart\n pieData={pieData}\n legendContent={props => (\n <CardLegendContent\n {...props}\n activeIndex={activeIndex}\n setActiveIndex={setActiveIndex}\n setTooltipPosition={setTooltipPosition}\n pieData={pieData}\n />\n )}\n tooltipContent={({ active, payload }) => (\n <CardPieTooltipContent\n active={active}\n payload={payload}\n pieData={pieData}\n />\n )}\n />\n\n {activeIndex !== null && tooltipPosition && (\n <CardTooltip\n tooltipPosition={tooltipPosition}\n pieData={pieData}\n payload={[\n {\n name: pieData[activeIndex].name,\n value: pieData[activeIndex].value,\n payload: pieData[activeIndex],\n },\n ]}\n />\n )}\n </CardChartContainer>\n </CardWrapper>\n );\n};\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"StatusGroupedCardComponent.esm.js","sources":["../../../../src/components/AggregatedMetricCards/StatusGroupedCard/StatusGroupedCardComponent.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 { useTheme } from '@mui/material/styles';\nimport { useState } from 'react';\nimport { PieData } from '../../types';\nimport type { TooltipPosition } from '../types';\nimport {\n getThresholdRuleColor,\n SCORECARD_ERROR_STATE_COLOR,\n resolveStatusColor,\n} from '../../../utils';\nimport { CardWrapper } from '../../Common/CardWrapper';\nimport { CardInfoButton } from '../components/CardInfoButton';\nimport { ResponsivePieChart } from '../../ScorecardHomepageSection/ResponsivePieChart';\nimport { CardLegendContent } from '../components/CardLegendContent';\nimport { CardPieTooltipContent } from '../components/CardPieTooltipContent';\nimport { CardChartContainer } from '../components/CardChartContainer';\nimport { CardSubheader } from '../components/CardSubheader';\nimport { CardTooltip } from '../components/CardTooltip';\nimport { StatusGroupedCardComponentProps } from './types';\n\nexport const StatusGroupedCardComponent = ({\n scorecard,\n cardTitle,\n description,\n aggregationId,\n showSubheader = true,\n showInfo = true,\n dataTestId,\n}: StatusGroupedCardComponentProps) => {\n const theme = useTheme();\n\n const [activeIndex, setActiveIndex] = useState<number | null>(null);\n const [tooltipPosition, setTooltipPosition] =\n useState<TooltipPosition | null>(null);\n\n const { id: scorecardId, result } = scorecard;\n\n const pieData: PieData[] =\n result.values?.map(value => ({\n name: value.name,\n value: value.count,\n color: resolveStatusColor(\n theme,\n getThresholdRuleColor(result.thresholds.rules, value.name) ??\n SCORECARD_ERROR_STATE_COLOR,\n ),\n })) ?? [];\n\n const subheader = showSubheader ? (\n <CardSubheader\n aggregationId={aggregationId}\n scorecardId={scorecardId}\n entitiesCount={result.total}\n entitiesConsidered={result.entitiesConsidered}\n calculationErrorCount={result.calculationErrorCount}\n />\n ) : null;\n\n const info = showInfo ? (\n <CardInfoButton timestamp={result.timestamp} />\n ) : null;\n\n return (\n <CardWrapper\n title={cardTitle}\n dataTestId={dataTestId}\n subheader={subheader}\n description={description}\n info={info}\n >\n <CardChartContainer>\n <ResponsivePieChart\n pieData={pieData}\n legendContent={props => (\n <CardLegendContent\n {...props}\n activeIndex={activeIndex}\n setActiveIndex={setActiveIndex}\n setTooltipPosition={setTooltipPosition}\n pieData={pieData}\n />\n )}\n tooltipContent={({ active, payload }) => (\n <CardPieTooltipContent\n active={active}\n payload={payload}\n pieData={pieData}\n />\n )}\n />\n\n {activeIndex !== null && tooltipPosition && (\n <CardTooltip\n tooltipPosition={tooltipPosition}\n pieData={pieData}\n payload={[\n {\n name: pieData[activeIndex].name,\n value: pieData[activeIndex].value,\n payload: pieData[activeIndex],\n },\n ]}\n />\n )}\n </CardChartContainer>\n </CardWrapper>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAmCO,MAAM,6BAA6B,CAAC;AAAA,EACzC,SAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA,GAAgB,IAAA;AAAA,EAChB,QAAA,GAAW,IAAA;AAAA,EACX;AACF,CAAA,KAAuC;AACrC,EAAA,MAAM,QAAQ,QAAA,EAAS;AAEvB,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAwB,IAAI,CAAA;AAClE,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GACxC,SAAiC,IAAI,CAAA;AAEvC,EAAA,MAAM,EAAE,EAAA,EAAI,WAAA,EAAa,MAAA,EAAO,GAAI,SAAA;AAEpC,EAAA,MAAM,OAAA,GACJ,MAAA,CAAO,MAAA,EAAQ,GAAA,CAAI,CAAA,KAAA,MAAU;AAAA,IAC3B,MAAM,KAAA,CAAM,IAAA;AAAA,IACZ,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,KAAA,EAAO,kBAAA;AAAA,MACL,KAAA;AAAA,MACA,sBAAsB,MAAA,CAAO,UAAA,CAAW,KAAA,EAAO,KAAA,CAAM,IAAI,CAAA,IACvD;AAAA;AACJ,GACF,CAAE,KAAK,EAAC;AAEV,EAAA,MAAM,YAAY,aAAA,mBAChB,GAAA;AAAA,IAAC,aAAA;AAAA,IAAA;AAAA,MACC,aAAA;AAAA,MACA,WAAA;AAAA,MACA,eAAe,MAAA,CAAO,KAAA;AAAA,MACtB,oBAAoB,MAAA,CAAO,kBAAA;AAAA,MAC3B,uBAAuB,MAAA,CAAO;AAAA;AAAA,GAChC,GACE,IAAA;AAEJ,EAAA,MAAM,OAAO,QAAA,mBACX,GAAA,CAAC,kBAAe,SAAA,EAAW,MAAA,CAAO,WAAW,CAAA,GAC3C,IAAA;AAEJ,EAAA,uBACE,GAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,SAAA;AAAA,MACP,UAAA;AAAA,MACA,SAAA;AAAA,MACA,WAAA;AAAA,MACA,IAAA;AAAA,MAEA,+BAAC,kBAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,kBAAA;AAAA,UAAA;AAAA,YACC,OAAA;AAAA,YACA,eAAe,CAAA,KAAA,qBACb,GAAA;AAAA,cAAC,iBAAA;AAAA,cAAA;AAAA,gBACE,GAAG,KAAA;AAAA,gBACJ,WAAA;AAAA,gBACA,cAAA;AAAA,gBACA,kBAAA;AAAA,gBACA;AAAA;AAAA,aACF;AAAA,YAEF,cAAA,EAAgB,CAAC,EAAE,MAAA,EAAQ,SAAQ,qBACjC,GAAA;AAAA,cAAC,qBAAA;AAAA,cAAA;AAAA,gBACC,MAAA;AAAA,gBACA,OAAA;AAAA,gBACA;AAAA;AAAA;AACF;AAAA,SAEJ;AAAA,QAEC,WAAA,KAAgB,QAAQ,eAAA,oBACvB,GAAA;AAAA,UAAC,WAAA;AAAA,UAAA;AAAA,YACC,eAAA;AAAA,YACA,OAAA;AAAA,YACA,OAAA,EAAS;AAAA,cACP;AAAA,gBACE,IAAA,EAAM,OAAA,CAAQ,WAAW,CAAA,CAAE,IAAA;AAAA,gBAC3B,KAAA,EAAO,OAAA,CAAQ,WAAW,CAAA,CAAE,KAAA;AAAA,gBAC5B,OAAA,EAAS,QAAQ,WAAW;AAAA;AAC9B;AACF;AAAA;AACF,OAAA,EAEJ;AAAA;AAAA,GACF;AAEJ;;;;"}
|
|
@@ -5,8 +5,8 @@ import Typography from '@mui/material/Typography';
|
|
|
5
5
|
import { TooltipContent, formatAggregationScoreDetail } from './TooltipContent.esm.js';
|
|
6
6
|
import { useTranslation } from '../../../hooks/useTranslation.esm.js';
|
|
7
7
|
import 'date-fns';
|
|
8
|
-
import { getTranslatedStatus } from '../../../utils/statusUtils.esm.js';
|
|
9
8
|
import '@red-hat-developer-hub/backstage-plugin-scorecard-common';
|
|
9
|
+
import { getTranslatedStatus } from '../../../utils/statusUtils.esm.js';
|
|
10
10
|
|
|
11
11
|
const DonutChartTooltipContent = ({
|
|
12
12
|
weightedSum,
|
|
@@ -3,8 +3,8 @@ import { useState } from 'react';
|
|
|
3
3
|
import { useTheme } from '@mui/material/styles';
|
|
4
4
|
import { CardWrapper } from '../../Common/CardWrapper.esm.js';
|
|
5
5
|
import 'date-fns';
|
|
6
|
-
import { resolveStatusColor } from '../../../utils/statusUtils.esm.js';
|
|
7
6
|
import '@red-hat-developer-hub/backstage-plugin-scorecard-common';
|
|
7
|
+
import { resolveStatusColor } from '../../../utils/statusUtils.esm.js';
|
|
8
8
|
import { ResponsivePieChart } from '../../ScorecardHomepageSection/ResponsivePieChart.esm.js';
|
|
9
9
|
import { CardInfoButton } from '../components/CardInfoButton.esm.js';
|
|
10
10
|
import { CardSubheader } from '../components/CardSubheader.esm.js';
|
|
@@ -41,10 +41,7 @@ const WeightedStatusScoreCardComponent = ({
|
|
|
41
41
|
const weightedStatusScorePercent = scorecard.result.weightedStatusScore;
|
|
42
42
|
const { fill: chartFillPercent, remainder: chartRemainderPercent } = clampPercentForDonut(weightedStatusScorePercent);
|
|
43
43
|
const centerPercentLabel = `${formatPercentage(weightedStatusScorePercent)}%`;
|
|
44
|
-
const arcResolvedColor = resolveStatusColor(
|
|
45
|
-
theme,
|
|
46
|
-
scorecard.result.aggregationChartDisplayColor
|
|
47
|
-
);
|
|
44
|
+
const arcResolvedColor = scorecard.result.aggregationChartDisplayColor ? resolveStatusColor(theme, scorecard.result.aggregationChartDisplayColor) : theme.palette.grey[300];
|
|
48
45
|
const weightedStatusScorePieData = [
|
|
49
46
|
{
|
|
50
47
|
name: WEIGHTED_STATUS_SCORE_SLICE,
|