@red-hat-developer-hub/backstage-plugin-scorecard 4.3.1 → 4.4.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 +20 -0
- package/README.md +43 -22
- package/dist/alpha.d.ts +4 -0
- package/dist/api/ScorecardQueryProvider.esm.js +2 -0
- package/dist/api/ScorecardQueryProvider.esm.js.map +1 -1
- package/dist/api/index.esm.js +162 -0
- package/dist/api/index.esm.js.map +1 -1
- package/dist/components/AggregatedMetricCards/AggregatedSparklineCard.esm.js +117 -0
- package/dist/components/AggregatedMetricCards/AggregatedSparklineCard.esm.js.map +1 -0
- package/dist/components/AggregatedMetricCards/components/CardInfoButton.esm.js +36 -22
- package/dist/components/AggregatedMetricCards/components/CardInfoButton.esm.js.map +1 -1
- package/dist/components/MetricGroupCard/DataSourcesDialog.esm.js +26 -59
- package/dist/components/MetricGroupCard/DataSourcesDialog.esm.js.map +1 -1
- package/dist/components/MetricGroupCard/DataSourcesDialogColumns.esm.js +37 -23
- package/dist/components/MetricGroupCard/DataSourcesDialogColumns.esm.js.map +1 -1
- package/dist/components/MetricGroupCard/MetricGroupCard.esm.js +9 -1
- package/dist/components/MetricGroupCard/MetricGroupCard.esm.js.map +1 -1
- package/dist/components/MetricGroupCard/collectorSourceRows.esm.js +30 -0
- package/dist/components/MetricGroupCard/collectorSourceRows.esm.js.map +1 -0
- package/dist/components/MetricGroupCard/metricSourceRows.esm.js +44 -0
- package/dist/components/MetricGroupCard/metricSourceRows.esm.js.map +1 -0
- package/dist/components/Scorecard/EntityMetricCard.esm.js +64 -0
- package/dist/components/Scorecard/EntityMetricCard.esm.js.map +1 -0
- package/dist/components/Scorecard/EntityScorecardContent.esm.js +2 -47
- package/dist/components/Scorecard/EntityScorecardContent.esm.js.map +1 -1
- package/dist/components/Scorecard/EntitySparklineCard.esm.js +134 -0
- package/dist/components/Scorecard/EntitySparklineCard.esm.js.map +1 -0
- package/dist/components/Scorecard/ScorecardEntityContentGridView.esm.js +5 -45
- package/dist/components/Scorecard/ScorecardEntityContentGridView.esm.js.map +1 -1
- package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js +66 -9
- package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js.map +1 -1
- package/dist/components/ScorecardPage/ScorecardPage.esm.js +2 -1
- package/dist/components/ScorecardPage/ScorecardPage.esm.js.map +1 -1
- package/dist/components/SparklineChart/SparklineChart.esm.js +260 -0
- package/dist/components/SparklineChart/SparklineChart.esm.js.map +1 -0
- package/dist/components/SparklineChart/SparklineCurrentValue.esm.js +55 -0
- package/dist/components/SparklineChart/SparklineCurrentValue.esm.js.map +1 -0
- package/dist/components/SparklineChart/SparklineDataSources.esm.js +23 -0
- package/dist/components/SparklineChart/SparklineDataSources.esm.js.map +1 -0
- package/dist/components/SparklineChart/SparklineLegend.esm.js +59 -0
- package/dist/components/SparklineChart/SparklineLegend.esm.js.map +1 -0
- package/dist/components/SparklineChart/SparklineTooltip.esm.js +59 -0
- package/dist/components/SparklineChart/SparklineTooltip.esm.js.map +1 -0
- package/dist/extensions/homePageCards.esm.js +71 -1
- package/dist/extensions/homePageCards.esm.js.map +1 -1
- package/dist/hooks/useAggregatedScorecard.esm.js +1 -1
- package/dist/hooks/useAggregatedScorecard.esm.js.map +1 -1
- package/dist/hooks/useAggregationMetadata.esm.js +3 -2
- package/dist/hooks/useAggregationMetadata.esm.js.map +1 -1
- package/dist/hooks/useAggregationTimeSeries.esm.js +50 -0
- package/dist/hooks/useAggregationTimeSeries.esm.js.map +1 -0
- package/dist/hooks/useMetricCollectors.esm.js +20 -0
- package/dist/hooks/useMetricCollectors.esm.js.map +1 -0
- package/dist/hooks/useMetricTimeSeries.esm.js +56 -0
- package/dist/hooks/useMetricTimeSeries.esm.js.map +1 -0
- package/dist/hooks/useSparklineDataSources.esm.js +71 -0
- package/dist/hooks/useSparklineDataSources.esm.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.esm.js +7 -2
- package/dist/index.esm.js.map +1 -1
- package/dist/translations/de.esm.js +41 -37
- package/dist/translations/de.esm.js.map +1 -1
- package/dist/translations/es.esm.js +23 -19
- package/dist/translations/es.esm.js.map +1 -1
- package/dist/translations/fr.esm.js +19 -15
- package/dist/translations/fr.esm.js.map +1 -1
- package/dist/translations/it.esm.js +18 -14
- package/dist/translations/it.esm.js.map +1 -1
- package/dist/translations/ja.esm.js +18 -14
- package/dist/translations/ja.esm.js.map +1 -1
- package/dist/translations/ref.esm.js +5 -1
- package/dist/translations/ref.esm.js.map +1 -1
- package/dist/utils/constants.esm.js +2 -1
- package/dist/utils/constants.esm.js.map +1 -1
- package/dist/utils/formatMetricUnit.esm.js +8 -1
- package/dist/utils/formatMetricUnit.esm.js.map +1 -1
- package/dist/utils/metricVisualization.esm.js +4 -0
- package/dist/utils/metricVisualization.esm.js.map +1 -0
- package/dist/utils/sparklineChartModel.esm.js +28 -0
- package/dist/utils/sparklineChartModel.esm.js.map +1 -0
- package/dist/utils/sparklineLegend.esm.js +56 -0
- package/dist/utils/sparklineLegend.esm.js.map +1 -0
- package/dist/utils/timeSeriesChartData.esm.js +106 -0
- package/dist/utils/timeSeriesChartData.esm.js.map +1 -0
- package/dist/utils/timeSeriesRange.esm.js +13 -0
- package/dist/utils/timeSeriesRange.esm.js.map +1 -0
- package/dist/utils/translationUtils.esm.js +1 -1
- package/dist/utils/translationUtils.esm.js.map +1 -1
- package/package.json +2 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @red-hat-developer-hub/backstage-plugin-scorecard
|
|
2
2
|
|
|
3
|
+
## 4.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f5f0d02: Updated translations for RHDH 2.1 (s3297).
|
|
8
|
+
- @red-hat-developer-hub/backstage-plugin-scorecard-common@4.4.1
|
|
9
|
+
|
|
10
|
+
## 4.4.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- aabab35: Add sparkline charts on the entity Scorecard tab for metrics whose `defaultVisualization` is `sparkline` (for example DORA). Each card shows a 30-day trend, a threshold legend, and a View data sources dialog for collectors. Legend and line color come from the time-series threshold rules.
|
|
15
|
+
- 6037d87: Add sparkline charts on the Scorecard homepage for aggregations whose visualization is `sparkline` (for example DORA). Each card shows a 30-day trend and a threshold legend. Legend and line color come from the time-series threshold rules.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 8c690d2: Remove unused package dependencies reported by knip. Add the missing `@backstage/config` dependency used by threshold config helpers.
|
|
20
|
+
- 73e2c67: Add a View data sources menu on homepage sparkline cards, next to the last-updated info button.
|
|
21
|
+
- @red-hat-developer-hub/backstage-plugin-scorecard-common@4.4.0
|
|
22
|
+
|
|
3
23
|
## 4.3.1
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -288,11 +288,21 @@ To align with the legacy EntityPage (Scorecard on component pages and default en
|
|
|
288
288
|
sm: { w: 4, h: 6, x: 4 }
|
|
289
289
|
xs: { w: 4, h: 6, x: 4 }
|
|
290
290
|
xxs: { w: 4, h: 6, x: 4 }
|
|
291
|
+
AggregatedCardWithDoraDeploymentFrequency:
|
|
292
|
+
priority: 530
|
|
293
|
+
breakpoints:
|
|
294
|
+
xl: { w: 4, h: 6, x: 8 }
|
|
295
|
+
lg: { w: 4, h: 6, x: 8 }
|
|
296
|
+
md: { w: 4, h: 6, x: 8 }
|
|
297
|
+
sm: { w: 4, h: 6, x: 8 }
|
|
298
|
+
xs: { w: 4, h: 6, x: 8 }
|
|
299
|
+
xxs: { w: 4, h: 6, x: 8 }
|
|
291
300
|
```
|
|
292
301
|
|
|
293
|
-
The home module contributes
|
|
302
|
+
The home module contributes these widgets:
|
|
294
303
|
|
|
295
304
|
- `AggregatedCardWithDeprecatedMetricId` (title: **Scorecard: With deprecated metricId property (Jira)**)
|
|
305
|
+
- `AggregatedCardWithDeprecatedDoraChangeFailureRate` (title: **Scorecard: With deprecated metricId property (DORA change failure rate)**)
|
|
296
306
|
- `AggregatedCardWithDefaultAggregation` (title: **Scorecard: With default aggregation config (GitHub)**)
|
|
297
307
|
- `AggregatedCardWithJiraOpenIssues` (title: **Scorecard: Jira open blocking tickets**)
|
|
298
308
|
- `AggregatedCardWithGithubOpenPrs` (title: **Scorecard: GitHub open PRs**)
|
|
@@ -304,6 +314,10 @@ To align with the legacy EntityPage (Scorecard on component pages and default en
|
|
|
304
314
|
- `AggregatedCardWithTotalOpenBugs` (title: **Scorecard: Total open bugs**)
|
|
305
315
|
- `AggregatedCardWithEntitiesWithOpenPrs` (title: **Scorecard: Entities with open PRs**)
|
|
306
316
|
- `AggregatedCardWithAvgOpenPrs` (title: **Scorecard: Average open PRs**)
|
|
317
|
+
- `AggregatedCardWithDoraDeploymentFrequency` (title: **Scorecard: DORA - Deployment Frequency**)
|
|
318
|
+
- `AggregatedCardWithDoraChangeFailureRate` (title: **Scorecard: DORA - Change Failure Rate**)
|
|
319
|
+
- `AggregatedCardWithDoraMedianLeadTimeForChanges` (title: **Scorecard: DORA - Lead Time for Changes**)
|
|
320
|
+
- `AggregatedCardWithDoraMedianTimeToRestore` (title: **Scorecard: DORA - Median Time to Restore**)
|
|
307
321
|
|
|
308
322
|
These widgets render the `ScorecardHomepageCard` component used in legacy apps, preconfigured with different aggregation/metric configurations.
|
|
309
323
|
|
|
@@ -321,24 +335,29 @@ The default `scorecardPlugin` registers the Scorecard page, API, entity tab, lay
|
|
|
321
335
|
|
|
322
336
|
**Extension IDs**
|
|
323
337
|
|
|
324
|
-
| Extension ID
|
|
325
|
-
|
|
|
326
|
-
| `api:scorecard`
|
|
327
|
-
| `page:scorecard`
|
|
328
|
-
| `entity-content:scorecard/entity-content-scorecard`
|
|
329
|
-
| `scorecard-layout:scorecard/scorecard-entity-layout-grid`
|
|
330
|
-
| `home-page-widget:scorecard/scorecard-deprecated-metric-id`
|
|
331
|
-
| `home-page-widget:scorecard/scorecard-
|
|
332
|
-
| `home-page-widget:scorecard/scorecard-
|
|
333
|
-
| `home-page-widget:scorecard/scorecard-
|
|
334
|
-
| `home-page-widget:scorecard/scorecard-github-
|
|
335
|
-
| `home-page-widget:scorecard/scorecard-github-filecheck-
|
|
336
|
-
| `home-page-widget:scorecard/scorecard-github-
|
|
337
|
-
| `home-page-widget:scorecard/scorecard-
|
|
338
|
-
| `home-page-widget:scorecard/scorecard-
|
|
339
|
-
| `home-page-widget:scorecard/scorecard-
|
|
340
|
-
| `home-page-widget:scorecard/scorecard-
|
|
341
|
-
| `home-page-widget:scorecard/scorecard-
|
|
338
|
+
| Extension ID | Description |
|
|
339
|
+
| -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
340
|
+
| `api:scorecard` | Scorecard API (auto-discovered when the plugin is installed). |
|
|
341
|
+
| `page:scorecard` | Scorecard entities / drill-down page. |
|
|
342
|
+
| `entity-content:scorecard/entity-content-scorecard` | Scorecard tab on catalog entity pages. Configure with `allowedFilters` in `app.extensions` to limit by kind and optionally type. |
|
|
343
|
+
| `scorecard-layout:scorecard/scorecard-entity-layout-grid` | Grid layout with metric group cards (disabled by default). Enable via `app.extensions` and define `groups` (see step 6). |
|
|
344
|
+
| `home-page-widget:scorecard/scorecard-deprecated-metric-id` | Homepage widget using deprecated `metricId` (Jira open issues). |
|
|
345
|
+
| `home-page-widget:scorecard/scorecard-deprecated-dora-change-failure-rate` | Homepage widget using deprecated `metricId` (DORA change failure rate). |
|
|
346
|
+
| `home-page-widget:scorecard/scorecard-default-aggregation` | Homepage widget using default aggregation (GitHub open PRs). |
|
|
347
|
+
| `home-page-widget:scorecard/scorecard-jira-open-issues` | Homepage widget for Jira open blocking tickets. |
|
|
348
|
+
| `home-page-widget:scorecard/scorecard-github-open-prs` | Homepage widget for GitHub open PRs. |
|
|
349
|
+
| `home-page-widget:scorecard/scorecard-github-filecheck-license` | Homepage widget for file check "License". |
|
|
350
|
+
| `home-page-widget:scorecard/scorecard-github-filecheck-codeowners` | Homepage widget for file check "Codeowners". |
|
|
351
|
+
| `home-page-widget:scorecard/scorecard-github-open-prs-weighted` | Homepage widget for weighted GitHub open PRs health. |
|
|
352
|
+
| `home-page-widget:scorecard/scorecard-max-open-prs` | Homepage widget for scalar max open PRs. |
|
|
353
|
+
| `home-page-widget:scorecard/scorecard-min-open-prs` | Homepage widget for scalar min open PRs. |
|
|
354
|
+
| `home-page-widget:scorecard/scorecard-total-open-bugs` | Homepage widget for scalar sum of open bugs. |
|
|
355
|
+
| `home-page-widget:scorecard/scorecard-entities-with-open-prs` | Homepage widget for scalar count of entities with open PRs. |
|
|
356
|
+
| `home-page-widget:scorecard/scorecard-avg-open-prs` | Homepage widget for scalar average open PRs. |
|
|
357
|
+
| `home-page-widget:scorecard/scorecard-dora-deployment-frequency` | Homepage widget for DORA deployment frequency sparkline (`doraDeploymentFrequencyKpi`). |
|
|
358
|
+
| `home-page-widget:scorecard/scorecard-dora-change-failure-rate` | Homepage widget for DORA change failure rate sparkline (`doraChangeFailureRateKpi`). |
|
|
359
|
+
| `home-page-widget:scorecard/scorecard-dora-median-lead-time-for-changes` | Homepage widget for DORA median lead time sparkline (`doraMedianLeadTimeForChangesKpi`). |
|
|
360
|
+
| `home-page-widget:scorecard/scorecard-dora-median-time-to-restore` | Homepage widget for DORA median time to restore sparkline (`doraMedianTimeToRestoreKpi`). |
|
|
342
361
|
|
|
343
362
|
##### Migration notes (NFS graduation)
|
|
344
363
|
|
|
@@ -509,7 +528,9 @@ The plugin exports **`ScorecardHomepageCard`** from `@red-hat-developer-hub/back
|
|
|
509
528
|
|
|
510
529
|
#### Backend configuration
|
|
511
530
|
|
|
512
|
-
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
|
|
531
|
+
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`. The default type is **`average`** when the metric’s **`defaultVisualization`** is **`sparkline`**, otherwise **`statusGrouped`**. A missing custom KPI key that is not a registered metric id returns **404**; the homepage card shows that error instead of staying in a loading state.
|
|
532
|
+
|
|
533
|
+
NFS `HomePageWidgetBlueprint`s are catalog presets with hardcoded ids. They are not the only way to put a card on the homepage: Dynamic Home Page / app-legacy can pass any `aggregationId`. Metric-id widgets (for example `filecheck.codeowners` or `dora.changeFailureRate`) work without an `aggregationKPIs` row. Custom KPI keys such as `avgDeploymentFrequency`, `licenseFileExistsKpi`, or `changeFailureRateKpi` must exist in app-config (or the metadata API returns 404).
|
|
513
534
|
|
|
514
535
|
Supported scorecard aggregation types (see [Entity Aggregation — Aggregation types](../scorecard-backend/docs/aggregation.md#aggregation-types)):
|
|
515
536
|
|
|
@@ -517,7 +538,7 @@ Supported scorecard aggregation types (see [Entity Aggregation — Aggregation t
|
|
|
517
538
|
- [`weightedStatusScore`](../scorecard-backend/docs/aggregation.md#weighted-status-score-type) — weighted portfolio health percentage (donut); requires `options.statusScores`.
|
|
518
539
|
- 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.
|
|
519
540
|
|
|
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
|
|
541
|
+
**Scalar KPI types** (`sum`, `average`, `max`, `min`, `count`) are fully supported by **`GET /aggregations/:aggregationId`**, including optional **`filter.status`** and **`options.thresholds`**. **`ScorecardHomepageCard`** first loads **`GET /aggregations/:aggregationId/metadata`**. When **`metadata.visualization`** is **`sparkline`**, it fetches **`GET /aggregations/:aggregationId/time-series`** and renders **`AggregatedSparklineCard`**. Otherwise **`AggregatedMetricCard`** chooses the UI from the snapshot **result shape**: a numeric `value` renders **`ScalarStatCard`** (large number, optional description, aggregation-type label, threshold tile color); 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.
|
|
521
542
|
|
|
522
543
|
**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`**.
|
|
523
544
|
|
|
@@ -528,7 +549,7 @@ Configure a scalar KPI such as **`maxOpenPrs`** under **`scorecard.aggregationKP
|
|
|
528
549
|
The supported model is **a single `aggregationId` string** whose value is either:
|
|
529
550
|
|
|
530
551
|
- a **KPI key** from **`scorecard.aggregationKPIs`** in app-config (custom title, description, type, backing metric), or
|
|
531
|
-
- a **metric id** when you have no KPI row for that card (default
|
|
552
|
+
- a **metric id** when you have no KPI row for that card (default **`average`** when the metric is a sparkline, otherwise **`statusGrouped`**).
|
|
532
553
|
|
|
533
554
|
| Prop | Status | Description |
|
|
534
555
|
| ------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
|
package/dist/alpha.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ declare const scorecardTranslationRef: _backstage_frontend_plugin_api.Translatio
|
|
|
19
19
|
readonly "permissionRequired.description": string;
|
|
20
20
|
readonly "permissionRequired.button": string;
|
|
21
21
|
readonly "permissionRequired.altText": string;
|
|
22
|
+
readonly "common.current": string;
|
|
22
23
|
readonly "common.loading": string;
|
|
23
24
|
readonly "errors.entityMissingProperties": string;
|
|
24
25
|
readonly "errors.missingAggregationId": string;
|
|
@@ -105,6 +106,9 @@ declare const scorecardTranslationRef: _backstage_frontend_plugin_api.Translatio
|
|
|
105
106
|
readonly "dataSourcesDialog.close": string;
|
|
106
107
|
readonly "dataSourcesDialog.unknownPlugin": string;
|
|
107
108
|
readonly "dataSourcesDialog.statusTooltip": string;
|
|
109
|
+
readonly "dataSourcesDialog.collectorStatusTooltip": string;
|
|
110
|
+
readonly "dataSourcesDialog.collectorEmptyValue": string;
|
|
111
|
+
readonly "dataSourcesDialog.collectorUnavailableStatus": string;
|
|
108
112
|
readonly "dataSourcesDialog.columns.plugin": string;
|
|
109
113
|
readonly "dataSourcesDialog.columns.check": string;
|
|
110
114
|
readonly "dataSourcesDialog.columns.value": string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScorecardQueryProvider.esm.js","sources":["../../src/api/ScorecardQueryProvider.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 { useMemo } from 'react';\nimport type { ReactNode } from 'react';\n\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\n\nlet queryClient: QueryClient | undefined;\n\nfunction getQueryClient() {\n if (!queryClient) {\n queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 5 * 60 * 1000, // 5 minutes\n gcTime: 5 * 60 * 1000, // 5 minutes\n retry: 1,\n refetchOnWindowFocus: false, // do not refetch when window regains focus\n },\n },\n });\n }\n return queryClient;\n}\n\n/**\n * uses a singleton QueryClient to ensure cache is shared across all scorecard components.\n * @public\n */\nexport const ScorecardQueryProvider = ({\n children,\n}: {\n readonly children: ReactNode;\n}) => {\n const client = useMemo(() => getQueryClient(), []);\n\n return <QueryClientProvider client={client}>{children}</QueryClientProvider>;\n};\n"],"names":[],"mappings":";;;;AAqBA,IAAI,WAAA;AAEJ,SAAS,cAAA,GAAiB;AACxB,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,WAAA,GAAc,IAAI,WAAA,CAAY;AAAA,MAC5B,cAAA,EAAgB;AAAA,QACd,OAAA,EAAS;AAAA,UACP,SAAA,EAAW,IAAI,EAAA,GAAK,GAAA;AAAA;AAAA,UACpB,MAAA,EAAQ,IAAI,EAAA,GAAK,GAAA;AAAA;AAAA,UACjB,KAAA,EAAO,CAAA;AAAA,UACP,oBAAA,EAAsB;AAAA;AAAA;AACxB;AACF,KACD,CAAA;AAAA,EACH;AACA,EAAA,OAAO,WAAA;AACT;AAMO,MAAM,yBAAyB,CAAC;AAAA,EACrC;AACF,CAAA,KAEM;AACJ,EAAA,MAAM,SAAS,OAAA,CAAQ,MAAM,cAAA,EAAe,EAAG,EAAE,CAAA;AAEjD,EAAA,uBAAO,GAAA,CAAC,mBAAA,EAAA,EAAoB,MAAA,EAAiB,QAAA,EAAS,CAAA;AACxD;;;;"}
|
|
1
|
+
{"version":3,"file":"ScorecardQueryProvider.esm.js","sources":["../../src/api/ScorecardQueryProvider.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 { useMemo } from 'react';\nimport type { ReactNode } from 'react';\n\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\n\nlet queryClient: QueryClient | undefined;\n\nfunction getQueryClient() {\n if (!queryClient) {\n queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 5 * 60 * 1000, // 5 minutes\n gcTime: 5 * 60 * 1000, // 5 minutes\n retry: 1,\n retryOnMount: false, // the query will not be retried on mount if it contains an error\n refetchOnWindowFocus: false, // do not refetch when window regains focus\n },\n },\n });\n }\n return queryClient;\n}\n\n/**\n * uses a singleton QueryClient to ensure cache is shared across all scorecard components.\n * @public\n */\nexport const ScorecardQueryProvider = ({\n children,\n}: {\n readonly children: ReactNode;\n}) => {\n const client = useMemo(() => getQueryClient(), []);\n\n return <QueryClientProvider client={client}>{children}</QueryClientProvider>;\n};\n"],"names":[],"mappings":";;;;AAqBA,IAAI,WAAA;AAEJ,SAAS,cAAA,GAAiB;AACxB,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,WAAA,GAAc,IAAI,WAAA,CAAY;AAAA,MAC5B,cAAA,EAAgB;AAAA,QACd,OAAA,EAAS;AAAA,UACP,SAAA,EAAW,IAAI,EAAA,GAAK,GAAA;AAAA;AAAA,UACpB,MAAA,EAAQ,IAAI,EAAA,GAAK,GAAA;AAAA;AAAA,UACjB,KAAA,EAAO,CAAA;AAAA,UACP,YAAA,EAAc,KAAA;AAAA;AAAA,UACd,oBAAA,EAAsB;AAAA;AAAA;AACxB;AACF,KACD,CAAA;AAAA,EACH;AACA,EAAA,OAAO,WAAA;AACT;AAMO,MAAM,yBAAyB,CAAC;AAAA,EACrC;AACF,CAAA,KAEM;AACJ,EAAA,MAAM,SAAS,OAAA,CAAQ,MAAM,cAAA,EAAe,EAAG,EAAE,CAAA;AAEjD,EAAA,uBAAO,GAAA,CAAC,mBAAA,EAAA,EAAoB,MAAA,EAAiB,QAAA,EAAS,CAAA;AACxD;;;;"}
|
package/dist/api/index.esm.js
CHANGED
|
@@ -239,6 +239,168 @@ class ScorecardApiClient {
|
|
|
239
239
|
);
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
|
+
async getAggregationTimeSeries({
|
|
243
|
+
aggregationId,
|
|
244
|
+
from,
|
|
245
|
+
to
|
|
246
|
+
}) {
|
|
247
|
+
if (!aggregationId || aggregationId.trim() === "") {
|
|
248
|
+
throw new Error(
|
|
249
|
+
"Aggregation ID is required for aggregation time-series lookup"
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
if (!from || !to) {
|
|
253
|
+
throw new Error(
|
|
254
|
+
"from and to are required for aggregation time-series lookup"
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
const baseUrl = await this.getBaseUrl();
|
|
258
|
+
const url = new URL(`${baseUrl}/aggregations/${aggregationId}/time-series`);
|
|
259
|
+
url.searchParams.set("from", from);
|
|
260
|
+
url.searchParams.set("to", to);
|
|
261
|
+
try {
|
|
262
|
+
const response = await this.fetchApi.fetch(url.toString());
|
|
263
|
+
if (!response.ok) {
|
|
264
|
+
const errorText = await response.text();
|
|
265
|
+
throw new Error(
|
|
266
|
+
`Failed to fetch aggregation time series: ${response.status} ${response.statusText}. ${errorText}`
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
const data = await response.json();
|
|
270
|
+
if (!data || Array.isArray(data) || typeof data !== "object" || typeof data.id !== "string" || typeof data.metricId !== "string" || !Array.isArray(data.points) || !data.points.every(isScalarAggregatedTimeSeriesPoint)) {
|
|
271
|
+
throw new TypeError(
|
|
272
|
+
"Invalid response format from aggregation time-series API"
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
return data;
|
|
276
|
+
} catch (error) {
|
|
277
|
+
if (error instanceof Error) {
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
throw new Error(
|
|
281
|
+
`Unexpected error fetching aggregation time series: ${String(error)}`
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
async getMetricTimeSeries({
|
|
286
|
+
entity,
|
|
287
|
+
metricId,
|
|
288
|
+
from,
|
|
289
|
+
to
|
|
290
|
+
}) {
|
|
291
|
+
if (!entity?.kind || !entity?.metadata?.namespace || !entity?.metadata?.name) {
|
|
292
|
+
throw new Error(
|
|
293
|
+
"Entity missing required properties for scorecard lookup"
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
if (!metricId || metricId.trim() === "") {
|
|
297
|
+
throw new Error("Metric ID is required for time-series lookup");
|
|
298
|
+
}
|
|
299
|
+
if (!from || !to) {
|
|
300
|
+
throw new Error("from and to are required for time-series lookup");
|
|
301
|
+
}
|
|
302
|
+
const baseUrl = await this.getBaseUrl();
|
|
303
|
+
const url = new URL(
|
|
304
|
+
`${baseUrl}/metrics/catalog/${entity.kind}/${entity.metadata.namespace}/${entity.metadata.name}/time-series`
|
|
305
|
+
);
|
|
306
|
+
url.searchParams.set("metricId", metricId);
|
|
307
|
+
url.searchParams.set("from", from);
|
|
308
|
+
url.searchParams.set("to", to);
|
|
309
|
+
try {
|
|
310
|
+
const response = await this.fetchApi.fetch(url.toString());
|
|
311
|
+
if (!response.ok) {
|
|
312
|
+
const errorText = await response.text();
|
|
313
|
+
throw new Error(
|
|
314
|
+
`Failed to fetch metric time series: ${response.status} ${response.statusText}. ${errorText}`
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
const data = await response.json();
|
|
318
|
+
if (!data || Array.isArray(data) || typeof data !== "object" || typeof data.metricId !== "string" || typeof data.entityRef !== "string" || !Array.isArray(data.points) || !data.points.every(isMetricTimeSeriesPoint) || !isOptionalThresholds(data.thresholds) || !isOptionalThresholdsError(data.thresholdsError)) {
|
|
319
|
+
throw new TypeError(
|
|
320
|
+
"Invalid response format from metric time-series API"
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
return data;
|
|
324
|
+
} catch (error) {
|
|
325
|
+
if (error instanceof Error) {
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
328
|
+
throw new Error(
|
|
329
|
+
`Unexpected error fetching metric time series: ${String(error)}`
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async getMetricCollectors(metricId) {
|
|
334
|
+
if (!metricId || metricId.trim() === "") {
|
|
335
|
+
throw new Error("Metric ID is required for collectors lookup");
|
|
336
|
+
}
|
|
337
|
+
const baseUrl = await this.getBaseUrl();
|
|
338
|
+
const url = `${baseUrl}/metrics/${encodeURIComponent(metricId)}/collectors`;
|
|
339
|
+
try {
|
|
340
|
+
const response = await this.fetchApi.fetch(url);
|
|
341
|
+
if (!response.ok) {
|
|
342
|
+
const errorText = await response.text();
|
|
343
|
+
throw new Error(
|
|
344
|
+
`Failed to fetch metric collectors: ${response.status} ${response.statusText}. ${errorText}`
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
const data = await response.json();
|
|
348
|
+
if (!data || Array.isArray(data) || typeof data !== "object" || !Array.isArray(data.collectors) || !data.collectors.every(isCollectorMetadata)) {
|
|
349
|
+
throw new TypeError(
|
|
350
|
+
"Invalid response format from metric collectors API"
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
return data.collectors;
|
|
354
|
+
} catch (error) {
|
|
355
|
+
if (error instanceof Error) {
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
throw new Error(
|
|
359
|
+
`Unexpected error fetching metric collectors: ${String(error)}`
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
function isCollectorMetadata(value) {
|
|
365
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
const collector = value;
|
|
369
|
+
return typeof collector.id === "string" && typeof collector.description === "string";
|
|
370
|
+
}
|
|
371
|
+
const isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
372
|
+
const isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
373
|
+
const isNullableFiniteNumber = (value) => value === null || isFiniteNumber(value);
|
|
374
|
+
const hasTimeSeriesPointShape = (value, isValidValue) => isRecord(value) && typeof value.timestamp === "string" && isValidValue(value.value);
|
|
375
|
+
function isThresholdRule(value) {
|
|
376
|
+
return isRecord(value) && typeof value.key === "string" && typeof value.expression === "string" && (value.color === void 0 || typeof value.color === "string") && (value.icon === void 0 || typeof value.icon === "string");
|
|
377
|
+
}
|
|
378
|
+
function isThresholdConfig(value) {
|
|
379
|
+
return isRecord(value) && Array.isArray(value.rules) && value.rules.every(isThresholdRule);
|
|
380
|
+
}
|
|
381
|
+
function isOptionalThresholds(value) {
|
|
382
|
+
return value === void 0 || isThresholdConfig(value);
|
|
383
|
+
}
|
|
384
|
+
function isOptionalThresholdsError(value) {
|
|
385
|
+
return value === void 0 || typeof value === "string";
|
|
386
|
+
}
|
|
387
|
+
function isMetricTimeSeriesPoint(value) {
|
|
388
|
+
return hasTimeSeriesPointShape(
|
|
389
|
+
value,
|
|
390
|
+
(pointValue) => isNullableFiniteNumber(pointValue) || typeof pointValue === "boolean"
|
|
391
|
+
) && (value.error === void 0 || typeof value.error === "string") && (value.thresholdEvaluation === void 0 || value.thresholdEvaluation === null || typeof value.thresholdEvaluation === "string");
|
|
392
|
+
}
|
|
393
|
+
function isTimeSeriesPointError(value) {
|
|
394
|
+
return isRecord(value) && typeof value.message === "string" && isFiniteNumber(value.count);
|
|
395
|
+
}
|
|
396
|
+
function isScalarAggregatedTimeSeriesPoint(value) {
|
|
397
|
+
if (!hasTimeSeriesPointShape(value, isNullableFiniteNumber)) {
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
if (!isFiniteNumber(value.successCount) || !isFiniteNumber(value.errorCount) || !isFiniteNumber(value.total) || value.status !== "success" && value.status !== "error") {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
return value.errors === void 0 || Array.isArray(value.errors) && value.errors.every(isTimeSeriesPointError);
|
|
242
404
|
}
|
|
243
405
|
|
|
244
406
|
export { ScorecardApiClient, scorecardApiRef };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../../src/api/index.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 createApiRef,\n FetchApi,\n DiscoveryApi,\n} from '@backstage/core-plugin-api';\nimport type {\n MetricResult,\n AggregatedMetricResult,\n AggregationMetadata,\n Metric,\n EntityMetricDetailResponse,\n} from '@red-hat-developer-hub/backstage-plugin-scorecard-common';\n\nimport type { GetAggregatedScorecardEntitiesOptions } from '../components/types';\n\nexport { ScorecardQueryProvider } from './ScorecardQueryProvider';\n\nimport type {\n ScorecardApi,\n ScorecardApiClientOptions,\n ScorecardOptions,\n} from './types';\n\nexport const scorecardApiRef = createApiRef<ScorecardApi>({\n id: 'plugin.scorecard.service',\n});\n\n/**\n * Client implementation for the Scorecard API.\n * @public\n */\nexport class ScorecardApiClient implements ScorecardApi {\n private readonly fetchApi: FetchApi;\n private readonly discoveryApi: DiscoveryApi;\n\n constructor(options: ScorecardApiClientOptions) {\n this.fetchApi = options.fetchApi;\n this.discoveryApi = options.discoveryApi;\n }\n\n async getBaseUrl(): Promise<string> {\n return await this.discoveryApi.getBaseUrl('scorecard');\n }\n\n async getScorecards({\n entity,\n metricIds,\n }: ScorecardOptions): Promise<MetricResult[]> {\n if (\n !entity?.kind ||\n !entity?.metadata?.namespace ||\n !entity?.metadata?.name\n ) {\n throw new Error(\n 'Entity missing required properties for scorecard lookup',\n );\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(\n `${baseUrl}/metrics/catalog/${entity.kind}/${entity.metadata.namespace}/${entity.metadata.name}`,\n );\n\n if (metricIds) {\n url.searchParams.set('metricIds', metricIds.join(','));\n }\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch scorecards: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (!Array.isArray(data)) {\n throw new Error('Invalid response format from scorecard API');\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error fetching scorecards: ${String(error)}`);\n }\n }\n\n async getAggregatedScorecard(\n aggregationId: string,\n ): Promise<AggregatedMetricResult> {\n if (!aggregationId || aggregationId.trim() === '') {\n throw new Error('Aggregation ID is required for aggregated scorecards');\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(`${baseUrl}/aggregations/${aggregationId}`);\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch aggregated scorecards: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (\n !data ||\n Array.isArray(data) ||\n typeof data !== 'object' ||\n !('result' in data) ||\n !('metadata' in data) ||\n !('id' in data) ||\n !('status' in data)\n ) {\n throw new TypeError(\n 'Invalid response format from aggregated scorecard API',\n );\n }\n\n const resultRaw = data.result;\n if (\n resultRaw === null ||\n typeof resultRaw !== 'object' ||\n Array.isArray(resultRaw)\n ) {\n throw new TypeError(\n 'Invalid response format from aggregated scorecard API: result must be a non-null object',\n );\n }\n\n const requireFiniteNumber = (value: unknown, fieldName: string) => {\n const n = Number(value ?? 0);\n if (!Number.isFinite(n)) {\n throw new TypeError(\n `Invalid aggregated scorecard API response: ${fieldName} must be a finite number`,\n );\n }\n return n;\n };\n\n const resultRecord = resultRaw as Record<string, unknown>;\n const timestampValue = resultRecord.timestamp;\n let timestamp: string;\n if (typeof timestampValue === 'string') {\n timestamp = timestampValue;\n } else if (\n typeof timestampValue === 'number' &&\n Number.isFinite(timestampValue)\n ) {\n timestamp = String(timestampValue);\n } else if (typeof timestampValue === 'bigint') {\n timestamp = timestampValue.toString();\n } else if (timestampValue instanceof Date) {\n timestamp = timestampValue.toISOString();\n } else {\n timestamp = '';\n }\n\n return {\n ...data,\n result: {\n ...resultRecord,\n total: requireFiniteNumber(resultRecord.total, 'total'),\n entitiesConsidered: requireFiniteNumber(\n resultRecord.entitiesConsidered,\n 'entitiesConsidered',\n ),\n calculationErrorCount: requireFiniteNumber(\n resultRecord.calculationErrorCount,\n 'calculationErrorCount',\n ),\n timestamp,\n },\n } as AggregatedMetricResult;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(\n `Unexpected error fetching aggregated scorecards: ${String(error)}`,\n );\n }\n }\n\n async getMetrics(options?: {\n metricIds?: string[];\n }): Promise<{ metrics: Metric[] }> {\n const { metricIds } = options || {};\n\n const isMetricIds =\n metricIds && Array.isArray(metricIds) && metricIds.length > 0;\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(`${baseUrl}/metrics`);\n\n if (isMetricIds) {\n url.searchParams.set('metricIds', metricIds.join(','));\n }\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch metric: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (\n !data ||\n Array.isArray(data) ||\n typeof data !== 'object' ||\n !('metrics' in data) ||\n !Array.isArray(data.metrics)\n ) {\n throw new TypeError('Invalid response format from metrics API');\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error fetching metric: ${String(error)}`);\n }\n }\n\n async getAggregatedScorecardEntities(\n options: GetAggregatedScorecardEntitiesOptions,\n ): Promise<EntityMetricDetailResponse> {\n const {\n metricId,\n page,\n pageSize,\n ownershipEntityRefs = [],\n orderBy = null,\n order = 'asc',\n } = options;\n\n if (!metricId) {\n throw new Error('Metric ID is required for aggregated scorecards');\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(\n `${baseUrl}/metrics/${metricId}/catalog/aggregations/entities`,\n );\n if (page) {\n url.searchParams.append('page', page.toString());\n }\n if (pageSize) {\n url.searchParams.append('pageSize', pageSize.toString());\n }\n if (ownershipEntityRefs.length > 0) {\n for (const ownershipEntityRef of ownershipEntityRefs) {\n url.searchParams.append('owner', ownershipEntityRef);\n }\n }\n if (orderBy) {\n url.searchParams.append('sortBy', orderBy);\n url.searchParams.append('sortOrder', order);\n }\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch aggregated scorecards: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (!data || Array.isArray(data) || typeof data !== 'object') {\n throw new TypeError(\n 'Invalid response format from aggregated scorecard API',\n );\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(\n `Unexpected error fetching aggregated scorecards: ${String(error)}`,\n );\n }\n }\n\n async getAggregationMetadata(\n aggregationId: string,\n ): Promise<AggregationMetadata> {\n if (!aggregationId || aggregationId.trim() === '') {\n throw new Error('Aggregation ID is required for aggregation metadata');\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(`${baseUrl}/aggregations/${aggregationId}/metadata`);\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch aggregation metadata: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (\n !data ||\n Array.isArray(data) ||\n typeof data !== 'object' ||\n !('title' in data) ||\n !('description' in data) ||\n !('type' in data) ||\n !('aggregationType' in data)\n ) {\n throw new TypeError(\n 'Invalid response format from aggregation metadata API',\n );\n }\n\n return data as AggregationMetadata;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(\n `Unexpected error fetching aggregation metadata: ${String(error)}`,\n );\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../../src/api/index.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 createApiRef,\n FetchApi,\n DiscoveryApi,\n} from '@backstage/core-plugin-api';\nimport type {\n MetricResult,\n AggregatedMetricResult,\n AggregationMetadata,\n Metric,\n EntityMetricDetailResponse,\n MetricTimeSeriesResponse,\n MetricTimeSeriesPoint,\n AggregatedMetricTimeSeriesResponse,\n ScalarAggregatedTimeSeriesPoint,\n AggregatedTimeSeriesPointError,\n CollectorMetadata,\n ThresholdConfig,\n ThresholdRule,\n} from '@red-hat-developer-hub/backstage-plugin-scorecard-common';\n\nimport type { GetAggregatedScorecardEntitiesOptions } from '../components/types';\n\nexport { ScorecardQueryProvider } from './ScorecardQueryProvider';\n\nimport type {\n GetAggregationTimeSeriesOptions,\n GetMetricTimeSeriesOptions,\n ScorecardApi,\n ScorecardApiClientOptions,\n ScorecardOptions,\n} from './types';\n\nexport const scorecardApiRef = createApiRef<ScorecardApi>({\n id: 'plugin.scorecard.service',\n});\n\n/**\n * Client implementation for the Scorecard API.\n * @public\n */\nexport class ScorecardApiClient implements ScorecardApi {\n private readonly fetchApi: FetchApi;\n private readonly discoveryApi: DiscoveryApi;\n\n constructor(options: ScorecardApiClientOptions) {\n this.fetchApi = options.fetchApi;\n this.discoveryApi = options.discoveryApi;\n }\n\n async getBaseUrl(): Promise<string> {\n return await this.discoveryApi.getBaseUrl('scorecard');\n }\n\n async getScorecards({\n entity,\n metricIds,\n }: ScorecardOptions): Promise<MetricResult[]> {\n if (\n !entity?.kind ||\n !entity?.metadata?.namespace ||\n !entity?.metadata?.name\n ) {\n throw new Error(\n 'Entity missing required properties for scorecard lookup',\n );\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(\n `${baseUrl}/metrics/catalog/${entity.kind}/${entity.metadata.namespace}/${entity.metadata.name}`,\n );\n\n if (metricIds) {\n url.searchParams.set('metricIds', metricIds.join(','));\n }\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch scorecards: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (!Array.isArray(data)) {\n throw new Error('Invalid response format from scorecard API');\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error fetching scorecards: ${String(error)}`);\n }\n }\n\n async getAggregatedScorecard(\n aggregationId: string,\n ): Promise<AggregatedMetricResult> {\n if (!aggregationId || aggregationId.trim() === '') {\n throw new Error('Aggregation ID is required for aggregated scorecards');\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(`${baseUrl}/aggregations/${aggregationId}`);\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch aggregated scorecards: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (\n !data ||\n Array.isArray(data) ||\n typeof data !== 'object' ||\n !('result' in data) ||\n !('metadata' in data) ||\n !('id' in data) ||\n !('status' in data)\n ) {\n throw new TypeError(\n 'Invalid response format from aggregated scorecard API',\n );\n }\n\n const resultRaw = data.result;\n if (\n resultRaw === null ||\n typeof resultRaw !== 'object' ||\n Array.isArray(resultRaw)\n ) {\n throw new TypeError(\n 'Invalid response format from aggregated scorecard API: result must be a non-null object',\n );\n }\n\n const requireFiniteNumber = (value: unknown, fieldName: string) => {\n const n = Number(value ?? 0);\n if (!Number.isFinite(n)) {\n throw new TypeError(\n `Invalid aggregated scorecard API response: ${fieldName} must be a finite number`,\n );\n }\n return n;\n };\n\n const resultRecord = resultRaw as Record<string, unknown>;\n const timestampValue = resultRecord.timestamp;\n let timestamp: string;\n if (typeof timestampValue === 'string') {\n timestamp = timestampValue;\n } else if (\n typeof timestampValue === 'number' &&\n Number.isFinite(timestampValue)\n ) {\n timestamp = String(timestampValue);\n } else if (typeof timestampValue === 'bigint') {\n timestamp = timestampValue.toString();\n } else if (timestampValue instanceof Date) {\n timestamp = timestampValue.toISOString();\n } else {\n timestamp = '';\n }\n\n return {\n ...data,\n result: {\n ...resultRecord,\n total: requireFiniteNumber(resultRecord.total, 'total'),\n entitiesConsidered: requireFiniteNumber(\n resultRecord.entitiesConsidered,\n 'entitiesConsidered',\n ),\n calculationErrorCount: requireFiniteNumber(\n resultRecord.calculationErrorCount,\n 'calculationErrorCount',\n ),\n timestamp,\n },\n } as AggregatedMetricResult;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(\n `Unexpected error fetching aggregated scorecards: ${String(error)}`,\n );\n }\n }\n\n async getMetrics(options?: {\n metricIds?: string[];\n }): Promise<{ metrics: Metric[] }> {\n const { metricIds } = options || {};\n\n const isMetricIds =\n metricIds && Array.isArray(metricIds) && metricIds.length > 0;\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(`${baseUrl}/metrics`);\n\n if (isMetricIds) {\n url.searchParams.set('metricIds', metricIds.join(','));\n }\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch metric: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (\n !data ||\n Array.isArray(data) ||\n typeof data !== 'object' ||\n !('metrics' in data) ||\n !Array.isArray(data.metrics)\n ) {\n throw new TypeError('Invalid response format from metrics API');\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error fetching metric: ${String(error)}`);\n }\n }\n\n async getAggregatedScorecardEntities(\n options: GetAggregatedScorecardEntitiesOptions,\n ): Promise<EntityMetricDetailResponse> {\n const {\n metricId,\n page,\n pageSize,\n ownershipEntityRefs = [],\n orderBy = null,\n order = 'asc',\n } = options;\n\n if (!metricId) {\n throw new Error('Metric ID is required for aggregated scorecards');\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(\n `${baseUrl}/metrics/${metricId}/catalog/aggregations/entities`,\n );\n if (page) {\n url.searchParams.append('page', page.toString());\n }\n if (pageSize) {\n url.searchParams.append('pageSize', pageSize.toString());\n }\n if (ownershipEntityRefs.length > 0) {\n for (const ownershipEntityRef of ownershipEntityRefs) {\n url.searchParams.append('owner', ownershipEntityRef);\n }\n }\n if (orderBy) {\n url.searchParams.append('sortBy', orderBy);\n url.searchParams.append('sortOrder', order);\n }\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch aggregated scorecards: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (!data || Array.isArray(data) || typeof data !== 'object') {\n throw new TypeError(\n 'Invalid response format from aggregated scorecard API',\n );\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(\n `Unexpected error fetching aggregated scorecards: ${String(error)}`,\n );\n }\n }\n\n async getAggregationMetadata(\n aggregationId: string,\n ): Promise<AggregationMetadata> {\n if (!aggregationId || aggregationId.trim() === '') {\n throw new Error('Aggregation ID is required for aggregation metadata');\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(`${baseUrl}/aggregations/${aggregationId}/metadata`);\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch aggregation metadata: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (\n !data ||\n Array.isArray(data) ||\n typeof data !== 'object' ||\n !('title' in data) ||\n !('description' in data) ||\n !('type' in data) ||\n !('aggregationType' in data)\n ) {\n throw new TypeError(\n 'Invalid response format from aggregation metadata API',\n );\n }\n\n return data as AggregationMetadata;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(\n `Unexpected error fetching aggregation metadata: ${String(error)}`,\n );\n }\n }\n\n async getAggregationTimeSeries({\n aggregationId,\n from,\n to,\n }: GetAggregationTimeSeriesOptions): Promise<AggregatedMetricTimeSeriesResponse> {\n if (!aggregationId || aggregationId.trim() === '') {\n throw new Error(\n 'Aggregation ID is required for aggregation time-series lookup',\n );\n }\n\n if (!from || !to) {\n throw new Error(\n 'from and to are required for aggregation time-series lookup',\n );\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(`${baseUrl}/aggregations/${aggregationId}/time-series`);\n url.searchParams.set('from', from);\n url.searchParams.set('to', to);\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch aggregation time series: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (\n !data ||\n Array.isArray(data) ||\n typeof data !== 'object' ||\n typeof data.id !== 'string' ||\n typeof data.metricId !== 'string' ||\n !Array.isArray(data.points) ||\n !data.points.every(isScalarAggregatedTimeSeriesPoint)\n ) {\n throw new TypeError(\n 'Invalid response format from aggregation time-series API',\n );\n }\n\n return data as AggregatedMetricTimeSeriesResponse;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(\n `Unexpected error fetching aggregation time series: ${String(error)}`,\n );\n }\n }\n\n async getMetricTimeSeries({\n entity,\n metricId,\n from,\n to,\n }: GetMetricTimeSeriesOptions): Promise<MetricTimeSeriesResponse> {\n if (\n !entity?.kind ||\n !entity?.metadata?.namespace ||\n !entity?.metadata?.name\n ) {\n throw new Error(\n 'Entity missing required properties for scorecard lookup',\n );\n }\n\n if (!metricId || metricId.trim() === '') {\n throw new Error('Metric ID is required for time-series lookup');\n }\n\n if (!from || !to) {\n throw new Error('from and to are required for time-series lookup');\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = new URL(\n `${baseUrl}/metrics/catalog/${entity.kind}/${entity.metadata.namespace}/${entity.metadata.name}/time-series`,\n );\n url.searchParams.set('metricId', metricId);\n url.searchParams.set('from', from);\n url.searchParams.set('to', to);\n\n try {\n const response = await this.fetchApi.fetch(url.toString());\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch metric time series: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (\n !data ||\n Array.isArray(data) ||\n typeof data !== 'object' ||\n typeof data.metricId !== 'string' ||\n typeof data.entityRef !== 'string' ||\n !Array.isArray(data.points) ||\n !data.points.every(isMetricTimeSeriesPoint) ||\n !isOptionalThresholds(data.thresholds) ||\n !isOptionalThresholdsError(data.thresholdsError)\n ) {\n throw new TypeError(\n 'Invalid response format from metric time-series API',\n );\n }\n\n return data as MetricTimeSeriesResponse;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(\n `Unexpected error fetching metric time series: ${String(error)}`,\n );\n }\n }\n\n async getMetricCollectors(metricId: string): Promise<CollectorMetadata[]> {\n if (!metricId || metricId.trim() === '') {\n throw new Error('Metric ID is required for collectors lookup');\n }\n\n const baseUrl = await this.getBaseUrl();\n const url = `${baseUrl}/metrics/${encodeURIComponent(metricId)}/collectors`;\n\n try {\n const response = await this.fetchApi.fetch(url);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch metric collectors: ${response.status} ${response.statusText}. ${errorText}`,\n );\n }\n\n const data = await response.json();\n\n if (\n !data ||\n Array.isArray(data) ||\n typeof data !== 'object' ||\n !Array.isArray(data.collectors) ||\n !data.collectors.every(isCollectorMetadata)\n ) {\n throw new TypeError(\n 'Invalid response format from metric collectors API',\n );\n }\n\n return data.collectors;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(\n `Unexpected error fetching metric collectors: ${String(error)}`,\n );\n }\n }\n}\n\nfunction isCollectorMetadata(value: unknown): value is CollectorMetadata {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n\n const collector = value as Record<string, unknown>;\n return (\n typeof collector.id === 'string' &&\n typeof collector.description === 'string'\n );\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n\nconst isFiniteNumber = (value: unknown): value is number =>\n typeof value === 'number' && Number.isFinite(value);\n\nconst isNullableFiniteNumber = (value: unknown): value is number | null =>\n value === null || isFiniteNumber(value);\n\nconst hasTimeSeriesPointShape = (\n value: unknown,\n isValidValue: (pointValue: unknown) => boolean,\n): value is Record<string, unknown> =>\n isRecord(value) &&\n typeof value.timestamp === 'string' &&\n isValidValue(value.value);\n\nfunction isThresholdRule(value: unknown): value is ThresholdRule {\n return (\n isRecord(value) &&\n typeof value.key === 'string' &&\n typeof value.expression === 'string' &&\n (value.color === undefined || typeof value.color === 'string') &&\n (value.icon === undefined || typeof value.icon === 'string')\n );\n}\n\nfunction isThresholdConfig(value: unknown): value is ThresholdConfig {\n return (\n isRecord(value) &&\n Array.isArray(value.rules) &&\n value.rules.every(isThresholdRule)\n );\n}\n\nfunction isOptionalThresholds(\n value: unknown,\n): value is ThresholdConfig | undefined {\n return value === undefined || isThresholdConfig(value);\n}\n\nfunction isOptionalThresholdsError(\n value: unknown,\n): value is string | undefined {\n return value === undefined || typeof value === 'string';\n}\n\nfunction isMetricTimeSeriesPoint(\n value: unknown,\n): value is MetricTimeSeriesPoint {\n return (\n hasTimeSeriesPointShape(\n value,\n pointValue =>\n isNullableFiniteNumber(pointValue) || typeof pointValue === 'boolean',\n ) &&\n (value.error === undefined || typeof value.error === 'string') &&\n (value.thresholdEvaluation === undefined ||\n value.thresholdEvaluation === null ||\n typeof value.thresholdEvaluation === 'string')\n );\n}\n\nfunction isTimeSeriesPointError(\n value: unknown,\n): value is AggregatedTimeSeriesPointError {\n return (\n isRecord(value) &&\n typeof value.message === 'string' &&\n isFiniteNumber(value.count)\n );\n}\n\nfunction isScalarAggregatedTimeSeriesPoint(\n value: unknown,\n): value is ScalarAggregatedTimeSeriesPoint {\n if (!hasTimeSeriesPointShape(value, isNullableFiniteNumber)) {\n return false;\n }\n\n if (\n !isFiniteNumber(value.successCount) ||\n !isFiniteNumber(value.errorCount) ||\n !isFiniteNumber(value.total) ||\n (value.status !== 'success' && value.status !== 'error')\n ) {\n return false;\n }\n\n return (\n value.errors === undefined ||\n (Array.isArray(value.errors) && value.errors.every(isTimeSeriesPointError))\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { useTheme } from '@mui/material/styles';
|
|
4
|
+
import { CardWrapper } from '../Common/CardWrapper.esm.js';
|
|
5
|
+
import { SparklineChart } from '../SparklineChart/SparklineChart.esm.js';
|
|
6
|
+
import '@mui/material/Box';
|
|
7
|
+
import '@mui/material/Typography';
|
|
8
|
+
import { SparklineDataSources } from '../SparklineChart/SparklineDataSources.esm.js';
|
|
9
|
+
import { CardInfoButton } from './components/CardInfoButton.esm.js';
|
|
10
|
+
import { CardSubheader } from './components/CardSubheader.esm.js';
|
|
11
|
+
import { useLanguage } from '../../hooks/useLanguage.esm.js';
|
|
12
|
+
import { useTranslation } from '../../hooks/useTranslation.esm.js';
|
|
13
|
+
import { SCORECARD_ERROR_STATE_COLOR } from '../../utils/constants.esm.js';
|
|
14
|
+
import 'date-fns';
|
|
15
|
+
import { toAggregationSparklinePoints } from '../../utils/timeSeriesChartData.esm.js';
|
|
16
|
+
import '@red-hat-developer-hub/backstage-plugin-scorecard-common';
|
|
17
|
+
import { resolveStatusColor } from '../../utils/statusUtils.esm.js';
|
|
18
|
+
import { getThresholdRuleColor } from '../../utils/thresholdUtils.esm.js';
|
|
19
|
+
import { toSparklineChartModel, formatSparklineDateLabel } from '../../utils/sparklineChartModel.esm.js';
|
|
20
|
+
|
|
21
|
+
const AggregatedSparklineCard = ({
|
|
22
|
+
series,
|
|
23
|
+
aggregationId,
|
|
24
|
+
cardTitle,
|
|
25
|
+
description,
|
|
26
|
+
showSubheader = true,
|
|
27
|
+
showInfo = true,
|
|
28
|
+
dataTestId,
|
|
29
|
+
showCurrentValue = false
|
|
30
|
+
}) => {
|
|
31
|
+
const theme = useTheme();
|
|
32
|
+
const locale = useLanguage();
|
|
33
|
+
const { t } = useTranslation();
|
|
34
|
+
const lastPoint = series.points[series.points.length - 1];
|
|
35
|
+
const thresholdRules = series.thresholds?.rules;
|
|
36
|
+
const chartColorToken = series.aggregationChartDisplayColor;
|
|
37
|
+
const matchingThresholdKey = chartColorToken ? thresholdRules?.find(
|
|
38
|
+
(rule) => getThresholdRuleColor(thresholdRules, rule.key) === chartColorToken
|
|
39
|
+
)?.key : void 0;
|
|
40
|
+
const chartColor = resolveStatusColor(
|
|
41
|
+
theme,
|
|
42
|
+
chartColorToken ?? SCORECARD_ERROR_STATE_COLOR
|
|
43
|
+
);
|
|
44
|
+
const unit = series.metadata.unit;
|
|
45
|
+
const fallbackErrorLabel = t("errors.metricDataUnavailable");
|
|
46
|
+
const { chartData, strokeDasharray, legendItems } = useMemo(
|
|
47
|
+
() => toSparklineChartModel({
|
|
48
|
+
inputPoints: toAggregationSparklinePoints(
|
|
49
|
+
series.points,
|
|
50
|
+
fallbackErrorLabel
|
|
51
|
+
),
|
|
52
|
+
formatDateLabel: (timestamp) => formatSparklineDateLabel(timestamp, locale),
|
|
53
|
+
matchingThresholdKey,
|
|
54
|
+
chartColor,
|
|
55
|
+
unit,
|
|
56
|
+
theme,
|
|
57
|
+
t,
|
|
58
|
+
legendRules: thresholdRules
|
|
59
|
+
}),
|
|
60
|
+
[
|
|
61
|
+
series.points,
|
|
62
|
+
thresholdRules,
|
|
63
|
+
fallbackErrorLabel,
|
|
64
|
+
locale,
|
|
65
|
+
matchingThresholdKey,
|
|
66
|
+
chartColor,
|
|
67
|
+
unit,
|
|
68
|
+
theme,
|
|
69
|
+
t
|
|
70
|
+
]
|
|
71
|
+
);
|
|
72
|
+
const subheader = showSubheader && lastPoint ? /* @__PURE__ */ jsx(
|
|
73
|
+
CardSubheader,
|
|
74
|
+
{
|
|
75
|
+
aggregationId,
|
|
76
|
+
scorecardId: series.metricId,
|
|
77
|
+
entitiesCount: lastPoint.successCount,
|
|
78
|
+
entitiesConsidered: lastPoint.total,
|
|
79
|
+
calculationErrorCount: lastPoint.errorCount
|
|
80
|
+
}
|
|
81
|
+
) : null;
|
|
82
|
+
const info = showInfo ? /* @__PURE__ */ jsx(
|
|
83
|
+
SparklineDataSources,
|
|
84
|
+
{
|
|
85
|
+
title: cardTitle,
|
|
86
|
+
metricId: series.metricId,
|
|
87
|
+
lastSyncedTimestamp: lastPoint?.timestamp,
|
|
88
|
+
extraInfo: lastPoint ? /* @__PURE__ */ jsx(CardInfoButton, { timestamp: lastPoint.timestamp, marginRight: 0 }) : null
|
|
89
|
+
}
|
|
90
|
+
) : null;
|
|
91
|
+
return /* @__PURE__ */ jsx(
|
|
92
|
+
CardWrapper,
|
|
93
|
+
{
|
|
94
|
+
title: cardTitle,
|
|
95
|
+
dataTestId,
|
|
96
|
+
subheader,
|
|
97
|
+
description,
|
|
98
|
+
info,
|
|
99
|
+
children: /* @__PURE__ */ jsx(
|
|
100
|
+
SparklineChart,
|
|
101
|
+
{
|
|
102
|
+
data: chartData,
|
|
103
|
+
color: chartColor,
|
|
104
|
+
strokeDasharray,
|
|
105
|
+
unit,
|
|
106
|
+
testId: `sparkline-chart-${aggregationId}`,
|
|
107
|
+
legendItems,
|
|
108
|
+
legendTestId: `sparkline-threshold-legend-${aggregationId}`,
|
|
109
|
+
showCurrentValue
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export { AggregatedSparklineCard };
|
|
117
|
+
//# sourceMappingURL=AggregatedSparklineCard.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AggregatedSparklineCard.esm.js","sources":["../../../src/components/AggregatedMetricCards/AggregatedSparklineCard.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 { useMemo } from 'react';\nimport { useTheme } from '@mui/material/styles';\nimport type { AggregatedMetricTimeSeriesResponse } from '@red-hat-developer-hub/backstage-plugin-scorecard-common';\n\nimport { CardWrapper } from '../Common/CardWrapper';\nimport { SparklineChart } from '../SparklineChart';\nimport { SparklineDataSources } from '../SparklineChart/SparklineDataSources';\nimport { CardInfoButton } from './components/CardInfoButton';\nimport { CardSubheader } from './components/CardSubheader';\nimport { useLanguage } from '../../hooks/useLanguage';\nimport { useTranslation } from '../../hooks/useTranslation';\nimport {\n getThresholdRuleColor,\n resolveStatusColor,\n SCORECARD_ERROR_STATE_COLOR,\n toAggregationSparklinePoints,\n} from '../../utils';\nimport {\n formatSparklineDateLabel,\n toSparklineChartModel,\n} from '../../utils/sparklineChartModel';\nimport type { AggregatedMetricCardBaseProps } from './types';\n\nexport type AggregatedSparklineCardProps = AggregatedMetricCardBaseProps & {\n series: AggregatedMetricTimeSeriesResponse;\n showCurrentValue?: boolean;\n};\n\nexport const AggregatedSparklineCard = ({\n series,\n aggregationId,\n cardTitle,\n description,\n showSubheader = true,\n showInfo = true,\n dataTestId,\n showCurrentValue = false,\n}: AggregatedSparklineCardProps) => {\n const theme = useTheme();\n const locale = useLanguage();\n const { t } = useTranslation();\n\n const lastPoint = series.points[series.points.length - 1];\n const thresholdRules = series.thresholds?.rules;\n const chartColorToken = series.aggregationChartDisplayColor;\n const matchingThresholdKey = chartColorToken\n ? thresholdRules?.find(\n rule =>\n getThresholdRuleColor(thresholdRules, rule.key) === chartColorToken,\n )?.key\n : undefined;\n const chartColor = resolveStatusColor(\n theme,\n chartColorToken ?? SCORECARD_ERROR_STATE_COLOR,\n );\n\n const unit = series.metadata.unit;\n const fallbackErrorLabel = t('errors.metricDataUnavailable');\n const { chartData, strokeDasharray, legendItems } = useMemo(\n () =>\n toSparklineChartModel({\n inputPoints: toAggregationSparklinePoints(\n series.points,\n fallbackErrorLabel,\n ),\n formatDateLabel: timestamp =>\n formatSparklineDateLabel(timestamp, locale),\n matchingThresholdKey,\n chartColor,\n unit,\n theme,\n t,\n legendRules: thresholdRules,\n }),\n [\n series.points,\n thresholdRules,\n fallbackErrorLabel,\n locale,\n matchingThresholdKey,\n chartColor,\n unit,\n theme,\n t,\n ],\n );\n\n const subheader =\n showSubheader && lastPoint ? (\n <CardSubheader\n aggregationId={aggregationId}\n scorecardId={series.metricId}\n entitiesCount={lastPoint.successCount}\n entitiesConsidered={lastPoint.total}\n calculationErrorCount={lastPoint.errorCount}\n />\n ) : null;\n\n const info = showInfo ? (\n <SparklineDataSources\n title={cardTitle}\n metricId={series.metricId}\n lastSyncedTimestamp={lastPoint?.timestamp}\n extraInfo={\n lastPoint ? (\n <CardInfoButton timestamp={lastPoint.timestamp} marginRight={0} />\n ) : null\n }\n />\n ) : null;\n\n return (\n <CardWrapper\n title={cardTitle}\n dataTestId={dataTestId}\n subheader={subheader}\n description={description}\n info={info}\n >\n <SparklineChart\n data={chartData}\n color={chartColor}\n strokeDasharray={strokeDasharray}\n unit={unit}\n testId={`sparkline-chart-${aggregationId}`}\n legendItems={legendItems}\n legendTestId={`sparkline-threshold-legend-${aggregationId}`}\n showCurrentValue={showCurrentValue}\n />\n </CardWrapper>\n );\n};\n"],"names":[],"mappings":"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"}
|