Skip to content

feat(scorecard): Customize icons - #2641

Merged
dzemanov merged 9 commits into
redhat-developer:mainfrom
dzemanov:scorecard-threshold-icons
Apr 1, 2026
Merged

feat(scorecard): Customize icons#2641
dzemanov merged 9 commits into
redhat-developer:mainfrom
dzemanov:scorecard-threshold-icons

Conversation

@dzemanov

@dzemanov dzemanov commented Mar 30, 2026

Copy link
Copy Markdown
Member

Hey, I just made a Pull Request!

  • Introduces the ability to specify custom icons for Scorecard statuses.
    Reuses logic from HeaderIcon.
  • Adds scorecardSuccessStatusIcon, scorecardWarningStatusIcon, scorecardErrorStatusIcon to icons registry, following the naming convention of existing icons like ocmIcon, rbacIcon, and bulkImportIcon.
scorecard:
  plugins:
    myDatasource:
      myMetric:
        thresholds:
          rules:
            - key: success
              expression: '<10'
              icon: scorecardSuccessStatusIcon  # not needed to be specified
            - key: warning
              expression: '10-50'
              icon: '<svg xmlns="http://www.w3.org/2000/svg">...</svg>'
            - key: error
              expression: '>50'
              icon: 'customIcon'

Icon configuration - supports multiple formats:

  • Backstage system icons: 'kind:component', 'kind:api', etc.
  • Material Design icons: 'settings', 'home', 'build', etc.
  • SVG strings: '...'
  • URLs: 'https://example.com/icon.png', '/assets/icon.svg'
  • Data URIs: 'data:image/svg+xml;base64,...'

Threshold rules 'success', 'warning' and 'error' have default icons: scorecardSuccessStatusIcon, scorecardSuccessStatusIcon, scorecardSuccessStatusIcon.

Updated Scorecard configuration for RHDH:

dynamicPlugins:
  rootDirectory: dynamic-plugins-root
  frontend:

    red-hat-developer-hub.backstage-plugin-scorecard:
      entityTabs:
        - path: "/scorecard"
          title: Scorecard
          mountPoint: entity.page.scorecard
      mountPoints:
        - mountPoint: entity.page.scorecard/cards
          importName: EntityScorecardContent
          config:
            layout:
              gridColumn: 1 / -1
            if:
              allOf:
                - isKind: component
      appIcons:
        - name: scorecardSuccessStatusIcon
          importName: ScorecardSuccessStatusIcon
        - name: scorecardWarningStatusIcon
          importName: ScorecardWarningStatusIcon
        - name: scorecardErrorStatusIcon
          importName: ScorecardErrorStatusIcon

Fixes

https://redhat.atlassian.net/browse/RHIDP-12191

Demo

Screenshot 2026-03-27 at 17 13 08

How to test

Try out and uncomment these different icons:

scorecard:
  plugins:
    jira:
      open_issues:
        schedule:
          frequency: { minutes: 5 }
          timeout: { minutes: 10 }
          initialDelay: { seconds: 5 }
        thresholds:
          rules:
            - key: success
              expression: '<5'
            - key: warning
              expression: '<=20'
              # icon: scorecardWarningStatusIcon
              # icon: scorecardSuccessStatusIcon
              # icon: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" style="color:#02D8E9"><rect x="4" y="4" width="16" height="16" rx="2" stroke="#02D8E9" stroke-width="2"/><path d="M8 12l2.5 2.5L16 9" stroke="#02D8E9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'
              # icon: kind:component
              # icon: https://raw.githubusercontent.com/dzemanov/backstage-entities/main/icons/scorecard-icon.svg
              # icon: data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIj48cmVjdCB4PSI0IiB5PSI0IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHJ4PSIyIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIi8+PHBhdGggZD0iTTggMTJsMi41IDIuNUwxNiA5IiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L3N2Zz4=
              color: '#02D8E9'
            - key: error
              expression: '>20'

You can test this both in the old and new frontend system.
You can test this in RHDH:

  • run npx @red-hat-developer-hub/cli plugin export --dynamic-plugins-root /MyRoute/Projects/rhdh/dynamic-plugins-root --dev for each scorecard plugin (you can export only one of the modules)
  • see Updated Scorecard configuration for RHDH.

Note: color is not propagated correctly when using <svg or /http icons and will need to be specified in the icon itself. The logic for this is copied from HeaderIcon.

✔️ Checklist

  • A changeset describing the change and affected packages. (more info)
  • Added or Updated documentation
  • Tests for new functionality and regression tests for bug fixes
  • Screenshots attached (for UI changes)

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
@rhdh-gh-app

rhdh-gh-app Bot commented Mar 30, 2026

Copy link
Copy Markdown

Important

This PR includes changes that affect public-facing API. Please ensure you are adding/updating documentation for new features or behavior.

Changed Packages

Package Name Package Path Changeset Bump Current Version
app-legacy workspaces/scorecard/packages/app-legacy none v0.0.0
app workspaces/scorecard/packages/app none v0.0.0
@red-hat-developer-hub/backstage-plugin-scorecard-backend workspaces/scorecard/plugins/scorecard-backend minor v2.4.0
@red-hat-developer-hub/backstage-plugin-scorecard-common workspaces/scorecard/plugins/scorecard-common minor v2.4.0
@red-hat-developer-hub/backstage-plugin-scorecard-node workspaces/scorecard/plugins/scorecard-node minor v2.4.0
@red-hat-developer-hub/backstage-plugin-scorecard workspaces/scorecard/plugins/scorecard minor v2.4.0

@rhdh-qodo-merge

Copy link
Copy Markdown

Review Summary by Qodo

Add custom icon support for scorecard threshold rules

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add custom icon support for scorecard threshold rules
• Export Material Design icons as default status icons
• Create icon resolution component supporting multiple formats
• Enhance validation to require icon or color for custom thresholds
• Refactor color utilities into threshold-specific module
Diagram
flowchart LR
  A["Threshold Config"] -->|icon property| B["Icon Validation"]
  B -->|validated| C["Icon Resolution"]
  C -->|system icon| D["ScorecardIcon Component"]
  C -->|SVG/URL| D
  C -->|Material Design| D
  D -->|renders| E["Scorecard UI"]
  F["Material Design Icons"] -->|exported| G["Icons Module"]
  G -->|registered| E
Loading

Grey Divider

File Changes

1. workspaces/scorecard/packages/app/src/modules/icons/index.ts ✨ Enhancement +39/-0

Create icons module for frontend system

workspaces/scorecard/packages/app/src/modules/icons/index.ts


2. workspaces/scorecard/plugins/scorecard-backend/config.d.ts 📝 Documentation +44/-3

Document icon configuration in threshold rules

workspaces/scorecard/plugins/scorecard-backend/config.d.ts


3. workspaces/scorecard/plugins/scorecard-backend/src/utils/mergeEntityAndProviderThresholds.test.ts 🧪 Tests +12/-2

Add icon property to threshold merge tests

workspaces/scorecard/plugins/scorecard-backend/src/utils/mergeEntityAndProviderThresholds.test.ts


View more (22)
4. workspaces/scorecard/plugins/scorecard-common/src/types/threshold.ts ✨ Enhancement +34/-0

Add icon field to ThresholdRule type definition

workspaces/scorecard/plugins/scorecard-common/src/types/threshold.ts


5. workspaces/scorecard/plugins/scorecard-node/src/utils/thresholds/validateThresholds.test.ts 🧪 Tests +92/-19

Add icon validation tests for threshold rules

workspaces/scorecard/plugins/scorecard-node/src/utils/thresholds/validateThresholds.test.ts


6. workspaces/scorecard/plugins/scorecard-node/src/utils/thresholds/validateThresholds.ts ✨ Enhancement +22/-3

Implement icon format validation logic

workspaces/scorecard/plugins/scorecard-node/src/utils/thresholds/validateThresholds.ts


7. workspaces/scorecard/plugins/scorecard/src/index.ts ✨ Enhancement +4/-0

Export Material Design status icons

workspaces/scorecard/plugins/scorecard/src/index.ts


8. workspaces/scorecard/plugins/scorecard/src/utils/colorUtils.ts Miscellaneous +0/-83

Remove color utilities file

workspaces/scorecard/plugins/scorecard/src/utils/colorUtils.ts


9. workspaces/scorecard/plugins/scorecard/src/utils/index.ts Miscellaneous +3/-3

Update exports to use new threshold utilities

workspaces/scorecard/plugins/scorecard/src/utils/index.ts


10. workspaces/scorecard/plugins/scorecard/src/utils/statusUtils.ts ✨ Enhancement +47/-13

Move color logic and add icon resolution

workspaces/scorecard/plugins/scorecard/src/utils/statusUtils.ts


11. workspaces/scorecard/plugins/scorecard/src/utils/thresholdUtils.ts ✨ Enhancement +62/-0

Create threshold utilities for color and icon

workspaces/scorecard/plugins/scorecard/src/utils/thresholdUtils.ts


12. workspaces/scorecard/.changeset/fancy-rice-rush.md 📝 Documentation +8/-0

Document custom threshold icons feature

workspaces/scorecard/.changeset/fancy-rice-rush.md


13. workspaces/scorecard/packages/app-legacy/src/App.tsx ⚙️ Configuration changes +8/-0

Register scorecard status icons in legacy app

workspaces/scorecard/packages/app-legacy/src/App.tsx


14. workspaces/scorecard/packages/app/src/App.tsx ⚙️ Configuration changes +2/-0

Import and register icons module in new app

workspaces/scorecard/packages/app/src/App.tsx


15. workspaces/scorecard/plugins/scorecard-backend/docs/thresholds.md 📝 Documentation +62/-0

Add comprehensive icon configuration documentation

workspaces/scorecard/plugins/scorecard-backend/docs/thresholds.md


16. workspaces/scorecard/plugins/scorecard-common/report.api.md 📝 Documentation +1/-0

Update API report with icon property

workspaces/scorecard/plugins/scorecard-common/report.api.md


17. workspaces/scorecard/plugins/scorecard/report.api.md 📝 Documentation +9/-0

Update API report with exported icons

workspaces/scorecard/plugins/scorecard/report.api.md


18. workspaces/scorecard/plugins/scorecard/src/components/Scorecard/EntityScorecardContent.tsx ✨ Enhancement +1/-1

Update to use icon string instead of component

workspaces/scorecard/plugins/scorecard/src/components/Scorecard/EntityScorecardContent.tsx


19. workspaces/scorecard/plugins/scorecard/src/components/Scorecard/Scorecard.tsx ✨ Enhancement +9/-6

Integrate ScorecardIcon component for rendering

workspaces/scorecard/plugins/scorecard/src/components/Scorecard/Scorecard.tsx


20. workspaces/scorecard/plugins/scorecard/src/components/Scorecard/__tests__/EntityScorecardContent.test.tsx 🧪 Tests +2/-2

Update tests for icon string property

workspaces/scorecard/plugins/scorecard/src/components/Scorecard/tests/EntityScorecardContent.test.tsx


21. workspaces/scorecard/plugins/scorecard/src/components/Scorecard/__tests__/Scorecard.test.tsx 🧪 Tests +20/-11

Mock system icon retrieval and update assertions

workspaces/scorecard/plugins/scorecard/src/components/Scorecard/tests/Scorecard.test.tsx


22. workspaces/scorecard/plugins/scorecard/src/components/ScorecardIcon/ScorecardIcon.tsx ✨ Enhancement +78/-0

Create icon rendering component with format support

workspaces/scorecard/plugins/scorecard/src/components/ScorecardIcon/ScorecardIcon.tsx


23. workspaces/scorecard/plugins/scorecard/src/utils/__tests__/colorUtils.test.tsx Miscellaneous +0/-124

Remove color utilities test file

workspaces/scorecard/plugins/scorecard/src/utils/tests/colorUtils.test.tsx


24. workspaces/scorecard/plugins/scorecard/src/utils/__tests__/statusUtils.test.tsx 🧪 Tests +87/-17

Update tests for icon string and add color tests

workspaces/scorecard/plugins/scorecard/src/utils/tests/statusUtils.test.tsx


25. workspaces/scorecard/plugins/scorecard/src/utils/__tests__/thresholdUtils.test.tsx 🧪 Tests +102/-0

Add comprehensive threshold utilities tests

workspaces/scorecard/plugins/scorecard/src/utils/tests/thresholdUtils.test.tsx


Grey Divider

Qodo Logo

@rhdh-qodo-merge

rhdh-qodo-merge Bot commented Mar 30, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (1) 🎨 UX Issues (0)

Grey Divider


Action required

1. Wrong default icon registry keys 📎 Requirement gap ≡ Correctness
Description
The PR registers/uses
scorecardSuccessStatusIcon/scorecardWarningStatusIcon/scorecardErrorStatusIcon instead of the
required registry keys scorecard-ok/scorecard-warning/scorecard-error. This breaks the
compliance requirement for stable, collision-free default icon keys resolvable via the global icon
registry.
Code

workspaces/scorecard/plugins/scorecard/src/utils/thresholdUtils.ts[R52-60]

+  switch (ruleKey) {
+    case 'error':
+      return 'scorecardErrorStatusIcon';
+    case 'warning':
+      return 'scorecardWarningStatusIcon';
+    case 'success':
+      return 'scorecardSuccessStatusIcon';
+    default:
+      return undefined;
Evidence
Compliance ID 4 requires registry entries keyed as scorecard-ok, scorecard-warning, and
scorecard-error, but the code hardcodes and registers different keys (scorecard*StatusIcon).
This means the scorecard cannot resolve the required keys as specified.

Register default scorecard icons in Backstage global icon registry with required keys
workspaces/scorecard/plugins/scorecard/src/utils/thresholdUtils.ts[52-60]
workspaces/scorecard/packages/app/src/modules/icons/index.ts[29-35]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The implementation hardcodes and registers default icon keys as `scorecardSuccessStatusIcon` / `scorecardWarningStatusIcon` / `scorecardErrorStatusIcon`, but compliance requires the Backstage global icon registry keys `scorecard-ok`, `scorecard-warning`, and `scorecard-error`.

## Issue Context
`getThresholdRuleIcon` provides the default icon key strings that the frontend resolves via `useApp().getSystemIcon(...)`. These defaults must align with the required registry keys.

## Fix Focus Areas
- workspaces/scorecard/plugins/scorecard/src/utils/thresholdUtils.ts[52-60]
- workspaces/scorecard/packages/app/src/modules/icons/index.ts[29-35]
- workspaces/scorecard/packages/app-legacy/src/App.tsx[280-284]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Data URI icons unsupported🐞 Bug ≡ Correctness
Description
ScorecardIcon documents/supports data:image/... icons, but the render logic never treats data:
as an image source, so configured data URIs fall through to the Material-icon-name path and won’t
render as images.
Code

workspaces/scorecard/plugins/scorecard/src/components/ScorecardIcon/ScorecardIcon.tsx[R61-76]

+  if (
+    icon.startsWith('https://') ||
+    icon.startsWith('http://') ||
+    icon.startsWith('/')
+  ) {
+    return (
+      <MuiIcon fontSize={size} baseClassName="material-icons-outlined" sx={sx}>
+        <img src={icon} alt="" height="100%" width="100%" />
+      </MuiIcon>
+    );
+  }
+
+  return (
+    <MuiIcon fontSize={size} baseClassName="material-icons-outlined" sx={sx}>
+      {icon}
+    </MuiIcon>
Evidence
Docs and config typing explicitly claim Data URIs are supported, but ScorecardIcon only renders
images for http(s) and absolute/relative /... paths; data: values miss that branch and fall
through to the final <MuiIcon>{icon}</MuiIcon> case.

workspaces/scorecard/plugins/scorecard/src/components/ScorecardIcon/ScorecardIcon.tsx[61-76]
workspaces/scorecard/plugins/scorecard-backend/docs/thresholds.md[317-326]
workspaces/scorecard/plugins/scorecard-backend/config.d.ts[73-83]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`ScorecardIcon` does not render `data:` URIs as images even though they are documented/supported. As a result, `icon: 'data:image/svg+xml;base64,...'` will be treated as a Material icon name and won’t display.

### Issue Context
The docs/config typing explicitly list Data URIs as supported icon formats. The implementation only renders `<img>` for `http(s)://` and `/...` paths.

### Fix Focus Areas
- workspaces/scorecard/plugins/scorecard/src/components/ScorecardIcon/ScorecardIcon.tsx[61-76]

### Suggested change
Extend the image-source branch to include `icon.startsWith('data:')` (and ideally `icon.trimStart()` before prefix checks). Ensure the `data:` value is passed directly to `<img src={icon} .../>`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. SVG btoa can throw 🐞 Bug ☼ Reliability
Description
ScorecardIcon uses btoa(icon) to base64-encode inline SVG strings; btoa throws on
non‑Latin1/unicode characters, causing runtime failures for valid SVG content pasted into config.
Code

workspaces/scorecard/plugins/scorecard/src/components/ScorecardIcon/ScorecardIcon.tsx[R52-58]

+  if (icon.startsWith('<svg')) {
+    const svgDataUri = `data:image/svg+xml;base64,${btoa(icon)}`;
+    return (
+      <MuiIcon fontSize={size} sx={sx}>
+        <img src={svgDataUri} alt="" />
+      </MuiIcon>
+    );
Evidence
The <svg path explicitly calls btoa(icon) on the raw SVG string. This is directly triggered by
the documented SVG-string icon format and can throw for SVG strings containing unicode (common in
metadata/text).

workspaces/scorecard/plugins/scorecard/src/components/ScorecardIcon/ScorecardIcon.tsx[52-58]
workspaces/scorecard/plugins/scorecard-backend/docs/thresholds.md[321-326]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Inline SVG icons are converted to base64 using `btoa(icon)`, which throws when `icon` contains characters outside Latin1. This can break Scorecard rendering for valid SVG strings.

### Issue Context
SVG strings are explicitly supported via config (`icon: '<svg ...>...</svg>'`). The current conversion assumes Latin1.

### Fix Focus Areas
- workspaces/scorecard/plugins/scorecard/src/components/ScorecardIcon/ScorecardIcon.tsx[52-58]

### Suggested change
Replace `btoa(icon)` with a UTF-8 safe encoding strategy, e.g.:
- `btoa(unescape(encodeURIComponent(icon)))` (browser)
- or a small helper using `TextEncoder` + base64 conversion.
Also consider trimming leading whitespace before `startsWith('<svg')` to accept indented SVG strings.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Misleading validation error text 🐞 Bug ⚙ Maintainability
Description
validateThresholds enforces that custom threshold keys must include both color and icon, but the
thrown error message says “color or icon”, contradicting the actual check and the backend docs.
Code

workspaces/scorecard/plugins/scorecard-node/src/utils/thresholds/validateThresholds.ts[R147-158]

    const standardThresholdRuleKeys = ['success', 'warning', 'error'];
-    if (!standardThresholdRuleKeys.includes(rule.key) && !('color' in rule)) {
+    if (
+      !standardThresholdRuleKeys.includes(rule.key) &&
+      (!('color' in rule) || !('icon' in rule))
+    ) {
      throw new ThresholdConfigFormatError(
        `Custom threshold key "${
          rule.key
-        }" must specify a color property. Only standard keys (${standardThresholdRuleKeys
+        }" must specify a color or icon property. Only standard keys (${standardThresholdRuleKeys
          .map(k => `'${k}'`)
-          .join(', ')}) have default colors.`,
+          .join(', ')}) have default colors and icons.`,
      );
Evidence
The condition throws when either color is missing OR icon is missing, which means both are
required. The docs separately state custom keys must specify a color property and must specify an
icon property, but the error message uses “or”.

workspaces/scorecard/plugins/scorecard-node/src/utils/thresholds/validateThresholds.ts[147-158]
workspaces/scorecard/plugins/scorecard-backend/docs/thresholds.md[289-290]
workspaces/scorecard/plugins/scorecard-backend/docs/thresholds.md[350-351]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The validation error message for custom threshold keys says they must specify a "color or icon" property, but the code throws if either is missing (so it requires both). This misleads users during configuration.

### Issue Context
Docs require custom keys to specify both `color` and `icon`.

### Fix Focus Areas
- workspaces/scorecard/plugins/scorecard-node/src/utils/thresholds/validateThresholds.ts[147-158]

### Suggested change
Update the message to say "must specify a color and icon property" (or split into two clearer checks/messages: missing color vs missing icon). Update associated tests expecting the old string.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment thread workspaces/scorecard/plugins/scorecard/src/utils/thresholdUtils.ts
Comment on lines +61 to +76
if (
icon.startsWith('https://') ||
icon.startsWith('http://') ||
icon.startsWith('/')
) {
return (
<MuiIcon fontSize={size} baseClassName="material-icons-outlined" sx={sx}>
<img src={icon} alt="" height="100%" width="100%" />
</MuiIcon>
);
}

return (
<MuiIcon fontSize={size} baseClassName="material-icons-outlined" sx={sx}>
{icon}
</MuiIcon>

This comment was marked as resolved.

@christoph-jerolimov christoph-jerolimov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! Thanks @dzemanov 👍

Keep it open for a day if someone else wants take a look as well.

@Eswaraiahsapram Eswaraiahsapram left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dzemanov, tested in local. Looks good to me 🎉

/lgtm

Image Image

Configuration I used

scorecard:
  plugins:
    jira:
      open_issues:
        thresholds:
          rules:
            - key: success
              expression: '<5'
              color: 'success.main'
              icon: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" style="color:#02D8E9"><rect x="4" y="4" width="16" height="16" rx="2" stroke="#02D8E9" stroke-width="2"/><path d="M8 12l2.5 2.5L16 9" stroke="#02D8E9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'
            - key: warning
              expression: '6-60'
              color: '#FFA500'
              icon: kind:component
            - key: error
              expression: '>60'
              color: 'rgb(255, 0, 0)'
              icon: https://raw.githubusercontent.com/dzemanov/backstage-entities/main/icons/scorecard-icon.svg
    github:
      open_prs:
        thresholds:
          rules:
            - key: success
              expression: '<5'
              icon: https://raw.githubusercontent.com/dzemanov/backstage-entities/main/icons/scorecard-icon.svg
            - key: warning
              expression: '6-60'
              icon: kind:api
            - key: error
              expression: '>60'
              icon: kind:system

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
@openshift-ci openshift-ci Bot removed the lgtm label Mar 31, 2026
@openshift-ci

openshift-ci Bot commented Mar 31, 2026

Copy link
Copy Markdown

New changes are detected. LGTM label has been removed.

@imykhno

imykhno commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

Thanks @dzemanov for this PR. I tested locally and have a couple questions:

Using Image URL

Config

. . .
thresholds:  
  rules:
    - key: error
      expression: '>50'
      color: 'rgb(229, 85, 0)'
      icon: https://raw.githubusercontent.com/dzemanov/backstage-entities/main/icons/scorecard-icon.svg

Screenshot

Screenshot 2026-03-31 at 11 41 45

Question

When URLs are used, the icon color defaults to black in my case. Is this the expected behaviour, and how can I change the icon color to match the rest of the donut chart?

Using "Text" for icon config

Config

. . .
thresholds:  
  rules:
    - key: error
      expression: '>50'
      color: 'rgb(229, 85, 0)'
      icon: Nice

Screenshot

Screenshot 2026-03-31 at 11 54 25

Question

I am not certain whether we can programmatically validate the icon configuration, however, I wanted to confirm that we are aware of this behaviour.

Using Backstage System Icon

Works as expected. Using the same color as rest of the donut chart

Config

. . .
thresholds:  
  rules:
    - key: error
      expression: '>50'
      color: 'rgb(229, 85, 0)'
      icon: kind:group

Screenshot

Screenshot 2026-03-31 at 12 06 59

Using Data URI

Config

. . .
thresholds:  
  rules:
    - key: error
      expression: '>50'
      color: 'rgb(229, 85, 0)'
      icon: data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIj48cmVjdCB4PSI0IiB5PSI0IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHJ4PSIyIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIi8+PHBhdGggZD0iTTggMTJsMi41IDIuNUwxNiA5IiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L3N2Zz4=

Screenshot

Screenshot 2026-03-31 at 12 18 54

Question

When Data URIs are used, the icon color defaults to black in my case. Is this the expected behaviour, and how can I change the icon color to match the rest of the donut chart?

Using SVG String

Works as expected. Using the same color as rest of the donut chart

Config

. . .
thresholds:  
  rules:
    - key: error
      expression: '>50'
      color: 'rgb(229, 85, 0)'
      icon: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" style="color:#e55500"><rect x="4" y="4" width="16" height="16" rx="2" stroke="#e55500" stroke-width="2"/><path d="M8 12l2.5 2.5L16 9" stroke="#e55500" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'

Screenshot

Screenshot 2026-03-31 at 12 24 05

Using Default Icons

Works as expected. Using the same color as rest of the donut chart

Config

. . .
thresholds:  
  rules:
    - key: error
      expression: '>50'
      color: 'rgb(229, 85, 0)'
      icon: scorecardSuccessStatusIcon

Screenshot

Screenshot 2026-03-31 at 12 26 29

@dzemanov

Copy link
Copy Markdown
Member Author

@imykhno thank you for the review!

Color propagation:

  • From description:

    Note: color is not propagated correctly when using /http icons and will need to be specified in the icon itself. The logic for this is copied from HeaderIcon.

  • Svg icon you used is also not propagating:

image

The problem is that <img is already rendered and sx properties are not applied for it.
I can try to use CSS masking to fix this.

Icon validation:
Since app.getSystemIcon(...) is frontend API only and users can freely define icon names, there is no way to validate the name other then checking it is non-empty string.

@imykhno

imykhno commented Mar 31, 2026

Copy link
Copy Markdown
Contributor
  • Svg icon you used is also not propagating:
image

Yes your are totally right color is not propagating at the svg icon.
However if we try to find solution for svg icon right now we may recommend to provide the same as threshold color to the config as I did: icon: '<svg xmlns="http://www.w3 . . . . style="color:#e55500"> . . . . stroke="#e55500" . . . . stroke="#e55500" . . . ./svg>' (short example of config shared by me)

The problem is that <img is already rendered and sx properties are not applied for it. I can try to use CSS masking to fix this.

It will be great if you try to find solution. I think, providing this approach help customers configure the well styled cards with scorecard plugin.

Icon validation: Since app.getSystemIcon(...) is frontend API only and users can freely define icon names, there
is no way to validate the name other then checking it is non-empty string.

Thank you for additional information regarding this question. I have no objections, I just wanted to make sure we knew about it. Thank you!

CC @dzemanov

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
@dzemanov

Copy link
Copy Markdown
Member Author

@imykhno yes, we can encourage users to specify their color in the icon itself.

I have updated the code to render with correct color using CSS masking.
You can test it out with for example these icons:

icon: https://raw.githubusercontent.com/dzemanov/backstage-entities/refs/heads/main/icons/check_circle.png
icon: https://raw.githubusercontent.com/dzemanov/backstage-entities/refs/heads/main/icons/check_circle.svg

This means that using image like this:

icon: https://raw.githubusercontent.com/dzemanov/backstage-entities/refs/heads/main/icons/website.png
image will result in: image

However, I don't expect users using these types of images and it makes sense to use specified / default threshold colors for icons.

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
This reverts commit 3954388.
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
@dzemanov

Copy link
Copy Markdown
Member Author

I have reverted the changes with CSS masking due to compatibility issues in Safari - which I fixed - but there might be other potential problems with older browsers. I added to Readme information about the requirement for icons from urls to be pre-colored.

dzemanov and others added 2 commits March 31, 2026 18:56
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
@dzemanov

Copy link
Copy Markdown
Member Author

Fixed tests, not sure why CI did not catch it in #2650

@sonarqubecloud

Copy link
Copy Markdown

@dzemanov
dzemanov merged commit 55226c2 into redhat-developer:main Apr 1, 2026
10 checks passed
@dzemanov
dzemanov deleted the scorecard-threshold-icons branch April 1, 2026 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants