Skip to content

feat(org-lens): org lens project detail page UI#1028

Open
danoqualls wants to merge 71 commits into
mainfrom
feat/LFXV2-1885
Open

feat(org-lens): org lens project detail page UI#1028
danoqualls wants to merge 71 commits into
mainfrom
feat/LFXV2-1885

Conversation

@danoqualls

@danoqualls danoqualls commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Business case: company can view their involvement in a project in a detailed way that adds up to influence in the project and compares influence to other companies. UI only with demo data. Includes both influence detail tab and leaderboards tab.

This pull request introduces the Org Lens Project Detail sub-page (LFXV2-1885) to the application, enabling users to view detailed analytics and leaderboard data for individual projects within an organization. It includes the new route and navigation entry, a complete UI with tabbed navigation, metric and time range toggles, demo data integration, and comprehensive E2E tests. Additionally, it restores interactivity for project rows in the Org Overview, allowing users to drill down into project details.

Org Lens Project Detail Feature Implementation:

  • Added the /org/projects/:projectSlug route, navigation entry, and associated metadata, enabling direct navigation to project detail pages. [1] [2]
  • Implemented the OrgProjectDetailService to provide demo data for the project detail page, designed for easy replacement with a real backend API in the future.
  • Created the OrgProjectDetailTabBarComponent for tabbed navigation, including keyboard accessibility, metric toggles, and time range selection. [1] [2]
  • Added comprehensive Playwright E2E tests covering rendering, tab navigation, leaderboard interactions, URL parameter persistence, and 404 handling for unknown slugs.

Org Overview Interactivity Restoration:

  • Restored click and keyboard handlers to project rows in the Org Overview, allowing users to navigate to the new project detail page and emitting telemetry events. [1] [2] [3]

Supporting and Miscellaneous Updates:

  • Exported new interfaces for the Org Lens Project Detail feature in the shared package.
  • Minor improvement to the Valkey cache service for more robust JSON retrieval.

Summary

  • Adds the Org Lens Project Detail sub-page at /org/projects/:projectSlug, opened from the Overview's Foundations & Projects table
  • Backed by a TypeScript demo-data service (org-lens-project-detail.demo-data.ts) via a new service + controller + route — demo company data only; real Snowflake integration is a separate story. Note: there is no static JSON fixture; all demo payloads are generated server-side in TypeScript.
  • Two tabs — Our Influence (default) and Leaderboards — with tab/metric/range state persisted as query params (?tab=, ?metric=, ?range=)

Our Influence tab:

  • Hero block (logo, name, description, LFX Insights link, First commit, Software value, Health badge, Foundation pill)
  • Technical Influence section (Maintainers, Contributors, Commit Activities, Pull Requests, Avg Merge Time) — horizontal carousel with scrolling chevrons; each card opens a detail drawer
  • Ecosystem Influence section (Collaboration Activity, Meeting Attendance, Board Members, Committee Members, Event Attendance, Event Speakers, Training Completions, Certified Individuals, Mailing List Posts)
  • Per-card influence chart (area / bar / line variants with custom external tooltip)
  • Card detail drawer: definition table + card-specific data table

Leaderboards tab:

  • Side-by-side Technical / Ecosystem leaderboard tables with search, PrimeNG paginator, viewing-org row highlighted, band tags (Leading / Contributing / Participating / Non-LF)
  • Metric toggle (Calculated Influence / Activity Count) + time range pill group (1y / 2y / All time) in the shared tab bar
  • Stacked 100% area trend chart showing top-10 companies' share over time with deterministic demo trajectories

Shell:

  • Page-state machine (loading / error / notFound / ready) with <p-skeleton> loading states and lfx-empty-state error/not-found panels
  • Breadcrumb: Projects → <project name>
  • All sections use data-testid attributes; E2E coverage added

PR size rationale

This PR is ~2,500 lines. The branch builds the complete Project Detail page end-to-end (scaffold → hero → influence cards → trend chart → leaderboards → e2e → polish). The intermediate commits are not independently shippable — routing and the data layer land without visible UI until the component is complete. Splitting at a natural seam (e.g., scaffold-only or data-layer-only) would merge dead routes that don't render. The full page is the atomic unit of work here, consistent with how the sibling Membership Detail page (PR #921) was delivered.

Test plan

  • Start dev server with org lens flag enabled; open /org/overview, expand a foundation, click an LF project row → lands on /org/projects/<slug>
  • Hero renders all tiles (name, description, LFX Insights link, First commit, Software value, Health badge, Foundation)
  • Tab switch updates ?tab= and survives page reload
  • Technical + Ecosystem cards render counts, trendlines; clicking a card opens the detail drawer with definition + data table
  • Influence Trend stacked area chart renders with correct ordering (most influential at bottom); time range pills update the dataset window
  • Leaderboard tables rank orgs, pin the viewing-org row (highlighted), paginator works
  • Metric toggle switches between Calculated Influence (band tag) and Activity Count (numeric)
  • Time range pills update ?range= query param and persist on reload
  • Unknown slug shows the not-found panel; Back to Projects navigates to /org/projects
  • Playwright E2E suite passes: yarn e2e

🤖 Generated with Claude Code

@danoqualls danoqualls requested a review from a team as a code owner June 24, 2026 21:21
Copilot AI review requested due to automatic review settings June 24, 2026 21:21
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds an Org Lens project-detail route, API, demo payloads, page rendering logic, and E2E coverage, plus a Valkey JSON cache miss handling tweak.

Changes

Org Project Detail

Layer / File(s) Summary
Route entry points
apps/lfx-one/src/app/app.routes.ts, apps/lfx-one/src/app/modules/dashboards/org/components/org-overview-foundations-and-projects/*
Adds the project-detail route and makes LF project rows navigate to that deep link on click and keyboard activation.
Shared contracts and API wiring
packages/shared/src/constants/*, packages/shared/src/interfaces/*, apps/lfx-one/src/app/shared/services/org-lens-project-detail.service.ts, apps/lfx-one/src/server/services/org-lens-project-detail.service.ts, apps/lfx-one/src/server/controllers/org-lens-project-detail.controller.ts, apps/lfx-one/src/server/routes/orgs.route.ts
Adds the project-detail constants and payload types, the client fetch wrapper, and the server controller/service route that returns JSON or 404 for the project detail API.
Demo payload generation
apps/lfx-one/src/server/services/org-lens-project-detail.demo-data.ts
Builds deterministic demo project detail responses with seeded cards, leaderboard rows, trend points, and drawer sections for known slugs.
Page logic and chart transforms
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.ts
Derives tab and query-param state, fetch state, leaderboard filters, chart view models, and stacked trend data for the project-detail page.
Templates and tab bar
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail-tab-bar.*, apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html
Renders the project-detail tab bar, page states, hero, influence tracks, leaderboards, trend chart, and drawer content.
E2E coverage
apps/lfx-one/e2e/org-project-detail.spec.ts
Adds Playwright coverage for page rendering, tab and metric URL behavior, leaderboard search, and the not-found state.

Valkey typing

Layer / File(s) Summary
Typed cache miss handling
apps/lfx-one/src/server/services/valkey.service.ts
Changes getJson to cast the raw Valkey value to `string

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • linuxfoundation/lfx-self-serve#753: Also changes the org route subtree in apps/lfx-one/src/app/app.routes.ts, which is directly related to the new project-detail deep link.
  • linuxfoundation/lfx-self-serve#754: Also changes the org-lens server routing layer in apps/lfx-one/src/server/routes/orgs.route.ts, which is directly related to the new project-detail API route.
  • linuxfoundation/lfx-self-serve#756: Also adds Org Lens project row navigation in apps/lfx-one/src/app/modules/dashboards/org/components/org-overview-foundations-and-projects/*, which is part of the same entry path into the new page.

Suggested labels

org-lens, enhancement

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Description check ✅ Passed The description matches the changeset by summarizing the new project detail page, routing, demo data, tabs, overview drilldown, and E2E tests.
Title check ✅ Passed The title accurately summarizes the main change: adding the Org Lens project detail page UI.
✨ 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/LFXV2-1885

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

@github-actions

Copy link
Copy Markdown

🚀 Deployment Status

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

Deployment Details:

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

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

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 the Org Lens Project Detail page under /org/projects/:projectSlug, introducing shared payload contracts plus a frontend demo-data seam and new UI (tabs, charts, drawer details) with query-param state. The PR also wires a new org route and updates navigation/telemetry touchpoints, and adds Playwright coverage.

Changes:

  • Add shared OrgLensProjectDetailResponse contracts and export them from @lfx-one/shared/interfaces.
  • Implement the Org Project Detail page UI (tabs, influence cards, leaderboards, stacked trend chart, card-detail drawer) backed by demo fixtures and a new Angular service.
  • Add org routing + E2E tests; minor Valkey cache read typing tweak.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
packages/shared/src/interfaces/org-lens-project-detail.interface.ts Adds shared API contracts for Org Lens Project Detail payloads.
packages/shared/src/interfaces/index.ts Re-exports the new Project Detail interfaces from the interfaces barrel.
apps/lfx-one/src/server/services/valkey.service.ts Tightens getJson typing for Valkey reads and null handling.
apps/lfx-one/src/app/shared/services/org-lens-project-detail.service.ts Adds a frontend service seam for loading project detail (currently demo-backed).
apps/lfx-one/src/app/shared/services/org-lens-project-detail.demo-data.ts Adds large deterministic demo fixture generator for the project detail page.
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.ts Implements page state machine, query-param persistence, leaderboard ranking, and chart dataset construction.
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail.component.html Implements page shell, hero, tabs, influence cards, leaderboards, trend chart, and drawer markup with testids.
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail-tab-bar.component.ts Adds the shared tab/metric/range control bar with keyboard navigation.
apps/lfx-one/src/app/modules/dashboards/org/org-project-detail/org-project-detail-tab-bar.component.html Tab bar template (tablist + metric toggle + time-range pills).
apps/lfx-one/src/app/modules/dashboards/org/components/org-overview-foundations-and-projects/org-overview-foundations-and-projects.component.ts Adds telemetry + navigation handlers intended to open project detail from overview rows.
apps/lfx-one/src/app/layouts/main-layout/main-layout.component.ts Re-enables “Projects” entry in Org Lens sidebar section.
apps/lfx-one/src/app/app.routes.ts Adds the /org/projects/:projectSlug route entry.
apps/lfx-one/e2e/org-project-detail.spec.ts Adds Playwright E2E coverage for project detail page behaviors and URL persistence.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/lfx-one/src/app/layouts/main-layout/main-layout.component.ts Outdated
Comment thread apps/lfx-one/src/app/app.routes.ts
Comment thread apps/lfx-one/e2e/org-project-detail.spec.ts
Comment thread apps/lfx-one/e2e/org-project-detail.spec.ts
Comment thread apps/lfx-one/e2e/org-project-detail.spec.ts
@danoqualls danoqualls changed the title feat(org-lens): org lens project detail page (LFXV2-1885) feat(org-lens): org lens project detail page UI (LFXV2-1885) Jun 25, 2026
Copilot AI review requested due to automatic review settings June 25, 2026 03:03

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 13 out of 13 changed files in this pull request and generated 5 comments.

Comment thread apps/lfx-one/e2e/org-project-detail.spec.ts
Comment thread apps/lfx-one/e2e/org-project-detail.spec.ts
Comment thread apps/lfx-one/e2e/org-project-detail.spec.ts
Copilot AI review requested due to automatic review settings June 25, 2026 03:08
@danoqualls danoqualls removed the request for review from Copilot June 25, 2026 03:08
Copilot AI review requested due to automatic review settings June 25, 2026 03:20
@danoqualls danoqualls removed the request for review from Copilot June 25, 2026 03:20
danoqualls added a commit that referenced this pull request Jun 25, 2026
Address review comments from copilot-pull-request-reviewer,
copilot-swe-agent:

- org-project-detail.component.ts: make scoreColumnLabel dynamic using
  TIME_RANGE_MONTHS[timeRange()] so Activity column shows correct period
  for 2y/all ranges, not hard-coded (12mo) (per copilot-pull-request-reviewer)
- org-project-detail.component.ts: fix All others stacked trend to use
  the SUM of scores, not average — average understates the aggregate
  (per copilot-swe-agent)
- org-overview-foundations-and-projects.component.html: restore project
  row click/keydown handlers now that the detail drilldown page is built;
  remove the deferred-until-ready comment (per copilot-pull-request-reviewer)
- org-lens-project-detail.service.ts: remove Generated-with comment
  (per copilot-pull-request-reviewer)
- e2e/org-project-detail.spec.ts: move project-detail-trend-group
  assertion to the leaderboards test where it is actually rendered
  (per copilot-swe-agent)
- e2e/org-project-detail.spec.ts: remove stale ?score=/ from JSDoc —
  only ?metric= is used (per copilot-swe-agent)

Resolves 5 review threads; 2 threads addressed via responses only
(breadcrumb/CTA route and SSR endpoint are intentional by design).

Signed-off-by: daniel qualls <dqualls@linuxfoundation.org>
Copilot AI review requested due to automatic review settings June 25, 2026 13:03

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 16 out of 16 changed files in this pull request and generated 4 comments.

@danoqualls

Copy link
Copy Markdown
Contributor Author

Review Feedback Addressed

Commits: 7e6218f, 8373620

Changes Made

  • org-project-detail.component.html / app.routes.ts: not-found CTA and breadcrumb home now route to `/org/overview` — the `/org/projects` list page is being delivered in LFXV2-1883 / PR feat(org-lens): add projects page UI #921 (per copilot-pull-request-reviewer)
  • org-overview-foundations-and-projects.component.html: project row click/keydown handlers wired; deferred comment removed now that the detail page is built (per copilot-pull-request-reviewer)
  • org-lens-project-detail.service.ts / orgs.route.ts: service migrated from demo-data shim to `HttpClient` calling `GET /api/orgs/:orgUid/lens/projects/:projectSlug`; SSR controller and route registered (per copilot-pull-request-reviewer)
  • org-project-detail.component.ts: `scoreColumnLabel` is now computed dynamically — `Activity (12mo)`, `Activity (24mo)`, or `Activity (36mo)` based on the active time range (per copilot-pull-request-reviewer)
  • org-project-detail.component.ts: `buildStackedTrend()` All others now uses sum of remaining scores instead of average (per copilot-swe-agent)
  • e2e/org-project-detail.spec.ts: `project-detail-trend-group` assertion moved — now asserts after navigating to Leaderboards tab (where the section is rendered); also added to the leaderboards describe block (per copilot-swe-agent)
  • e2e/org-project-detail.spec.ts: removed stale `?score=/` from JSDoc — only `?metric=` is used (per copilot-swe-agent)

Threads Resolved

7 of 7 unresolved threads addressed in this iteration.

Copilot AI review requested due to automatic review settings June 25, 2026 13:17

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 18 out of 18 changed files in this pull request and generated 3 comments.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Dano Qualls <mynameisdano@gmail.com>
Copilot AI review requested due to automatic review settings June 30, 2026 01:57
danoqualls and others added 2 commits June 29, 2026 19:57
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Dano Qualls <mynameisdano@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Dano Qualls <mynameisdano@gmail.com>

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 18 out of 18 changed files in this pull request and generated 3 comments.

Copilot AI review requested due to automatic review settings June 30, 2026 02:01

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 18 out of 18 changed files in this pull request and generated 3 comments.

Address review comments from copilot-pull-request-reviewer:

- org-project-detail.component.ts: add drawerTimeRangeLabel computed
  signal that derives the month count from TIME_RANGE_MONTHS[timeRange()]
  so the drawer subtitle reflects the active time window (per copilot-pull-request-reviewer)
- org-project-detail.component.html: replace hard-coded "Last 12 months"
  in drawer subtitle with drawerTimeRangeLabel() (per copilot-pull-request-reviewer)
- org-project-detail.component.html: change [alt]="row.orgName + ' logo'"
  to alt="" on both leaderboard org logo images — they are decorative
  (org name shown as adjacent text) so aria-hidden="true" + empty alt is
  correct per WCAG; the previous mixed semantics (aria-hidden + non-empty
  alt) were flagged as inconsistent (per copilot-pull-request-reviewer)

Resolves 3 review threads.

Signed-off-by: daniel qualls <dqualls@linuxfoundation.org>
@danoqualls

Copy link
Copy Markdown
Contributor Author

Review Feedback Addressed

Commit: 200039d

Changes Made

  • org-project-detail.component.ts: Added drawerTimeRangeLabel computed signal that derives the label from TIME_RANGE_MONTHS[timeRange()], matching the existing scoreColumnLabel pattern — so the drawer subtitle ("Last N months") stays accurate as the time range toggle changes (per copilot-pull-request-reviewer)
  • org-project-detail.component.html: Replaced hard-coded "Last 12 months" in the drawer subtitle with {{ drawerTimeRangeLabel() }} (per copilot-pull-request-reviewer)
  • org-project-detail.component.html: Changed [alt]="row.orgName + ' logo'" to alt="" on both leaderboard org logo <img> elements (technical and ecosystem tables) — the org name is displayed as adjacent text, so the images are decorative; aria-hidden="true" + empty alt is the correct WCAG pattern (per copilot-pull-request-reviewer)

Threads Resolved

3 of 3 unresolved threads addressed in this iteration.

Copilot AI review requested due to automatic review settings June 30, 2026 13:17

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 18 out of 18 changed files in this pull request and generated 2 comments.

Address review comments from copilot-pull-request-reviewer:

- org-project-detail.component.ts: replace activityFor() synthetic
  formula with entry.row.activityCount from the wire contract in
  buildBoard() — the formula (score * 46 * months/12) was reading the
  dimensional score instead of combined and applying a scaling factor
  not present in the payload, diverging from OrgLensProjectLeaderboardRow
  .activityCount which is already computed on the server (per
  copilot-pull-request-reviewer, lines 277 and 293)
- org-project-detail.component.ts: remove the now-unused activityFor()
  private method

Resolves 2 review threads.

Signed-off-by: daniel qualls <dqualls@linuxfoundation.org>
@danoqualls

Copy link
Copy Markdown
Contributor Author

Review Feedback Addressed

Commit: 3300654

Changes Made

  • org-project-detail.component.ts: Replaced this.activityFor(entry.score).toLocaleString() with entry.row.activityCount.toLocaleString() in buildBoard() — the displayed activity count now reads directly from the OrgLensProjectLeaderboardRow.activityCount field on the payload instead of a synthetic formula (score * 46 * months/12) that was using the dimensional score rather than combined and applied a client-side scaling factor not present in the wire contract (per copilot-pull-request-reviewer)
  • org-project-detail.component.ts: Removed the now-unused activityFor() private method

Threads Resolved

2 of 2 unresolved threads addressed in this iteration.

…t files

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

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 18 out of 18 changed files in this pull request and generated 1 comment.

Address review comments from copilot-pull-request-reviewer:

- org-project-detail.component.ts: removed unused `sourceUrl` computed
  signal (per copilot-pull-request-reviewer)

Resolves 1 review thread.

Signed-off-by: daniel qualls <dqualls@linuxfoundation.org>
@danoqualls

Copy link
Copy Markdown
Contributor Author

Review Feedback Addressed

Commit: 895a694

Changes Made

  • org-project-detail.component.ts: removed unused sourceUrl computed signal that was declared but never referenced in the template or class body (per copilot-pull-request-reviewer)

Threads Resolved

1 of 1 unresolved threads addressed in this iteration.

@luismoriguerra

Copy link
Copy Markdown
Contributor

Audit: PR #1028 — feat(org-lens): org lens project detail page UI (LFXV2-1885)

@danoqualls · head 895a694cmain · OPEN · 18 files, +2666/−9 · LFXV2-1885

Scope: Org Lens Project Detail page (/org/projects/:projectSlug) — BFF demo-data endpoint, Angular UI (tabs, influence cards, leaderboards, charts), shared contracts, Playwright e2e, Valkey typing tweak.

Lanes run: lint/format/types/build (worktree) · secrets (6a) · ui-reviewer (6b) · architecture (6c) · v2-knowledge drift questions (6d)


1. Why this change

Delivers LFXV2-1885: a per-project Org Lens view so a company can see detailed influence analytics and cross-org leaderboards. UI-only with server-side TypeScript demo fixtures; Snowflake integration is explicitly deferred. Restores Overview row click/keyboard navigation into the new page.

2. How it was done

Layer Mechanism
Route /org/projects/:projectSlug; sidebar “Projects” re-enabled
BFF GET /api/orgs/:orgUid/lens/projects/:projectSlug → controller → service → org-lens-project-detail.demo-data.ts
Client HttpClient proxy; large signal-based component with ?tab= / ?metric= / ?range= persistence
Contracts @lfx-one/shared interfaces + org-lens-project-detail.constants.ts
Tests Playwright e2e/org-project-detail.spec.ts

Matches the established Org Lens BFF seam (validation + Cache-Control: no-store + service-owned data).

3. Is it correct

Gates re-run (isolated worktree after yarn install):

Check Result
yarn lint
yarn format:check
yarn check-types
yarn build
yarn e2e ⏭ not run (needs dev server + auth + org-lens flag)

Prior review threads — resolved @ 895a694c:

Finding Status
Template method calls (bandChipClass, personInitials) ✅ Fixed
Local types/constants in component ✅ Moved to @lfx-one/shared
Cache-Control: no-store on 404 ✅ Fixed
Prettier / format:check ✅ Fixed
Overview row click handlers ✅ Fixed
Not-found CTA routing ✅ Fixed

Architecture: No provable ADR violations. Aligns with ADR 0017 - account-scoped reads hosted at the data owner, ADR 0008 - CQRS OpenSearch derived copy (N/A here), ADR 0021 - public HTTPS query API.

Security: No medium+ findings — session auth on /api/*, demo fixtures only, client path encoding, tooltip text escaped.

4. Missing / gaps

  1. 🔴 BlockingActivity metric mode does not re-rank leaderboards (org-project-detail.component.ts ~276–279). buildBoard() always sorts by scores[dimension] while activity mode displays activityCount. Rank should follow the active metric per the shared contract. (Inline comment posted.)

  2. 🟡 Non-blocking — Overview nav uses projectSlug only; testid falls back to projectId — align before real data.

  3. 🟡 Non-blocking.trim() in template bindings (lines 256, 333) — use computed signals per repo convention.

  4. 🟡 Non-blocking — Tab bar missing OnPush; LFXV2-1885 ticket refs in shipped comments; e2e missing error/Retry path; PR body ## Test plan section (move checklist to Jira per team convention).

  5. 🟡 Pre-GA — Demo data always-on without prod gate — confirm rollout plan before GA.

5. Q&A this PR resolves

  • Q: Why server-side demo data instead of a JSON fixture? — A: TypeScript generator in org-lens-project-detail.demo-data.ts is slug-keyed and deterministic; only the service body swaps to Snowflake later.
  • Q: What happens on unknown slug? — A: Server 404 → client nullnotFound panel.
  • Q: How does tab/metric/range persist? — A: Query params ?tab=, ?metric=, ?range= read on init and written on interaction.
  • Q: Why is Valkey touched? — A: Unrelated typing/null guard on getJson; no TTL or behavior change.
  • Q: Does this add org-level FGA on the BFF? — A: No — same as sibling org-lens read routes (session auth + assertOrgUid).

6. Business rules & ADRs

Business rules encoded:

  • Project health: excellent | healthy | at-risk
  • Leaderboard bands via markup-mu thresholds
  • Modes: influence (band tag) vs activity (count); ranges 1y | 2y | all
  • Viewing-org row always present and highlighted
  • Demo lookup keyed by projectSlug
ADR Alignment
ADR 0017 - account-scoped reads hosted at the data owner ✅ BFF-hosted read seam
ADR 0015 - dual authorization planes ✅ Session auth; no new FGA deviation vs peers
ADR 0008 - CQRS OpenSearch derived copy N/A (in-memory demo)

ADR status: none added/updated for merge.

7. Open questions & confirmations

  • (confirm) Projects list still uses client-side demo while Detail uses BFF — is Detail the canonical seam going forward?
  • (confirm) Demo-always-on in production — is org-lens flag gating sufficient until Snowflake GA?
  • (confirm) Missing per-org grant check matches peer lens reads — intentional through demo phase?

Verdict: 🔴 Required changes

Merge readiness: blocked-on-activity-metric-ranking — fix buildBoard() sort when ?metric=activity; remaining items are convention or pre-GA follow-up.

(Comment-only review — not requesting changes via GitHub review state.)

@luismoriguerra luismoriguerra 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.

Inline annotations for the blocking activity-metric ranking gap and two convention nits. Full audit report is in the top-level comment above.

Comment on lines +276 to +279
private buildBoard(dimension: LeaderboardDimension, search: string) {
const valued = (this.detail()?.leaderboard ?? []).map((row) => ({ row, score: row.scores[dimension] }));
valued.sort((a, b) => b.score - a.score || a.row.orgName.localeCompare(b.row.orgName));
const ranked = valued.map((entry, i) => {

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.

🔴 Blocking — activity metric does not re-rank rows

buildBoard() always sorts by row.scores[dimension], but when ?metric=activity the table shows activityCount while # rank still reflects influence scores. The shared contract says rank is derived from the active metric (OrgLensProjectLeaderboardRow JSDoc).

Suggested fix: when this.metric() === 'activity', sort by row.activityCount instead; only compute bandLabel / bandSeverity in influence mode.

Consider an e2e assertion that toggling to Activity Count changes rank order when counts and influence scores diverge.

protected onProjectRowClick(project: OrgLensFoundationRow['projects'][number]): void {
if (!project.isLfProject) return;
this.onProjectClick({ projectId: project.projectId, projectName: project.projectName });
void this.router.navigate(['/org/projects', project.projectSlug]);

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.

🟡 Non-blocking — slug fallback mismatch

The template testid already falls back to projectId when projectSlug is empty, but navigation always uses project.projectSlug. Before Snowflake wiring, align nav with the same fallback (projectSlug || projectId) so a row click cannot land on a route the fetch pipeline rejects (filter(!!slug)).

</div>
@if (technicalBoard().length === 0) {
<p class="py-8 text-center text-sm text-gray-500" data-testid="project-detail-leaderboard-technical-empty">
{{ techSearch().trim() ? 'No organizations match your search.' : 'No ranked organizations for this project yet.' }}

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.

🟡 Non-blocking — method call in template

techSearch().trim() (and the ecosystem twin at line 333) violates the repo convention against function calls in template bindings. Prefer computed signals such as techSearchTrimmed / ecoSearchTrimmed.

@danoqualls danoqualls changed the title feat(org-lens): org lens project detail page UI (LFXV2-1885) feat(org-lens): org lens project detail page UI Jul 1, 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.

5 participants