Skip to content

feat(scorecard): implement blueprint architecture for grouped layouts#3282

Open
Eswaraiahsapram wants to merge 5 commits into
redhat-developer:mainfrom
Eswaraiahsapram:group-metrics-RHIDP-13955
Open

feat(scorecard): implement blueprint architecture for grouped layouts#3282
Eswaraiahsapram wants to merge 5 commits into
redhat-developer:mainfrom
Eswaraiahsapram:group-metrics-RHIDP-13955

Conversation

@Eswaraiahsapram
Copy link
Copy Markdown
Member

@Eswaraiahsapram Eswaraiahsapram commented Jun 3, 2026

Hey, I just made a Pull Request!

Fix - https://redhat.atlassian.net/browse/RHIDP-13955

Description:

Add blueprint pattern for scorecard metric grouping with dynamic layout extensions discoverable through Backstage NFS.

Changes:

  • Create ScorecardEntityContentLayoutBlueprint with groups config schema
  • Add Grid and List layout extension instances via .make()
  • Update entity tab to declare layouts input and render ScorecardLayoutSwitcher
  • Implement draft ScoreEntityContentGridView component
  • Add ScorecardLayoutSwitcher for toggling between enabled layouts
  • Bundle layout extensions in scorecardCatalogModule for auto-discovery
  • Support enable/disable of individual layouts via app-config.yaml

Screenshot

Screenshot 2026-06-03 at 5 11 41 PM

How to Test

  1. cd workspaces/scorecard
  2. yarn install
  3. yarn start
  4. Navigate to an entity with scorecard metrics (Component with SonarQube, GitHub, filecheck data).
Config to Enable Both Layouts
app:
  extensions:
    # Scorecard tab: entity shows tab if it matches any filter below.
    - entity-content:catalog/entity-content-scorecard:
        config:
          allowedFilters:
            - kind: component # e.g. Component with spec.type: website
              type: website
            - kind: api # e.g. any API entity
            - type: service # e.g. Component or System with spec.type: service
            
    # Grid layout – enabled with metric grouping
    - scorecard-layout:catalog/scorecard-entity-layout-grid:
        config:
          groups:
            code-quality:
              title: Code Quality
              description: Code quality and coverage metrics from SonarQube
              metrics:
                - sonarqube.quality_gate
                - sonarqube.code_coverage
                - sonarqube.code_duplications
                - sonarqube.maintainability_issues
                - sonarqube.security_hotspots
                - sonarqube.reliability_rating
                - sonarqube.reliability_issues

            repository-standards:
              title: Repository Standards
              description: Essential repository files and documentation
              metrics:
                - filecheck.license
                - filecheck.codeowners
                - filecheck.readme
                - filecheck.contributing

            security:
              title: Security Compliance
              description: Security scans and vulnerability checks
              metrics:
                - dependabot.vulnerabilities
                - ossf.scorecard
                - snyk.vulnerabilities

    # List layout – disabled
    - scorecard-layout:catalog/scorecard-entity-layout-list:
        config:
          groups:
            code-quality:
              title: Code Quality
              description: Code quality and coverage metrics from SonarQube
              metrics:
                - sonarqube.quality_gate
                - sonarqube.code_coverage
                - sonarqube.code_duplications
                - sonarqube.maintainability_issues
                - sonarqube.security_hotspots
                - sonarqube.reliability_rating
                - sonarqube.reliability_issues

            repository-standards:
              title: Repository Standards
              description: Essential repository files and documentation
              metrics:
                - filecheck.license
                - filecheck.codeowners
                - filecheck.readme
                - filecheck.contributing

            security:
              title: Security Compliance
              description: Security scans and vulnerability checks
              metrics:
                - dependabot.vulnerabilities
                - ossf.scorecard
                - snyk.vulnerabilities

✔️ 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)

@rhdh-gh-app
Copy link
Copy Markdown

rhdh-gh-app Bot commented Jun 3, 2026

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
@red-hat-developer-hub/backstage-plugin-scorecard workspaces/scorecard/plugins/scorecard major v2.7.7

@fullsend-ai-review
Copy link
Copy Markdown

fullsend-ai-review Bot commented Jun 3, 2026

Review

Findings

Critical

  • [logic-error] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScorecardEntityContentGridView.tsx:245 — The grouped-card rendering path is gated behind a hardcoded {false && ...} condition, making the entire GroupCard/MetricTile rendering dead code. The component computes groupedMetrics and ungroupedMetrics maps but never uses either — the grouped view never renders. This defeats the PR's stated purpose of implementing grouped scorecard layouts. The PR description acknowledges this is a "draft" component, but it is labeled ready-for-merge and ships ~100 lines of dead code (GroupCard, MetricTile, statusTileBg/statusTileText maps, getEvaluation helper, and several unused MUI imports).
    Remediation: Either remove the false && guard and enable the grouped rendering, or remove the dead GroupCard/MetricTile code entirely and defer it to a follow-up PR. If this is intentionally staged, remove the ready-for-merge label.

High

  • [logic-error] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScorecardEntityContentGridView.tsx:272 — Even if the false && guard were removed, the flat rendering block iterates over all scorecards rather than ungroupedMetrics. Every metric assigned to a group would appear both inside its GroupCard and again as an individual Scorecard tile below, causing duplicate rendering. The ungroupedMetrics array is computed but never consumed.
    Remediation: Change scorecards.map(...) to ungroupedMetrics.map(...) in the second rendering block so only metrics not assigned to any group render as individual cards.

Medium

  • [api-contract] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScorecardEntityListView.tsx:17 — ScorecardEntityListView does not accept ScorecardLayoutProps (the groups prop). The blueprint factory always passes { groups: config.groups } to loaded components. The list layout silently discards its configuration, violating the blueprint's contract.
    Remediation: Accept ScorecardLayoutProps as the component's props type, matching the blueprint's expectations.

  • [missing-export] workspaces/scorecard/plugins/scorecard/src/alpha/index.tsx / report-alpha.api.mdScorecardEntityContentLayoutBlueprint, scorecardLayoutTitleDataRef, and ScorecardLayoutProps are marked @alpha in source but are not re-exported from src/alpha/index.tsx and do not appear in report-alpha.api.md. External consumers cannot create custom scorecard layout extensions using the blueprint. Other blueprints in this repo (e.g., GlobalHeaderComponentBlueprint, AppDrawerContentBlueprint) are exported from their package's public API. See also: [backward-compatibility] finding.

Low

  • [edge-case] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScorecardLayoutSwitcher.tsx:38 — If the layouts prop changes dynamically (e.g., hot-reload removing a layout), the stale selectedIndex state could reference a removed layout. The fallback layouts[selectedIndex] ?? layouts[0] silently resets rendering but leaves state inconsistent for subsequent toggles.

  • [pattern-inconsistency] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScorecardEntityContentGridView.tsx:42statusTileBg and statusTileText use hardcoded hex color strings rather than theme-aware values. Existing components (Scorecard.tsx, CustomLegend.tsx) consistently use useTheme() and resolveStatusColor() for dark-mode compatibility.

  • [pattern-inconsistency] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/index.ts:19 — New exports use direct re-export syntax (export { X } from './X') while the existing pattern in this file uses import-then-re-export (import { X } from './X'; export { X };).

  • [missing-test] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScorecardEntityContentGridView.tsx — No component test exists for ScorecardEntityContentGridView. A test rendering with groups config would have caught both the false && dead-code bug and the duplicate rendering issue.

Info

  • [architectural-coherence] workspaces/scorecard/plugins/scorecard/src/alpha/blueprints/ScorecardLayoutBlueprint.ts — The blueprint architecture follows established repo patterns (createExtensionBlueprint, generator factory, custom data refs, attachment to parent input). The design is consistent with the project's Backstage NFS adoption trajectory.
Previous run

Review

Findings

Low

  • [edge-case] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScorecardLayoutSwitcher.tsx:27 — The fallback layouts[selectedIndex] ?? layouts[0] masks a potential stale-index state when selectedIndex exceeds layouts.length. In practice, layouts is resolved statically at framework boot time and does not change between renders, making this a theoretical concern. However, adding a useEffect to clamp selectedIndex when it falls out of bounds would make the component more robust for future use cases where layouts might be dynamically toggled.

  • [test-inadequate] workspaces/scorecard/plugins/scorecard/src/alpha/blueprints/ScorecardLayoutBlueprint.test.tsx — Tests use two different loader patterns: async () => () => <MockLayout /> (wrapping component, ignoring groups prop) vs async () => MockLayout (direct component, receiving groups). The production code uses the direct pattern, so this doesn't mask a real bug, but standardizing test loaders would prevent confusion and improve test reliability.

  • [error-handling] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScorecardLayoutSwitcher.tsx:50 — Toggle buttons use layout.title as the React key. If two layouts shared the same title, React would produce duplicate key warnings and potentially incorrect reconciliation. Currently mitigated by hardcoded titles ('Grid', 'List').

Info

  • [sub-agent-failure] N/A — The style-conventions, intent-coherence, and docs-currency sub-agents could not complete due to model availability issues on this deployment. These dimensions were not evaluated in this review cycle.
Previous run (2)

Review

Findings

High

  • [missing-test] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScoreEntityContentGridView.tsx — This PR introduces a major new feature (blueprint architecture, grid view, layout switcher, blueprint factory) with zero test files. The existing codebase has thorough test coverage for comparable components (EntityScorecardContent.test.tsx, Scorecard.test.tsx, CustomLegend.test.tsx). ScoreEntityContentGridView contains substantial logic (metric grouping, status color resolution, ungrouped-metric detection, multiple rendering branches) that is untested. ScorecardLayoutSwitcher has state management and edge-case behavior that also lacks tests.
    Remediation: Add tests for (1) ScoreEntityContentGridView covering grouping logic, ungrouped metric fallback, error/loading/empty states, and permission error; (2) ScorecardLayoutSwitcher covering layout switching and single-layout behavior; (3) ScorecardLayoutBlueprint verifying the factory yields expected extension data.

  • [type-safety] workspaces/scorecard/plugins/scorecard/src/alpha/extensions/entityTab.tsx(inputs as any).layouts bypasses all TypeScript type checking. No other file in src/alpha/ uses as any. The subsequent .map((l: any) => ...) also uses any, meaning l.get() calls have no compile-time verification. The root cause is that the blueprint omits the dataRefs field (both existing blueprints in this repo — GlobalHeaderComponentBlueprint, AppDrawerContentBlueprint — declare dataRefs), which would enable type-safe access to extension data.
    Remediation: Add a dataRefs field to ScorecardEntityContentLayoutBlueprint and type the inputs parameter properly. If the upstream Blueprint API genuinely lacks the types, add focused runtime guards and a TODO comment explaining the gap.

  • [incomplete-work] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScorecardEntityListView.tsxScorecardEntityListView is a non-functional stub (return <div>ScorecardEntityListView</div>) registered as a first-class layout extension via the blueprint and wired into scorecardCatalogModule. It will be discoverable and selectable by platform engineers. Shipping a placeholder as a registered extension in a versioned release creates a confusing UX if toggled on.
    Remediation: Either remove the list layout extension and add it in a follow-up PR when implemented, or gate it behind an explicit experimental flag.

  • [naming-convention] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScoreEntityContentGridView.tsx — The component uses the prefix Score instead of Scorecard. Every other public component in the codebase uses the Scorecard prefix (ScorecardPage, ScorecardIcon, ScorecardHomepageCard, EntityScorecardContent). Additionally, the naming pattern is asymmetric with its sibling: ScoreEntityContentGridView vs ScorecardEntityListView (extra Content word in grid).
    Remediation: Rename to a consistent pattern, e.g., ScorecardEntityGridView / ScorecardEntityListView.

Medium

  • [behavioral-contract-change] workspaces/scorecard/plugins/scorecard/src/alpha/index.tsx:68 — scorecardCatalogModule now registers two additional extensions (scorecardEntityLayoutGrid, scorecardEntityLayoutList). Because the entity tab checks layouts.length > 0 to decide whether to render ScorecardLayoutSwitcher or the legacy EntityScorecardContent, existing consumers who import scorecardCatalogModule will get a different UI without any code change. This is a behavioral breaking change for the @alpha export.
    Remediation: Ship layout extensions in a separate opt-in module (e.g., scorecardLayoutsModule) so existing consumers retain the legacy view by default, or ensure layout extensions are disabled by default and must be explicitly enabled in app-config.yaml.

  • [stale-doc] workspaces/scorecard/plugins/scorecard/README.md:225 — The Modules table describes scorecardCatalogModule as only "Registers the Scorecard entity tab" — after this PR it also registers grid and list layout extensions. The Extensions list (lines 229-238) omits both new scorecard-layout extensions. The NFS configuration section documents allowedFilters but not the new groups config schema for layout extensions.
    Remediation: Update the module description, add extension entries, and document the groups config schema with examples.

  • [hardcoded-colors] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScoreEntityContentGridView.tsx:48 — statusTileBg and statusTileText maps use hardcoded hex color literals (#e8f5e9, #2e7d32, etc.). The rest of the codebase resolves status colors through the theme via resolveStatusColor(). The component already imports useTheme and calls resolveStatusColor for the donut color but bypasses it for tile backgrounds and text. These values will not adapt to dark mode or custom themes.
    Remediation: Derive colors from the MUI theme palette or use alpha(resolvedColor, 0.12) from @mui/material/styles for background tints.

  • [edge-case] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScoreEntityContentGridView.tsx — If the same metric ID appears in multiple groups (which the config schema does not prevent), the metric will be rendered in multiple group cards. This is likely unintended duplication that could confuse users.
    Remediation: Either validate at config parse time that metric IDs are unique across groups, or assign each metric to only the first matching group.

  • [stale-doc] workspaces/scorecard/plugins/scorecard/report-alpha.api.md — The auto-generated API report does not include the new alpha exports (ScorecardEntityContentLayoutBlueprint, scorecardLayoutTitleDataRef, ScorecardLayoutProps). Needs regeneration.
    Remediation: Run the API extractor to regenerate report-alpha.api.md.

Low

  • [pattern-inconsistency] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/index.ts:18 — The original barrel file uses import-then-re-export pattern; the three new lines use inline re-exports. Mixing styles in one file is inconsistent.

  • [i18n-gap] workspaces/scorecard/plugins/scorecard/src/components/Scorecard/ScoreEntityContentGridView.tsx:176 — Hardcoded English strings ('No metric data available yet', metric/metrics pluralization) bypass the useTranslation hook used elsewhere in the codebase.

Info

  • [incomplete-checklist] All PR checklist items are unchecked (changeset review, documentation, tests, screenshots). The do-not-merge/hold label is appropriately applied.
Previous run (3)

Review

Reason: stale-head

The review agent reviewed commit 204a6f50c836ff85ca3db2a5ba879aea7df84f1a but the PR HEAD is now d1c2822915ed8399970ff75bbd8b200d0f7db58c. This review was discarded to avoid approving unreviewed code.

Copy link
Copy Markdown

@fullsend-ai-review fullsend-ai-review Bot left a comment

Choose a reason for hiding this comment

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

See the review comment for full details.

* extensions (grid + list) into the Catalog entity pages.
*
* The plugin ships both layouts; platform engineers enable/disable individual
* layouts via app-config.yaml. No separate module registration is needed
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] behavioral-contract-change

scorecardCatalogModule now bundles layout extensions that change the default UI for existing consumers. When layouts are registered, the entity tab renders ScorecardLayoutSwitcher instead of the legacy EntityScorecardContent.

Suggested fix: Ship layout extensions in a separate opt-in module or ensure they are disabled by default.

success: '#e8f5e9',
warning: '#fff3e0',
error: '#fce4ec',
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] hardcoded-colors

statusTileBg and statusTileText use hardcoded hex colors that will not adapt to dark mode or custom themes. Rest of codebase uses resolveStatusColor() through the theme.

Suggested fix: Derive colors from MUI theme palette or use alpha(resolvedColor, 0.12) for background tints.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 3, 2026

Codecov Report

❌ Patch coverage is 29.00000% with 71 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.92%. Comparing base (6069ca8) to head (97f9226).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3282      +/-   ##
==========================================
- Coverage   53.95%   53.92%   -0.03%     
==========================================
  Files        2379     2384       +5     
  Lines       86136    86235      +99     
  Branches    23882    23918      +36     
==========================================
+ Hits        46471    46500      +29     
- Misses      38073    38143      +70     
  Partials     1592     1592              
Flag Coverage Δ *Carryforward flag
adoption-insights 83.58% <ø> (ø) Carriedforward from 6069ca8
ai-integrations 70.03% <ø> (ø) Carriedforward from 6069ca8
app-defaults 69.60% <ø> (ø) Carriedforward from 6069ca8
augment 46.39% <ø> (ø) Carriedforward from 6069ca8
bulk-import 72.86% <ø> (ø) Carriedforward from 6069ca8
cost-management 17.48% <ø> (ø) Carriedforward from 6069ca8
dcm 59.64% <ø> (ø) Carriedforward from 6069ca8
extensions 62.24% <ø> (ø) Carriedforward from 6069ca8
global-floating-action-button 74.30% <ø> (ø) Carriedforward from 6069ca8
global-header 61.63% <ø> (ø) Carriedforward from 6069ca8
homepage 51.52% <ø> (ø) Carriedforward from 6069ca8
konflux 91.01% <ø> (ø) Carriedforward from 6069ca8
lightspeed 68.50% <ø> (ø) Carriedforward from 6069ca8
mcp-integrations 85.46% <ø> (ø) Carriedforward from 6069ca8
orchestrator 37.33% <ø> (ø) Carriedforward from 6069ca8
quickstart 62.09% <ø> (ø) Carriedforward from 6069ca8
sandbox 79.42% <ø> (ø) Carriedforward from 6069ca8
scorecard 82.25% <29.00%> (-1.60%) ⬇️
theme 64.54% <ø> (ø) Carriedforward from 6069ca8
translations 8.49% <ø> (ø) Carriedforward from 6069ca8
x2a 78.79% <ø> (ø) Carriedforward from 6069ca8

*This pull request uses carry forward flags. Click here to find out more.


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6069ca8...97f9226. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.


/** @alpha */
export interface ScorecardLayoutItem {
title: string;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] edge-case

The fallback layouts[selectedIndex] ?? layouts[0] masks a potential stale-index state. In practice layouts are static extension inputs resolved at boot time, but adding a useEffect to clamp selectedIndex would make the component more robust.

Suggested fix: Add useEffect(() => { if (selectedIndex >= layouts.length) setSelectedIndex(0); }, [layouts.length, selectedIndex]);

return (
<Box>
{layouts.length > 1 && (
<Box display="flex" justifyContent="flex-end" mb={2}>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] error-handling

Toggle buttons use layout.title as React key. Duplicate titles would cause reconciliation issues. Currently mitigated by hardcoded unique titles.

@fullsend-ai-review fullsend-ai-review Bot added the ready-for-merge All reviewers approved — ready to merge label Jun 3, 2026
@Eswaraiahsapram Eswaraiahsapram force-pushed the group-metrics-RHIDP-13955 branch from 58c014f to 97f9226 Compare June 5, 2026 11:21
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Jun 5, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Copy link
Copy Markdown

@fullsend-ai-review fullsend-ai-review Bot left a comment

Choose a reason for hiding this comment

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

See the review comment for full details.

gap={2.5}
>
{/* show groups if they are configured for entity tab */}
{false &&
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[critical] logic-error

The grouped-card rendering path is gated behind a hardcoded {false && ...} condition, making the entire GroupCard/MetricTile rendering dead code. The component computes groupedMetrics and ungroupedMetrics maps but never uses either. This defeats the PR's stated purpose of implementing grouped scorecard layouts. The PR ships ~100 lines of dead code including GroupCard, MetricTile, statusTileBg/statusTileText maps, and getEvaluation helper.

Suggested fix: Either remove the false && guard and enable the grouped rendering, or remove the dead GroupCard/MetricTile code entirely and defer to a follow-up PR. If intentionally staged, remove the ready-for-merge label.

);
})}

{scorecards.length > 0 &&
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[high] logic-error

Even if the false && guard were removed, the flat rendering block iterates over all scorecards rather than ungroupedMetrics. Every metric assigned to a group would appear both inside its GroupCard and again as an individual Scorecard tile, causing duplicate rendering. The ungroupedMetrics array is computed but never consumed.

Suggested fix: Change scorecards.map(...) to ungroupedMetrics.map(...) in the second rendering block so only metrics not assigned to any group render as individual cards.

* limitations under the License.
*/

export const ScorecardEntityListView = () => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] api-contract

ScorecardEntityListView does not accept ScorecardLayoutProps (the groups prop). The blueprint factory always passes { groups: config.groups } to loaded components. The list layout silently discards its configuration, violating the blueprint's contract.

Suggested fix: Accept ScorecardLayoutProps as the component's props type, matching the blueprint's expectations.


export const ScorecardLayoutSwitcher = ({
layouts,
}: {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] edge-case

If the layouts prop changes dynamically, stale selectedIndex state could reference a removed layout. The fallback silently resets rendering but leaves state inconsistent for subsequent toggles.

Suggested fix: Add a useEffect that clamps selectedIndex to layouts.length - 1 when the layouts array changes.

resolveStatusColor,
resolveMetricTranslation,
} from '../../utils';
import { useTranslation } from '../../hooks/useTranslation';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] pattern-inconsistency

statusTileBg and statusTileText use hardcoded hex color strings rather than theme-aware values. Existing components consistently use useTheme() and resolveStatusColor() for dark-mode compatibility.

Suggested fix: Replace hardcoded hex maps with theme-aware color derivation.

import { EntityScorecardContent } from './EntityScorecardContent';

export { EntityScorecardContent };
export { ScorecardEntityContentGridView } from './ScorecardEntityContentGridView';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] pattern-inconsistency

New exports use direct re-export syntax while the existing pattern in this file uses import-then-re-export.

Suggested fix: Match the existing import-then-re-export pattern.

@fullsend-ai-review fullsend-ai-review Bot removed the ready-for-merge All reviewers approved — ready to merge label Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants