@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.
Files changed (89) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +43 -22
  3. package/dist/alpha.d.ts +4 -0
  4. package/dist/api/ScorecardQueryProvider.esm.js +2 -0
  5. package/dist/api/ScorecardQueryProvider.esm.js.map +1 -1
  6. package/dist/api/index.esm.js +162 -0
  7. package/dist/api/index.esm.js.map +1 -1
  8. package/dist/components/AggregatedMetricCards/AggregatedSparklineCard.esm.js +117 -0
  9. package/dist/components/AggregatedMetricCards/AggregatedSparklineCard.esm.js.map +1 -0
  10. package/dist/components/AggregatedMetricCards/components/CardInfoButton.esm.js +36 -22
  11. package/dist/components/AggregatedMetricCards/components/CardInfoButton.esm.js.map +1 -1
  12. package/dist/components/MetricGroupCard/DataSourcesDialog.esm.js +26 -59
  13. package/dist/components/MetricGroupCard/DataSourcesDialog.esm.js.map +1 -1
  14. package/dist/components/MetricGroupCard/DataSourcesDialogColumns.esm.js +37 -23
  15. package/dist/components/MetricGroupCard/DataSourcesDialogColumns.esm.js.map +1 -1
  16. package/dist/components/MetricGroupCard/MetricGroupCard.esm.js +9 -1
  17. package/dist/components/MetricGroupCard/MetricGroupCard.esm.js.map +1 -1
  18. package/dist/components/MetricGroupCard/collectorSourceRows.esm.js +30 -0
  19. package/dist/components/MetricGroupCard/collectorSourceRows.esm.js.map +1 -0
  20. package/dist/components/MetricGroupCard/metricSourceRows.esm.js +44 -0
  21. package/dist/components/MetricGroupCard/metricSourceRows.esm.js.map +1 -0
  22. package/dist/components/Scorecard/EntityMetricCard.esm.js +64 -0
  23. package/dist/components/Scorecard/EntityMetricCard.esm.js.map +1 -0
  24. package/dist/components/Scorecard/EntityScorecardContent.esm.js +2 -47
  25. package/dist/components/Scorecard/EntityScorecardContent.esm.js.map +1 -1
  26. package/dist/components/Scorecard/EntitySparklineCard.esm.js +134 -0
  27. package/dist/components/Scorecard/EntitySparklineCard.esm.js.map +1 -0
  28. package/dist/components/Scorecard/ScorecardEntityContentGridView.esm.js +5 -45
  29. package/dist/components/Scorecard/ScorecardEntityContentGridView.esm.js.map +1 -1
  30. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js +66 -9
  31. package/dist/components/ScorecardHomepageSection/ScorecardHomepageCard.esm.js.map +1 -1
  32. package/dist/components/ScorecardPage/ScorecardPage.esm.js +2 -1
  33. package/dist/components/ScorecardPage/ScorecardPage.esm.js.map +1 -1
  34. package/dist/components/SparklineChart/SparklineChart.esm.js +260 -0
  35. package/dist/components/SparklineChart/SparklineChart.esm.js.map +1 -0
  36. package/dist/components/SparklineChart/SparklineCurrentValue.esm.js +55 -0
  37. package/dist/components/SparklineChart/SparklineCurrentValue.esm.js.map +1 -0
  38. package/dist/components/SparklineChart/SparklineDataSources.esm.js +23 -0
  39. package/dist/components/SparklineChart/SparklineDataSources.esm.js.map +1 -0
  40. package/dist/components/SparklineChart/SparklineLegend.esm.js +59 -0
  41. package/dist/components/SparklineChart/SparklineLegend.esm.js.map +1 -0
  42. package/dist/components/SparklineChart/SparklineTooltip.esm.js +59 -0
  43. package/dist/components/SparklineChart/SparklineTooltip.esm.js.map +1 -0
  44. package/dist/extensions/homePageCards.esm.js +71 -1
  45. package/dist/extensions/homePageCards.esm.js.map +1 -1
  46. package/dist/hooks/useAggregatedScorecard.esm.js +1 -1
  47. package/dist/hooks/useAggregatedScorecard.esm.js.map +1 -1
  48. package/dist/hooks/useAggregationMetadata.esm.js +3 -2
  49. package/dist/hooks/useAggregationMetadata.esm.js.map +1 -1
  50. package/dist/hooks/useAggregationTimeSeries.esm.js +50 -0
  51. package/dist/hooks/useAggregationTimeSeries.esm.js.map +1 -0
  52. package/dist/hooks/useMetricCollectors.esm.js +20 -0
  53. package/dist/hooks/useMetricCollectors.esm.js.map +1 -0
  54. package/dist/hooks/useMetricTimeSeries.esm.js +56 -0
  55. package/dist/hooks/useMetricTimeSeries.esm.js.map +1 -0
  56. package/dist/hooks/useSparklineDataSources.esm.js +71 -0
  57. package/dist/hooks/useSparklineDataSources.esm.js.map +1 -0
  58. package/dist/index.d.ts +45 -0
  59. package/dist/index.esm.js +7 -2
  60. package/dist/index.esm.js.map +1 -1
  61. package/dist/translations/de.esm.js +41 -37
  62. package/dist/translations/de.esm.js.map +1 -1
  63. package/dist/translations/es.esm.js +23 -19
  64. package/dist/translations/es.esm.js.map +1 -1
  65. package/dist/translations/fr.esm.js +19 -15
  66. package/dist/translations/fr.esm.js.map +1 -1
  67. package/dist/translations/it.esm.js +18 -14
  68. package/dist/translations/it.esm.js.map +1 -1
  69. package/dist/translations/ja.esm.js +18 -14
  70. package/dist/translations/ja.esm.js.map +1 -1
  71. package/dist/translations/ref.esm.js +5 -1
  72. package/dist/translations/ref.esm.js.map +1 -1
  73. package/dist/utils/constants.esm.js +2 -1
  74. package/dist/utils/constants.esm.js.map +1 -1
  75. package/dist/utils/formatMetricUnit.esm.js +8 -1
  76. package/dist/utils/formatMetricUnit.esm.js.map +1 -1
  77. package/dist/utils/metricVisualization.esm.js +4 -0
  78. package/dist/utils/metricVisualization.esm.js.map +1 -0
  79. package/dist/utils/sparklineChartModel.esm.js +28 -0
  80. package/dist/utils/sparklineChartModel.esm.js.map +1 -0
  81. package/dist/utils/sparklineLegend.esm.js +56 -0
  82. package/dist/utils/sparklineLegend.esm.js.map +1 -0
  83. package/dist/utils/timeSeriesChartData.esm.js +106 -0
  84. package/dist/utils/timeSeriesChartData.esm.js.map +1 -0
  85. package/dist/utils/timeSeriesRange.esm.js +13 -0
  86. package/dist/utils/timeSeriesRange.esm.js.map +1 -0
  87. package/dist/utils/translationUtils.esm.js +1 -1
  88. package/dist/utils/translationUtils.esm.js.map +1 -1
  89. 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 twelve widgets:
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 | Description |
325
- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
326
- | `api:scorecard` | Scorecard API (auto-discovered when the plugin is installed). |
327
- | `page:scorecard` | Scorecard entities / drill-down page. |
328
- | `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. |
329
- | `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). |
330
- | `home-page-widget:scorecard/scorecard-deprecated-metric-id` | Homepage widget using deprecated `metricId` (Jira open issues). |
331
- | `home-page-widget:scorecard/scorecard-default-aggregation` | Homepage widget using default aggregation (GitHub open PRs). |
332
- | `home-page-widget:scorecard/scorecard-jira-open-issues` | Homepage widget for Jira open blocking tickets. |
333
- | `home-page-widget:scorecard/scorecard-github-open-prs` | Homepage widget for GitHub open PRs. |
334
- | `home-page-widget:scorecard/scorecard-github-filecheck-license` | Homepage widget for file check "License". |
335
- | `home-page-widget:scorecard/scorecard-github-filecheck-codeowners` | Homepage widget for file check "Codeowners". |
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. |
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` (default status-grouped aggregation).
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 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.
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 **statusGrouped** aggregation and metric-defined metadata).
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;
@@ -13,6 +13,8 @@ function getQueryClient() {
13
13
  gcTime: 5 * 60 * 1e3,
14
14
  // 5 minutes
15
15
  retry: 1,
16
+ retryOnMount: false,
17
+ // the query will not be retried on mount if it contains an error
16
18
  refetchOnWindowFocus: false
17
19
  // do not refetch when window regains focus
18
20
  }
@@ -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;;;;"}
@@ -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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"}