Skip to content

feat(org-lens): add score-breakdown drawer to leaderboard rows UI only - #1276

Draft
danoqualls wants to merge 2 commits into
mainfrom
feat/org-leaderboard-detail-drawer
Draft

feat(org-lens): add score-breakdown drawer to leaderboard rows UI only#1276
danoqualls wants to merge 2 commits into
mainfrom
feat/org-leaderboard-detail-drawer

Conversation

@danoqualls

@danoqualls danoqualls commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Business case: show details of how influence leaderboards are calculated.

This pull request adds a new leaderboard row score-breakdown drawer to the Org Project Detail page, allowing users to click on leaderboard rows to view a detailed breakdown of an organization's influence score. The drawer displays demo data or a graceful empty state if data is unavailable. The implementation includes new component files, integration into the Org Project Detail page, and end-to-end tests to ensure correct behavior.

Feature: Leaderboard Row Score-Breakdown Drawer

  • Added OrgLeaderboardDetailDrawerComponent to display a detailed breakdown of an organization's leaderboard score, including summary, category breakdown, and methodology, with demo data and an empty state fallback (org-leaderboard-detail-drawer.component.ts, org-leaderboard-detail-drawer.component.html). [1] [2]
  • Integrated the drawer into the Org Project Detail page, enabling it to open when a technical or ecosystem leaderboard row is clicked (org-project-detail.component.html, org-project-detail.component.ts). [1] [2] [3] [4] [5] [6] [7]

Testing

  • Added end-to-end tests to verify that clicking leaderboard rows opens the drawer, displays the correct content or empty state, and that closing the drawer returns to the detail page (org-project-detail.spec.ts).

Constants

  • Exported new constants for demo data used in the score-breakdown drawer (index.ts).

UI Improvements

  • Made leaderboard table rows clickable and added hover effects to indicate interactivity (org-project-detail.component.html). [1] [2]

Summary

  • Clicking a row in either the Technical or Ecosystem leaderboard table on the Org Lens Project Detail page (pd-leaderboards tab) now opens a right-side drawer showing that organization's category-level score breakdown for the clicked influence dimension.
  • New OrgLeaderboardDetailDrawerComponent (apps/lfx-one/.../dashboards/components/org-leaderboard-detail-drawer/) renders: header (org name + "{{project}} · Technical/Ecosystem Influence"), a summary sentence (level + activity % + score + rank), category rows sorted by points descending with a highlighted top category, a bold total-score line, and a methodology explainer box — matching the validated prototype design.
  • Row click handling only added cursor-pointer/hover styling + a (click) handler to each leaderboard's #body row template; no other changes to the existing leaderboard tables.
  • New shared interfaces (org-leaderboard-detail-drawer.interface.ts), constants (org-leaderboard-detail-drawer.constants.ts), and utils (org-leaderboard-detail.utils.ts) added to @lfx-one/shared.

Demo-data caveat: category points/counts/company lookups in org-leaderboard-detail-drawer.constants.ts are explicitly DEMO/PLACEHOLDER data (called out in file-level comments), keyed by org display name since the real leaderboard rows carry no org id. This is pending a real Snowflake-backed data source in a follow-up ticket. Any org clicked that isn't in the demo lookup renders a graceful "not yet available" empty state instead of crashing — this covers the vast majority of real leaderboard rows today.

JIRA: LFXV2-2934

Test plan

  • yarn check-types passes
  • yarn lint passes (no new warnings/errors introduced)
  • yarn build passes (SSR bundle builds clean)
  • yarn format:check passes
  • ./check-headers.sh passes (license headers on all new files)
  • Added e2e coverage in apps/lfx-one/e2e/org-project-detail.spec.ts: clicking a technical/ecosystem row opens the drawer with the correct org name + dimension label and renders either the breakdown content or the empty state (never crashes); closing via Escape returns to the detail page
  • Manual QA: click several rows on both leaderboards against a live project and confirm the drawer opens/closes correctly and the empty state renders for orgs outside the demo dataset

Clicking a row in the Org Lens Project Detail Technical or Ecosystem
leaderboard now opens a right-side drawer with that org's category
score breakdown for the clicked influence dimension.

Category points/counts are DEMO/PLACEHOLDER data pending a real
Snowflake-backed data source; orgs not present in the demo lookup
render a graceful empty state instead of crashing.

LFXV2-2934

Signed-off-by: daniel qualls <dqualls@linuxfoundation.org>
@danoqualls
danoqualls requested a review from a team as a code owner July 30, 2026 19:44
Copilot AI balanced review requested due to automatic review settings July 30, 2026 19:44
@cursor

cursor Bot commented Jul 30, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Additive UI on the project detail page using client-side demo data; no API, auth, or leaderboard fetch behavior changes.

Overview
Adds a score-breakdown drawer on Org Lens Project Detail leaderboards: clicking a technical or ecosystem row opens a right-side panel for that org’s influence dimension.

Org project detail — Leaderboard table rows are now clickable (cursor-pointer, hover, (click)openLeaderboardDetail). State (leaderboardDetailOpen, dimension, org name) drives a new lfx-org-leaderboard-detail-drawer sibling to the existing influence card drawer.

New drawer component — Shows org + project subtitle, a summary (level, activity %, score, rank), category bars with points/%, total score, and methodology copy. Data comes from demo lookups keyed by org display name in shared constants until Snowflake (LFXV2-2934); orgs not in the map get an empty state instead of an error.

Shared package — New interfaces, placeholder company/category/methodology constants, and utils for influence level thresholds and category row sorting.

E2E — Covers row click (technical/ecosystem), title match, content or empty state, and Escape to close without leaving the page.

Reviewed by Cursor Bugbot for commit 104602c. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9b4e0a5a-4cc3-41fa-a6cb-f9a6e940ae58

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a score-breakdown drawer for technical and ecosystem leaderboard rows on the organization project detail page, using shared interfaces, demo data, calculation utilities, row-click wiring, and E2E coverage for opening, rendering, and closing the drawer.

Changes

Leaderboard score-breakdown drawer

Layer / File(s) Summary
Shared contracts, data, and calculations
packages/shared/src/interfaces/..., packages/shared/src/constants/..., packages/shared/src/utils/...
Defines drawer data shapes, category and methodology content, demo company metrics, score-level thresholds, category-row calculations, and public exports.
Drawer rendering and derived state
apps/lfx-one/src/app/modules/dashboards/components/org-leaderboard-detail-drawer/*
Adds the drawer component with dimension-specific company lookup, score and category derivation, methodology content, populated breakdown rendering, empty state, and close handling.
Project detail row interaction and validation
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/*, apps/lfx-one/e2e/org-project-detail.spec.ts
Makes technical and ecosystem leaderboard rows clickable, wires drawer state and bindings, and tests drawer opening, content, empty fallback, Escape closing, and page retention.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant OrgProjectDetailComponent
  participant OrgLeaderboardDetailDrawerComponent
  participant SharedLeaderboardData
  User->>OrgProjectDetailComponent: Click technical or ecosystem leaderboard row
  OrgProjectDetailComponent->>OrgLeaderboardDetailDrawerComponent: Set dimension, organization, and visibility
  OrgLeaderboardDetailDrawerComponent->>SharedLeaderboardData: Resolve company breakdown and methodology
  SharedLeaderboardData-->>OrgLeaderboardDetailDrawerComponent: Provide score and category data
  OrgLeaderboardDetailDrawerComponent-->>User: Display breakdown or empty state
Loading

Possibly related PRs

Suggested labels: enhancement, e2e-tests

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: adding a score-breakdown drawer for leaderboard rows.
Description check ✅ Passed The description is directly related to the changeset and accurately describes the new drawer, integration, and tests.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/org-leaderboard-detail-drawer

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html`:
- Around line 364-368: The technical leaderboard row trigger at
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html#L364-L368
and ecosystem leaderboard row trigger at
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html#L494-L498
are mouse-only. Make both organization-cell triggers keyboard operable using an
accessible button while preserving row styling, or add equivalent focusable
Enter/Space handling and accessible names; keep each trigger opening
openLeaderboardDetail with its existing leaderboard type and row.

In
`@apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.ts`:
- Around line 427-432: Guard openLeaderboardDetail so it returns without opening
the drawer unless metric() is influence mode, and ensure both activity
leaderboard tables no longer expose a clickable row affordance or invoke this
handler. Add coverage confirming activity mode cannot open the score breakdown
while preserving influence-mode behavior.

In `@packages/shared/src/constants/org-leaderboard-detail-drawer.constants.ts`:
- Around line 46-194: Align ORG_LEADERBOARD_DETAIL_TECHNICAL_COMPANIES and
ORG_LEADERBOARD_DETAIL_ECOSYSTEM_COMPANIES with
ORG_LEADERBOARD_DETAIL_METHODOLOGY: ensure maintainer points are 10 whenever
counts.maintainer is positive and board points are 0 whenever counts.board is
zero, while recalculating affected scores as needed. Alternatively, explicitly
label both the demo data and methodology copy as illustrative so they are not
presented as matching calculations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e2dd5ffd-d0ee-4e0b-a244-a03a26d4ed7e

📥 Commits

Reviewing files that changed from the base of the PR and between 5c77906 and 104602c.

📒 Files selected for processing (11)
  • apps/lfx-one/e2e/org-project-detail.spec.ts
  • apps/lfx-one/src/app/modules/dashboards/components/org-leaderboard-detail-drawer/org-leaderboard-detail-drawer.component.html
  • apps/lfx-one/src/app/modules/dashboards/components/org-leaderboard-detail-drawer/org-leaderboard-detail-drawer.component.ts
  • apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html
  • apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.ts
  • packages/shared/src/constants/index.ts
  • packages/shared/src/constants/org-leaderboard-detail-drawer.constants.ts
  • packages/shared/src/interfaces/index.ts
  • packages/shared/src/interfaces/org-leaderboard-detail-drawer.interface.ts
  • packages/shared/src/utils/index.ts
  • packages/shared/src/utils/org-leaderboard-detail.utils.ts

Comment on lines 364 to +368
<tr
class="border-b border-gray-100"
class="cursor-pointer border-b border-gray-100 hover:bg-blue-50"
[class.bg-blue-50]="row.isViewingOrg"
[attr.data-testid]="row.isViewingOrg ? 'project-detail-leaderboard-technical-viewing-row' : null">
[attr.data-testid]="row.isViewingOrg ? 'project-detail-leaderboard-technical-viewing-row' : null"
(click)="openLeaderboardDetail('technical', row)">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make leaderboard-row activation keyboard accessible.

Both rows are mouse-only <tr> click targets, so keyboard users cannot open the drawer. Use a keyboard-operable button in the organization cell (while retaining the row styling), or provide equivalent focus, Enter/Space handling, and accessible naming.

  • apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html#L364-L368: make the technical-row trigger keyboard operable.
  • apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html#L494-L498: make the ecosystem-row trigger keyboard operable.
📍 Affects 1 file
  • apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html#L364-L368 (this comment)
  • apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html#L494-L498
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html`
around lines 364 - 368, The technical leaderboard row trigger at
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html#L364-L368
and ecosystem leaderboard row trigger at
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html#L494-L498
are mouse-only. Make both organization-cell triggers keyboard operable using an
accessible button while preserving row styling, or add equivalent focusable
Enter/Space handling and accessible names; keep each trigger opening
openLeaderboardDetail with its existing leaderboard type and row.

Comment on lines +427 to +432
/** Opens the leaderboard row score-breakdown drawer for the clicked technical/ecosystem row. */
protected openLeaderboardDetail(dimension: LeaderboardDimension, row: BoardDisplayRow): void {
this.leaderboardDetailDimension.set(dimension);
this.leaderboardDetailOrgName.set(row.orgName);
this.leaderboardDetailOpen.set(true);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not open a score breakdown from activity leaderboards.

This handler runs while metric() === 'activity', where the row represents contribution/collaboration counts rather than influence scores. It then opens a static influence-score breakdown for that organization. Guard this handler for influence mode and remove the clickable affordance from both activity tables; add activity-mode coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.ts`
around lines 427 - 432, Guard openLeaderboardDetail so it returns without
opening the drawer unless metric() is influence mode, and ensure both activity
leaderboard tables no longer expose a clickable row affordance or invoke this
handler. Add coverage confirming activity mode cannot open the score breakdown
while preserving influence-mode behavior.

Comment on lines +46 to +194
Google: {
rank: 1,
activityPct: 31,
score: 104,
points: { maintainer: 6, contributors: 22, commits: 52, prs: 24 },
counts: { maintainer: 1, contributors: 218, commits: 3842, prs: 296 },
},
'Red Hat': {
rank: 2,
activityPct: 24,
score: 98,
points: { maintainer: 18, contributors: 32, commits: 30, prs: 18 },
counts: { maintainer: 3, contributors: 314, commits: 2210, prs: 221 },
},
IBM: {
rank: 3,
activityPct: 13,
score: 71,
points: { maintainer: 22, contributors: 23, commits: 16, prs: 10 },
counts: { maintainer: 4, contributors: 226, commits: 1182, prs: 123 },
},
VMware: {
rank: 4,
activityPct: 9,
score: 58,
points: { maintainer: 15, contributors: 20, commits: 14, prs: 9 },
counts: { maintainer: 2, contributors: 196, commits: 1034, prs: 111 },
},
Microsoft: {
rank: 5,
activityPct: 21,
score: 68,
points: { maintainer: 6, contributors: 20, commits: 26, prs: 16 },
counts: { maintainer: 1, contributors: 197, commits: 1921, prs: 197 },
},
Intel: {
rank: 6,
activityPct: 11,
score: 47,
points: { maintainer: 6, contributors: 14, commits: 18, prs: 9 },
counts: { maintainer: 1, contributors: 137, commits: 1330, prs: 111 },
},
Cisco: {
rank: 7,
activityPct: 6,
score: 34,
points: { maintainer: 5, contributors: 10, commits: 12, prs: 7 },
counts: { maintainer: 1, contributors: 98, commits: 887, prs: 86 },
},
D2iQ: {
rank: 8,
activityPct: 3,
score: 22,
points: { maintainer: 3, contributors: 6, commits: 8, prs: 5 },
counts: { maintainer: 1, contributors: 59, commits: 591, prs: 62 },
},
};

/** DEMO DATA — illustrative per-company ecosystem-influence breakdown, keyed by org display name. */
export const ORG_LEADERBOARD_DETAIL_ECOSYSTEM_COMPANIES: Record<string, OrgLeaderboardDetailCompany> = {
'Red Hat': {
rank: 1,
activityPct: 22,
score: 96,
points: { collab: 40, meeting: 12, event: 10, committee: 12, board: 9, speakers: 7, meetup: 3, sponsor: 2, certified: 1 },
counts: { collab: 812, meeting: 145, event: 28, committee: 14, board: 2, speakers: 19, meetup: 9, sponsor: 3, certified: 12 },
},
Google: {
rank: 2,
activityPct: 27,
score: 88,
points: { collab: 46, meeting: 8, event: 12, committee: 4, board: 2, speakers: 9, meetup: 5, sponsor: 1, certified: 1 },
counts: { collab: 934, meeting: 97, event: 34, committee: 5, board: 0, speakers: 24, meetup: 15, sponsor: 2, certified: 8 },
},
IBM: {
rank: 3,
activityPct: 15,
score: 91,
points: { collab: 12, meeting: 16, event: 6, committee: 19, board: 18, speakers: 8, meetup: 4, sponsor: 5, certified: 3 },
counts: { collab: 244, meeting: 193, event: 17, committee: 22, board: 3, speakers: 21, meetup: 11, sponsor: 6, certified: 27 },
},
VMware: {
rank: 4,
activityPct: 11,
score: 62,
points: { collab: 18, meeting: 7, event: 5, committee: 6, board: 4, speakers: 5, meetup: 2, sponsor: 2, certified: 2 },
counts: { collab: 366, meeting: 85, event: 14, committee: 7, board: 1, speakers: 13, meetup: 6, sponsor: 3, certified: 15 },
},
Microsoft: {
rank: 5,
activityPct: 18,
score: 79,
points: { collab: 28, meeting: 10, event: 14, committee: 5, board: 3, speakers: 12, meetup: 4, sponsor: 2, certified: 1 },
counts: { collab: 571, meeting: 121, event: 39, committee: 6, board: 1, speakers: 31, meetup: 10, sponsor: 3, certified: 9 },
},
Intel: {
rank: 6,
activityPct: 9,
score: 54,
points: { collab: 14, meeting: 9, event: 4, committee: 8, board: 7, speakers: 4, meetup: 3, sponsor: 3, certified: 2 },
counts: { collab: 284, meeting: 109, event: 11, committee: 9, board: 2, speakers: 10, meetup: 8, sponsor: 4, certified: 14 },
},
Cisco: {
rank: 7,
activityPct: 7,
score: 41,
points: { collab: 10, meeting: 6, event: 4, committee: 5, board: 4, speakers: 4, meetup: 3, sponsor: 3, certified: 2 },
counts: { collab: 202, meeting: 73, event: 11, committee: 6, board: 1, speakers: 10, meetup: 8, sponsor: 4, certified: 13 },
},
D2iQ: {
rank: 8,
activityPct: 4,
score: 26,
points: { collab: 8, meeting: 3, event: 3, committee: 3, board: 2, speakers: 3, meetup: 2, sponsor: 1, certified: 1 },
counts: { collab: 162, meeting: 36, event: 8, committee: 4, board: 0, speakers: 8, meetup: 5, sponsor: 2, certified: 6 },
},
};

/** Condensed "Company influence metrics" methodology copy shown in the drawer, per dimension. */
export const ORG_LEADERBOARD_DETAIL_METHODOLOGY: Record<'technical' | 'ecosystem', OrgLeaderboardDetailMethodology> = {
technical: {
intro:
'Only four categories earn technical-influence points. Each earns points independently — there are no preset weights per category. Points from all categories are added together to get the total score.',
bullets: [
{ label: 'Maintainers', text: '— 10 pts if the company has 1+ project maintainers, else 0.' },
{
label: 'Contributors, Commit Activities, PRs Opened',
text: '— each 0.1% share of the project total earns 0.1 pt, plus a +1 bonus for any share above 0%.',
},
],
levelMapping: 'Total score maps to a level: 0 = Silent, 1–4 = Participating, 5–14 = Contributing, 15+ = Leading.',
},
ecosystem: {
intro:
'Each category below earns points independently — there are no preset weights per category. Points from all categories are added together to get the total score.',
bullets: [
{
label: 'Collaboration Activity, Meeting Attendance, Committee Members, Event Speakers',
text: '— each 0.1% share of the project/foundation total earns 0.1 pt, plus a +1 bonus for any share above 0%.',
},
{ label: 'Board Members', text: '— 1 pt if the company has 1+ foundation board members, else 0.' },
{
label: 'Event Attendance, Event Sponsorships, Meetup Attendance, Certified Individuals',
text: '— tiered by share: 0 / 0.33 / 0.66 / 1 pt for none / up to 25% / up to 50% / over 50%.',
},
],
levelMapping: 'Total score maps to a level: 0–2 = Silent, 3–10 = Participating, 11–19 = Contributing, 20+ = Leading.',
},
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Align the demo scores with the displayed methodology.

The drawer presents this as the scoring calculation, but the data contradicts it: Google has one technical maintainer worth 6 points (Lines 50-51) despite Line 170 saying that one maintainer earns 10; Google also has zero board members worth 2 points (Lines 117-118) despite Line 186 saying zero earns 0. Either make the demo values follow these rules or explicitly present both the data and copy as illustrative.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/shared/src/constants/org-leaderboard-detail-drawer.constants.ts`
around lines 46 - 194, Align ORG_LEADERBOARD_DETAIL_TECHNICAL_COMPANIES and
ORG_LEADERBOARD_DETAIL_ECOSYSTEM_COMPANIES with
ORG_LEADERBOARD_DETAIL_METHODOLOGY: ensure maintainer points are 10 whenever
counts.maintainer is positive and board points are 0 whenever counts.board is
zero, while recalculating affected scores as needed. Alternatively, explicitly
label both the demo data and methodology copy as illustrative so they are not
presented as matching calculations.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an Org Lens leaderboard drawer for viewing category-level influence score breakdowns, currently backed by placeholder data.

Changes:

  • Adds drawer UI and leaderboard row interactions.
  • Adds shared score types, constants, and calculations.
  • Adds Playwright coverage for opening and closing the drawer.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/shared/src/utils/org-leaderboard-detail.utils.ts Calculates levels and category rows.
packages/shared/src/utils/index.ts Exports the new utilities.
packages/shared/src/interfaces/org-leaderboard-detail-drawer.interface.ts Defines drawer data types.
packages/shared/src/interfaces/index.ts Exports the new interfaces.
packages/shared/src/constants/org-leaderboard-detail-drawer.constants.ts Provides placeholder breakdowns and methodology.
packages/shared/src/constants/index.ts Exports the new constants.
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.ts Manages drawer selection and visibility.
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html Makes leaderboard rows open the drawer.
apps/lfx-one/src/app/modules/dashboards/components/org-leaderboard-detail-drawer/org-leaderboard-detail-drawer.component.ts Implements drawer state and derived data.
apps/lfx-one/src/app/modules/dashboards/components/org-leaderboard-detail-drawer/org-leaderboard-detail-drawer.component.html Renders breakdown, methodology, and empty states.
apps/lfx-one/e2e/org-project-detail.spec.ts Tests drawer interactions.
Comments suppressed due to low confidence (3)

apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html:498

  • The ecosystem row has the same mouse-only interaction: it cannot receive focus or respond to Enter/Space, preventing keyboard users from opening its drawer. Add the same keyboard affordances used by other interactive table rows in this repository.
                          (click)="openLeaderboardDetail('ecosystem', row)">

packages/shared/src/constants/org-leaderboard-detail-drawer.constants.ts:189

  • The ecosystem breakdowns also cannot be produced by these displayed rules. For example, Google and D2iQ have zero board members but receive 2 board points even though the rule says zero, and Google receives 12 event-attendance points although the tiered rule caps that category at 1. Align the placeholder allocations with the methodology before presenting them together.
      { label: 'Board Members', text: '— 1 pt if the company has 1+ foundation board members, else 0.' },
      {
        label: 'Event Attendance, Event Sponsorships, Meetup Attendance, Certified Individuals',
        text: '— tiered by share: 0 / 0.33 / 0.66 / 1 pt for none / up to 25% / up to 50% / over 50%.',

apps/lfx-one/e2e/org-project-detail.spec.ts:345

  • This substring locator likewise matches the page's existing Ecosystem Influence Leaderboard heading as well as the drawer subtitle, causing a strict-mode failure. Scope it to the opened drawer so the test validates the intended dimension label.
    await expect(page.getByText('Ecosystem Influence')).toBeVisible();

[class.bg-blue-50]="row.isViewingOrg"
[attr.data-testid]="row.isViewingOrg ? 'project-detail-leaderboard-technical-viewing-row' : null">
[attr.data-testid]="row.isViewingOrg ? 'project-detail-leaderboard-technical-viewing-row' : null"
(click)="openLeaderboardDetail('technical', row)">
Comment on lines +130 to +131
score: 62,
points: { collab: 18, meeting: 7, event: 5, committee: 6, board: 4, speakers: 5, meetup: 2, sponsor: 2, certified: 2 },
position="right"
[modal]="true"
[showCloseIcon]="false"
styleClass="xl:w-[40%] lg:w-[50%] md:w-[65%] sm:w-[85%] w-full"
intro:
'Only four categories earn technical-influence points. Each earns points independently — there are no preset weights per category. Points from all categories are added together to get the total score.',
bullets: [
{ label: 'Maintainers', text: '— 10 pts if the company has 1+ project maintainers, else 0.' },
Comment on lines +32 to +37
export function orgLeaderboardDetailCategoryRows(
categories: OrgLeaderboardDetailCategory[],
points: Record<string, number>,
counts: Record<string, number>,
score: number
): OrgLeaderboardDetailCategoryRow[] {

await expect(page.getByTestId('org-leaderboard-detail-title')).toBeVisible();
await expect(page.getByTestId('org-leaderboard-detail-title')).toHaveText(orgName);
await expect(page.getByText('Technical Influence')).toBeVisible();

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 104602c. Configure here.

<span class="font-semibold text-blue-600">#{{ company()?.rank }}</span>
out of
<span class="font-semibold text-blue-600">{{ totalCompanies() }}</span>
companies participating in the project.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Summary sentence whitespace stripped

Medium Severity

The summary sentence separates styled spans from the following text with newline/indent only. With Angular's default preserveWhitespaces: false, those whitespace-only nodes are removed, so the copy runs together (for example level jammed into the dimension word, and % jammed into of).

Fix in Cursor Fix in Web

Triggered by learned rule: Flag whitespace-only text nodes between interpolation and @if/@for blocks — stripped by preserveWhitespaces: false

Reviewed by Cursor Bugbot for commit 104602c. Configure here.


await expect(page.getByTestId('org-leaderboard-detail-title')).toBeVisible();
await expect(page.getByTestId('org-leaderboard-detail-title')).toHaveText(orgName);
await expect(page.getByText('Ecosystem Influence')).toBeVisible();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ambiguous e2e influence text match

Medium Severity

getByText('Technical Influence') and getByText('Ecosystem Influence') also match the leaderboard board titles already on the page (Technical/Ecosystem Influence Leaderboard). After the drawer opens, Playwright strict mode can resolve multiple visible matches and fail the assertion.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 104602c. Configure here.

@danoqualls
danoqualls marked this pull request as draft July 30, 2026 20:13
@danoqualls danoqualls changed the title feat(dashboards): add score-breakdown drawer to leaderboard rows feat(org-lens): add score-breakdown drawer to leaderboard rows UI only Jul 30, 2026
@github-actions

Copy link
Copy Markdown

🚀 Deployment Status

Your branch has been deployed to: https://ui-pr-1276.dev.v2.cluster.linuxfound.info

Deployment Details:

  • Environment: Development
  • Namespace: ui-pr-1276
  • ArgoCD App: ui-pr-1276

The deployment will be automatically removed when this PR is closed.

Replaces the inline level chip with plain colored text, shrinks the
total-score value out of hero-stat territory, and gives the
methodology box's paragraphs and bullets explicit, consistent
size/weight classes instead of relying on inherited defaults.

LFXV2-2934

Signed-off-by: daniel qualls <dqualls@linuxfoundation.org>
Copilot AI review requested due to automatic review settings August 5, 2026 14:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (7)

apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html:368

  • These rows are mouse-only: adding (click) without a focus target or keyboard handlers prevents keyboard users from opening the drawer. Match the repository's interactive-row pattern (for example, foundation-row.component.html:4-10) by making the row focusable and handling Enter/Space.
                          class="cursor-pointer border-b border-gray-100 hover:bg-blue-50"
                          [class.bg-blue-50]="row.isViewingOrg"
                          [attr.data-testid]="row.isViewingOrg ? 'project-detail-leaderboard-technical-viewing-row' : null"
                          (click)="openLeaderboardDetail('technical', row)">

apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html:498

  • This second clickable row has the same mouse-only behavior, so keyboard users cannot open the ecosystem drawer. Make it focusable and activate it on Enter/Space as the existing interactive-row components do.
                          class="cursor-pointer border-b border-gray-100 hover:bg-blue-50"
                          [class.bg-blue-50]="row.isViewingOrg"
                          [attr.data-testid]="row.isViewingOrg ? 'project-detail-leaderboard-ecosystem-viewing-row' : null"
                          (click)="openLeaderboardDetail('ecosystem', row)">

packages/shared/src/constants/org-leaderboard-detail-drawer.constants.ts:131

  • VMware's ecosystem category points sum to 51, but score is 62. Because percentages use score as their denominator and the drawer labels the score as the category total, this renders a breakdown totaling only about 81% while showing “Total score 62 pts.” Reconcile the score and category points.
    score: 62,
    points: { collab: 18, meeting: 7, event: 5, committee: 6, board: 4, speakers: 5, meetup: 2, sponsor: 2, certified: 2 },

packages/shared/src/constants/org-leaderboard-detail-drawer.constants.ts:170

  • The displayed methodology says any company with maintainers earns exactly 10 points, but every technical fixture with a positive maintainer count assigns a different value (for example, Google shows 1 maintainer and 6 points). Users therefore see a breakdown that contradicts the “How this score is calculated” text in the same drawer. Make the fixtures follow this rule or adjust the methodology/demo model consistently.
      { label: 'Maintainers', text: '— 10 pts if the company has 1+ project maintainers, else 0.' },

apps/lfx-one/e2e/org-project-detail.spec.ts:333

  • getByText performs substring matching by default, and the page already contains “Technical Influence Leaderboard,” so after the drawer opens this locator matches both that heading and the drawer subtitle and fails strict-mode resolution. Use an exact match for the drawer label.
    await expect(page.getByText('Technical Influence')).toBeVisible();

apps/lfx-one/e2e/org-project-detail.spec.ts:345

  • This fuzzy text locator also matches the existing “Ecosystem Influence Leaderboard” heading in addition to the drawer subtitle, causing a Playwright strict-mode failure. Scope it to the drawer or request an exact match.
    await expect(page.getByText('Ecosystem Influence')).toBeVisible();

packages/shared/src/utils/org-leaderboard-detail.utils.ts:15

  • The new threshold and percentage calculations have no deterministic unit coverage. The added live-data E2E explicitly accepts either content or empty state, so it may never execute these helpers with a demo organization and cannot catch boundary, sorting, zero-score, or percentage regressions. Add a Vitest spec alongside this utility covering both dimensions' thresholds and category-row calculation.
export function orgLeaderboardDetailLevelFor(dimension: LeaderboardDimension, score: number): OrgLeaderboardDetailLevel {

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