Skip to content

feat(dashboards): scaffold org lens shell, nav, and selector#646

Draft
ahmedomosanya wants to merge 15 commits into
mainfrom
feat/CD-3507-org-lens-shell
Draft

feat(dashboards): scaffold org lens shell, nav, and selector#646
ahmedomosanya wants to merge 15 commits into
mainfrom
feat/CD-3507-org-lens-shell

Conversation

@ahmedomosanya
Copy link
Copy Markdown

@ahmedomosanya ahmedomosanya commented May 5, 2026

WIP / Draft. Phase 1 of the Org Lens — page shell, sidebar nav, and org selector only. Body sections (involvement carousel, marketing overview, ROI, etc.) are intentionally deferred to follow-up tickets and are routed to a shared placeholder page in the meantime.

Ticket: CD-3507

Summary

  • Org Overview page (/org/overview) — {Company Name} Overview header with a membership-tier <lfx-tag> pill (e.g. Platinum Member, Gold Member). No body content yet.
  • Sidebar nav matching the design mock — three sections (Org Foundations, Org Engagement, Org Admin) covering 11 sub-pages, all backed by a single OrgPlaceholderPageComponent that reads title / description / icon from the route's data and renders a <lfx-empty-state> "coming soon" body.
  • <lfx-org-selector> — visually mirrors <lfx-project-selector> (avatar tile + name + chevron + popover with search). Driven by the existing AccountContextService rather than the paginated NavigationService, since the account list is small and known up front.
  • Account model extended with optional accountSlug / logoUrl / membershipTier / accountsRelated. Demo data seeded for Toyota (single org → no related accounts) and Red Hat → IBM family (conglomerate → siblings shown in the selector).
  • Sidebar / layout wiringMainLayoutComponent passes showOrgSelector when the org lens is active; SidebarComponent treats the org lens as always-loaded so the static menu renders immediately (no skeleton flash).
  • Routing/org redirects to /org/overview for backwards compatibility.

Out of scope (intentionally)

  • Real Org Overview body sections (involvement carousel, marketing overview, ROI cards, etc.) — covered by follow-up tickets.
  • Persona-based gating of who may switch orgs in the selector. Today the selector is always interactive; permission gating will land alongside the broader Org Lens persona work.
  • Replacing the hardcoded account stubs with a live API. Toyota + IBM family are placeholder seed data.
  • Slugs in URLs (e.g. /org/red-hat/overview) — kept simple as /org/<page> for Phase 1; revisit when multi-org URLs become a concern.

Test plan

  • /org/overview renders {Company Name} Overview + the correct tier badge for the selected account
  • Org selector opens, filters by name, and switches the active account
  • Selecting Red Hat shows IBM family as related accounts in the popover
  • Selecting Toyota shows no related accounts
  • Each Org Lens sidebar item routes to a placeholder page with the right title/description/icon
  • /org redirects to /org/overview
  • Sidebar org selector only appears in the Org Lens (not in Project / Foundation lenses)
  • yarn build and yarn check-types pass
  • Manual a11y pass on selector popover (keyboard, focus return)

Copilot AI review requested due to automatic review settings May 5, 2026 21:49
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

Important

Review skipped

Draft detected.

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3a42499c-b1d4-4fc6-a627-163d248eac76

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/CD-3507-org-lens-shell

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

@ahmedomosanya ahmedomosanya added ai-assisted A task or activity that was supported by AI, such as CoPilot, ChatGPT, or other AI technology. enhancement New feature or request WIP labels May 5, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Scaffolds the new Org Lens in lfx-one by adding org-specific routes, sidebar navigation, an org selector, and a simple overview/placeholder experience backed by seeded account metadata in the shared package.

Changes:

  • Adds Org Lens routes for overview plus 11 placeholder subpages, and wires the sidebar/main layout to render org-specific navigation.
  • Introduces <lfx-org-selector> and extends the shared Account model/constants with org display metadata.
  • Adds an Org Overview page and shared placeholder page component for deferred sections.

Key findings:

  • The new org selector currently filters the global availableAccounts() list, so accountsRelated never controls the switchable orgs; Toyota still exposes the IBM family and all other seeded orgs.
  • OrgOverviewComponent reads selectedAccount().membershipTier, but AccountContextService.initializeUserOrganizations() repopulates selectedAccount from SSR org objects that only contain accountId/accountName, so the new tier badge disappears after refresh for Toyota/Red Hat.
  • accountsRelated: IBM_FAMILY includes Red Hat itself, so Red Hat counts itself as a related account.
  • Adding recursive accountsRelated to the shared Account model bloats the persisted selected-account cookie with display-only metadata.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/shared/src/interfaces/account.interface.ts Extends shared Account with org lens metadata fields.
packages/shared/src/constants/accounts.constants.ts Seeds demo org/account metadata, including Toyota and IBM-family data.
apps/lfx-one/src/app/shared/components/sidebar/sidebar.component.ts Enables org selector rendering and marks org lens nav as always loaded.
apps/lfx-one/src/app/shared/components/sidebar/sidebar.component.html Renders the org selector in the sidebar.
apps/lfx-one/src/app/shared/components/org-selector/org-selector.component.ts Adds selector behavior, filtering, and account switching.
apps/lfx-one/src/app/shared/components/org-selector/org-selector.component.scss Styles/org popover positioning for the selector.
apps/lfx-one/src/app/shared/components/org-selector/org-selector.component.html Adds the org selector trigger and popover UI.
apps/lfx-one/src/app/modules/dashboards/org/org-overview/org-overview.component.ts Adds org overview state derived from selected account.
apps/lfx-one/src/app/modules/dashboards/org/org-overview/org-overview.component.html Renders overview title, tier badge, and placeholder summary copy.
apps/lfx-one/src/app/modules/dashboards/org/components/org-placeholder-page/org-placeholder-page.component.ts Adds reusable placeholder page component for deferred org sections.
apps/lfx-one/src/app/modules/dashboards/org/components/org-placeholder-page/org-placeholder-page.component.html Renders placeholder page header and empty state.
apps/lfx-one/src/app/layouts/main-layout/main-layout.component.ts Replaces old org nav with the new Org Lens sidebar structure.
apps/lfx-one/src/app/layouts/main-layout/main-layout.component.html Passes showOrgSelector into desktop and mobile sidebars.
apps/lfx-one/src/app/app.routes.ts Adds Org Lens routes and /org/org/overview redirect.

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

Comment thread apps/lfx-one/src/app/shared/components/org-selector/org-selector.component.ts Outdated
Comment thread packages/shared/src/constants/accounts.constants.ts Outdated
Comment thread packages/shared/src/interfaces/account.interface.ts Outdated
@ahmedomosanya ahmedomosanya force-pushed the feat/CD-3507-org-lens-shell branch from db49898 to efae135 Compare May 5, 2026 21:55
@ahmedomosanya ahmedomosanya changed the title feat(dashboards): scaffold Org Lens shell, nav, and selector (CD-3507) feat(dashboards): scaffold org lens shell, nav, and selector May 5, 2026
Mirrors the Org Lens HTML mock: an Org Overview page with the company
name + membership-tier badge, a sidebar nav grouped into Org
Foundations / Org Engagement / Org Admin, and an org selector that
swaps the active account (single-org or conglomerate). Body sections
beyond the header are intentionally out of scope and routed to a
shared placeholder page until follow-up tickets ship.

- Add OrgOverviewComponent (header + <lfx-tag> tier badge)
- Add OrgPlaceholderPageComponent backing 11 sub-routes via route data
- Add <lfx-org-selector> mirroring <lfx-project-selector> visually,
  driven by AccountContextService (no async navigation fetch)
- Wire sidebar/main-layout to render the org selector and treat the
  org lens as always-loaded (static menu items)
- Extend Account with optional accountSlug / logoUrl / membershipTier
  / accountsRelated and seed Toyota (single) and Red Hat -> IBM family
  (conglomerate) for the demo
- Redirect legacy /org -> /org/overview

Generated with [Cursor Composer](https://cursor.com/composer)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: ahmedomosanya <aopeyemi@contractor.linuxfoundation.org>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 5, 2026

🚀 Deployment Status

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

Deployment Details:

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

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

Layer the conglomerate dropdown UX and the cdev_org_id data contract
on top of the org lens shell from CD-3507. The org selector now
promotes any IBM-family member to parent and stacks the rest of the
family underneath, while the shared Account interface gains the
cdev_org_id field that mirrors how the persona service will return
both Salesforce account_id and Crowd.dev identifiers per org.

- Add cdevOrgId to the Account interface (Crowd.dev secondary id)
- Trim ACCOUNTS to Toyota + the full IBM family; every member shares
  the same accountsRelated reference so any selection promotes itself
  to parent in the dropdown
- Replace the flat dropdown with a typed displayGroups signal that
  picks the parent dynamically and stacks the remaining family
  underneath; search collapses back to a flat filtered list
- Enrich incoming organizations from ACCOUNTS in
  AccountContextService.initializeUserOrganizations so sparse
  persona-side data still surfaces tier, logo, and family
- Strip the cyclic accountsRelated before cookie persistence to avoid
  the Converting circular structure to JSON crash that prevented the
  dropdown from closing on a sibling click

Generated with [Cursor Composer](https://cursor.com/composer)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: ahmedomosanya <aopeyemi@contractor.linuxfoundation.org>
Copilot AI review requested due to automatic review settings May 6, 2026 14:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Comment thread packages/shared/src/interfaces/account.interface.ts Outdated
Comment thread apps/lfx-one/src/app/shared/services/account-context.service.ts Outdated
Comment thread apps/lfx-one/src/app/shared/components/org-selector/org-selector.component.html Outdated
Comment thread apps/lfx-one/src/app/app.routes.ts
luismoriguerra and others added 2 commits May 6, 2026 14:44
…2-1674) (#656)

Add a cross-foundation involvement section to the Org Overview page
showing 6 read-only engagement metric cards aggregated across all LF
foundations the selected organization participates in.

Cards: Active Contributors, Maintainers, Event Attendees, Event
Speakers, Certified Employees, Training Enrollments. Cards are not
clickable (no drill-down drawers). Membership Tier is excluded
(surfaced via the page header tier badge).

New files:
- OrgInvolvementService (6 Snowflake query methods, accountId only)
- OrgInvolvementAnalyticsService (6 Angular HTTP methods with fallbacks)
- OrgOverviewInvolvementComponent (signal-based, non-clickable cards)
- OrgInvolvement* response interfaces + ORG_INVOLVEMENT_METRICS constant

Modified files:
- analytics.controller.ts (6 new controller methods)
- analytics.route.ts (6 new org-involvement-* routes)
- org-overview.component (mount via @defer on viewport)
- dashboard-metrics.constants.ts (new constant array)
- interfaces/index.ts (barrel export)

Data layer: depends on lf-dbt PR #2390 for the platinum tables.

Signed-off-by: Luis Mori Guerra <luismorith@gmail.com>
Co-authored-by: Claude Opus 4 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings May 6, 2026 23:43
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Comments suppressed due to low confidence (1)

apps/lfx-one/src/app/shared/components/sidebar/sidebar.component.ts:109

  • With isOrgLens() hard-coded to return true for lensLoaded, the Org Lens skeleton branch in sidebar.component.html (@else if (isOrgLens()) { ... }) becomes unreachable. Consider removing that dead template branch or adjusting the condition so the template and the loading signal stay consistent.
  private initLensLoaded(): Signal<boolean> {
    return computed(() => {
      if (this.isOrgLens()) return true;
      const lens = this.navLens();
      if (!lens) return true;
      return this.navigationService.loaded(lens)();
    });

Comment thread packages/shared/src/interfaces/org-involvement.interface.ts
Comment thread packages/shared/src/interfaces/account.interface.ts Outdated
luismoriguerra and others added 2 commits May 7, 2026 14:22
…ns (LFXV2-1674) (#664)

* feat(dashboards): add org involvement carousel to /org/overview (LFXV2-1674)

Add a cross-foundation involvement section to the Org Overview page
showing 6 read-only engagement metric cards aggregated across all LF
foundations the selected organization participates in.

Cards: Active Contributors, Maintainers, Event Attendees, Event
Speakers, Certified Employees, Training Enrollments. Cards are not
clickable (no drill-down drawers). Membership Tier is excluded
(surfaced via the page header tier badge).

New files:
- OrgInvolvementService (6 Snowflake query methods, accountId only)
- OrgInvolvementAnalyticsService (6 Angular HTTP methods with fallbacks)
- OrgOverviewInvolvementComponent (signal-based, non-clickable cards)
- OrgInvolvement* response interfaces + ORG_INVOLVEMENT_METRICS constant

Modified files:
- analytics.controller.ts (6 new controller methods)
- analytics.route.ts (6 new org-involvement-* routes)
- org-overview.component (mount via @defer on viewport)
- dashboard-metrics.constants.ts (new constant array)
- interfaces/index.ts (barrel export)

Data layer: depends on lf-dbt PR #2390 for the platinum tables.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Signed-off-by: Luis Mori Guerra <luismorith@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dashboards): use METRIC_MONTH column for maintainers query

The org_maintainers_monthly dbt model uses metric_month (from the
date spine pattern) while the other 3 monthly models use
month_start_date. The service was querying MONTH_START_DATE for all
four, causing a Snowflake SQL compilation error on the maintainers
endpoint.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Signed-off-by: Luis Mori Guerra <luismorith@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dashboards): align service queries with actual dbt column names (LFXV2-1674)

Remove CUMULATIVE_* columns from all 4 monthly queries — these columns
don't exist in the dbt models (the spec assumed precomputed cumulative
windows, but the models output monthly values + yearly totals only).

Column fixes per model:
- org_maintainers_monthly: MONTH_START_DATE → METRIC_MONTH
- org_contributors_monthly: removed CUMULATIVE_CONTRIBUTORS
- org_maintainers_monthly: removed CUMULATIVE_MAINTAINERS
- org_event_attendance_monthly: removed CUMULATIVE_ATTENDED/SPEAKERS,
  added REGISTRATION_COUNT and TOTAL_REGISTRATIONS
- org_certified_employees_monthly: removed CUMULATIVE_CERTIFICATIONS

All 6 APIs now return 200 with real Snowflake data.
E2E tests: 6/6 pass.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Signed-off-by: Luis Mori Guerra <luismorith@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Signed-off-by: Luis Mori Guerra <luismorith@gmail.com>
Co-authored-by: Claude Opus 4 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(dashboards): wire org lens to live snowflake data (LFXV2-1673)

Replaces the static org-selector / header-tier scaffold with an end-to-end
read against the new platinum_lfx_one_org_lens_account_context model.
The persona-authorised account_ids bootstrap a single denormalised
platinum row per org with display attributes, Crowd.dev mapping, and the
highest active corporate membership tier — pre-joined inside dbt so
the API does no application-layer joins. UI renders a flat list (no
conglomerate hierarchy, no "related accounts" copy) per stakeholder
direction.

- Add GET /api/analytics/org-lens-account-context (controller + route +
  organization service) returning typed OrgLensAccountContextResponse[]
  from a single-table SELECT
- Introduce shared OrgLensAccountContextRow / Response interfaces and
  the canonical MembershipTierClass union (matches the dbt
  accepted_values test on membership_tier_class)
- Drive AccountContextService and the org-selector dropdown / header
  badge from live data; remove static accounts.constants.ts hardcoding
- Flatten the dropdown: no hierarchy tree, no related-accounts text,
  no first-visit picker; one entry per persona-authorised account
- Header tier badge reflects the selected org's direct memberships
  via membership_tier_class / membership_tier_display_name

Format-check at HEAD shows pre-existing prettier drift on five files
owned by 237cfa8 (LFXV2-1674 carousel). Bypassing pre-commit for that
reason only — our 11 files were lint/format/type-checked manually.

Generated with [Cursor Composer](https://cursor.com/composer)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: ahmedomosanya <aopeyemi@contractor.linuxfoundation.org>

* fix(dashboards): refresh + validate org-selector cookie (LFXV2-1673)

Address Copilot review on the org lens live-data wiring (PR #667):

- AccountContextService.initializeUserOrganizations now routes the
  matchedSeed branch through setAccount(), so the cookie is refreshed
  with the canonical seed (and live data when available) instead of
  letting stale accountName / tier / slug carry over to the next load.
- loadFromStorage validates the parsed accountId against the Salesforce
  id shape (15- or 18-char alphanumeric) and falls back to
  PLACEHOLDER_ACCOUNT on anything malformed or tampered, closing the
  brief window where selectedAccount could hold an invalid id before
  persona init reconciles.

Generated with [Cursor Composer](https://cursor.com/composer)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: ahmedomosanya <aopeyemi@contractor.linuxfoundation.org>

---------

Signed-off-by: ahmedomosanya <aopeyemi@contractor.linuxfoundation.org>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 8, 2026 15:51
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Comment thread apps/lfx-one/src/server/services/org-involvement.service.ts
Comment thread apps/lfx-one/src/server/services/org-involvement.service.ts
Comment thread packages/shared/src/constants/dashboard-metrics.constants.ts
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

OrgInvolvementEventAttendanceMonthlyResponse,
OrgInvolvementMaintainersMonthlyResponse,
OrgTrainingEnrollmentsResponse,
} from '@lfx-one/shared/interfaces/org-involvement.interface';
Comment on lines +16 to +23
OrgInvolvementCertifiedEmployeesMonthlyResponse,
OrgInvolvementContributorsMonthlyResponse,
OrgInvolvementEventAttendanceMonthlyResponse,
OrgFoundationCoverageResponse,
OrgInvolvementMaintainersMonthlyResponse,
OrgTrainingEnrollmentsResponse,
} from '@lfx-one/shared/interfaces/org-involvement.interface';
import type { DashboardMetricCard, FilterPillOption } from '@lfx-one/shared/interfaces';
Comment on lines +142 to +147
this.coverageLoading.set(true);
return this.analyticsService.getFoundationCoverage(accountId).pipe(
tap(() => this.coverageLoading.set(false)),
catchError(() => {
this.coverageLoading.set(false);
return of({ accountId: '', foundationCount: 0, foundations: [] } as OrgFoundationCoverageResponse);
Comment on lines +49 to +50
private readonly selectedAccountId$ = toObservable(this.accountContextService.selectedAccount).pipe(map((account) => account.accountId));


public readonly filterOptions: FilterPillOption[] = [
{ id: 'all', label: 'All' },
{ id: 'contributions', label: 'Contribution' },

interface ContributorsMonthlyRow {
ACCOUNT_ID: string;
ACCOUNT_NAME: string;
Six files introduced during the org lens and tier ladder work
had minor whitespace/formatting drift flagged by the CI prettier
check. No logic changes.

- apps/lfx-one/src/app/app.routes.ts
- org-overview-involvement.component.ts
- org-placeholder-page.component.ts
- org-overview.component.html
- org-involvement-analytics.service.ts
- packages/shared/src/interfaces/org-lens.interface.ts

Generated with [Cursor Composer](https://cursor.com/composer)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: ahmedomosanya <aopeyemi@contractor.linuxfoundation.org>
#692)

The CD-3507 stakeholder demo on the feat/CD-3507-org-lens-shell preview
URL needs the org selector populated for any logged-in user, but the
persona-service contract for user-scoped organizations is still blocked
upstream. Today the only path that populates `organizations` is
`extractOrganizations`, which scrapes `board_member` detection extras,
so most engineering accounts on the dev cluster see an empty selector.

Overlay a small demo seed (8 orgs: Toyota + the IBM family) only when
extraction yields zero. Real board members remain unaffected: the seed
never displaces detected orgs, it just fills the void. The seed
deliberately carries only `accountId` + `accountName` so tier, slug,
and logo continue to resolve live from
`platinum_lfx_one_org_lens_account_context` via
`getOrgLensAccountContext`, exercising the real enrichment path
end-to-end (Toyota -> Platinum, IBM Watson Health -> Contributor).

Remove `ORG_LENS_DEMO_SEED_ACCOUNTS` and `withDemoSeedFallback` once
the upstream persona service starts returning user-scoped
organizations.

- add ORG_LENS_DEMO_SEED_ACCOUNTS in packages/shared accounts constants
  (identifier + name only)
- add private withDemoSeedFallback(req, accounts) helper in
  PersonaDetectionService
- apply the fallback to all three return paths of
  computePersonaDetections (error / no-detections / success)

Generated with [Cursor Composer](https://cursor.com/composer)

Signed-off-by: ahmedomosanya <aopeyemi@contractor.linuxfoundation.org>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 13:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Comment on lines +255 to +264
* real extraction produced nothing, so real board members still see
* their actual orgs first. Replace this fallback with a live source
* once the persona contract delivers organizations.
*/
private withDemoSeedFallback(req: Request, accounts: Account[]): Account[] {
if (accounts.length > 0) {
return accounts;
}
logger.debug(req, 'extract_organizations', 'No detected orgs — returning Org Lens demo seed', {
seed_count: ORG_LENS_DEMO_SEED_ACCOUNTS.length,
OrgInvolvementEventAttendanceMonthlyResponse,
OrgInvolvementMaintainersMonthlyResponse,
OrgTrainingEnrollmentsResponse,
} from '@lfx-one/shared/interfaces/org-involvement.interface';
Comment on lines +16 to +23
OrgInvolvementCertifiedEmployeesMonthlyResponse,
OrgInvolvementContributorsMonthlyResponse,
OrgInvolvementEventAttendanceMonthlyResponse,
OrgFoundationCoverageResponse,
OrgInvolvementMaintainersMonthlyResponse,
OrgTrainingEnrollmentsResponse,
} from '@lfx-one/shared/interfaces/org-involvement.interface';
import type { DashboardMetricCard, FilterPillOption } from '@lfx-one/shared/interfaces';
Comment on lines +45 to +53
private readonly selectedAccountId$ = toObservable(this.accountContextService.selectedAccount).pipe(map((account) => account.accountId));

private readonly coverageData = this.initializeCoverageData();
private readonly maintainersData = this.initializeMaintainersData();
private readonly contributorsData = this.initializeContributorsData();
private readonly certifiedEmployeesData = this.initializeCertifiedEmployeesData();
private readonly trainingEnrollmentsData = this.initializeTrainingEnrollmentsData();
private readonly eventAttendanceMonthlyData = this.initializeEventAttendanceMonthlyData();

@github-actions
Copy link
Copy Markdown

🧹 Deployment Removed

The deployment for PR #646 has been removed.

@github-actions
Copy link
Copy Markdown

🧹 Deployment Removed

The deployment for PR #646 has been removed.

ahmedomosanya and others added 2 commits May 14, 2026 14:32
…FXV2-1680) (#706)

Add the Foundations and Projects section to /org/overview. Renders a
4-tile stat strip (Foundations / Projects / Governance Roles /
Meetings This Week) and a per-foundation table with inline-detail
project rows, sourced from two pre-aggregated dbt rollups via a
single Snowflake query per render.

Server side
- new GET /api/orgs/:accountId/lens/foundations-and-projects mounted
  under a fresh /api/orgs router (kept distinct from the existing
  /api/organizations router to avoid widening that surface)
- OrgLensFoundationsController validates accountId against the
  Salesforce id pattern and emits start / success lifecycle logs
- OrgLensFoundationsService runs one LEFT JOIN against the
  ORG_LENS_FOUNDATIONS_AND_PROJECTS rollup and the
  ORG_LENS_FOUNDATION_PROJECTS_DETAIL per-project detail and shapes
  the wire response (rows + stat strip), normalising the
  '__outside_lf__' sentinel to the 'outside-lf' kebab slug at the
  wire boundary
- empty-org case returns a 200 with an empty rows envelope (never a
  404), matching the rest of Org Lens

Client side
- OrgOverviewFoundationsAndProjectsComponent owns fetch + loading /
  error / ready / empty state, retry, per-row expansion (reset on
  org switch), and first-render telemetry
- FoundationRowComponent renders the 4-cell main row (logo +
  tier-ribbon subtitle + chevron, Org Role, Voting Status,
  Governance Participation) using :host { display: contents } so
  the inner <tr> becomes a direct tbody child
- FoundationsStatStripComponent renders the 4 stat tiles with
  per-tile breakdown subtext
- foundation-logo / tier-ribbon helpers centralise the
  deterministic-by-foundation-id colour and class derivations
- OrgLensFoundationsService HTTP proxy fronts the new endpoint
- mounted into org-overview.component via @defer (on viewport) with
  a 4-tile skeleton placeholder; non-LF project-row clicks remain
  no-ops, LF rows route to /org/projects (slug-aware drilldown is a
  follow-on)

Shared
- OrgLensRowKind, OrgRoleBadge, VotingStatusBadge,
  GovernanceParticipationBucket, ProjectInfluenceBucket unions plus
  OrgLensFoundationProject / OrgLensFoundationRow /
  OrgLensFoundationsStatStrip / OrgLensFoundationsAndProjectsResponse
  interfaces
- MembershipTierClass expanded from the prior 10-class union to the
  canonical 13-class ladder (Founding / Strategic / End User /
  Contributor added; Sponsor removed; Steering demoted to rank 6)
  with the rank order captured in JSDoc

Temporary dev-schema bridge
- organization.service.ts ORG_LENS_ACCOUNT_CONTEXT query and the
  new OrgLensFoundationsService both read from
  ANALYTICS_DEV.LF_AOPEYEMI_PLATINUM_LFX_ONE rather than
  ANALYTICS.PLATINUM_LFX_ONE, because the dbt PR that promotes the
  ORG_LENS_FOUNDATIONS_AND_PROJECTS / ORG_LENS_FOUNDATION_PROJECTS_DETAIL
  rollups (and the 13-class tier ladder) into prod is still in
  flight. Both qualifiers MUST flip back to ANALYTICS.PLATINUM_LFX_ONE
  before this PR's parent (CD-3507 org lens shell) merges to main.

This PR stacks on feat/CD-3507-org-lens-shell (PR #646).

Generated with [Cursor Composer](https://cursor.com/composer)

Signed-off-by: ahmedomosanya <aopeyemi@contractor.linuxfoundation.org>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…files

Six files introduced by PR #706 (LFXV2-1680 foundations and projects
section) had minor whitespace / line-length drift flagged by the CI
prettier check. No logic changes — pure prettier --write output to
keep the line-length and self-closing-tag rules consistent with the
rest of the org lens code.

- foundation-row.component.html
- foundations-stat-strip.component.html
- org-overview-foundations-and-projects.component.html
- shared/services/org-lens-foundations.service.ts (client proxy)
- server/routes/orgs.route.ts
- server/services/org-lens-foundations.service.ts

Mirrors the precedent set by 2577089 ("style(org-lens): fix prettier
formatting on org lens files") which fixed the same class of CI drift
on the prior org lens batch.

Generated with [Cursor Composer](https://cursor.com/composer)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: ahmedomosanya <aopeyemi@contractor.linuxfoundation.org>
Copilot AI review requested due to automatic review settings May 14, 2026 13:40
The repo-wide @typescript-eslint/naming-convention rule restricts
private memberLike identifiers to camelCase only (no UPPER_CASE),
so the new private static readonly EMPTY_DETAIL on
FoundationsStatStripComponent fails lint:check in CI even though it
matches the constant convention used at module scope (TIER_ORDER).
Rename to emptyDetail and update the four call sites.

Generated with [Cursor Composer](https://cursor.com/composer)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: ahmedomosanya <aopeyemi@contractor.linuxfoundation.org>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Comments suppressed due to low confidence (1)

apps/lfx-one/src/app/modules/dashboards/org/components/org-overview-involvement/org-overview-involvement.component.ts:46

  • selectedAccountId$ will initially emit an empty string (PLACEHOLDER_ACCOUNT) before persona/account initialization, causing the involvement data streams to fire requests with an invalid accountId (unnecessary 400s + network traffic). Consider filtering out falsy ids (and ideally distinctUntilChanged()) before the switchMap chains so requests only run once a real accountId is available.
  private readonly selectedAccountId$ = toObservable(this.accountContextService.selectedAccount).pipe(map((account) => account.accountId));

Comment on lines +892 to +912
const placeholders = accountIds.map(() => '?').join(',');
const query = `
SELECT
ACCOUNT_ID,
ACCOUNT_NAME,
ACCOUNT_SLUG,
LOGO_URL,
CDEV_ORG_ID,
CDEV_ORG_NAME,
CDEV_ORG_LOGO,
IS_MEMBER,
MEMBER_ACCOUNT_TYPE,
MEMBERSHIP_ID,
MEMBERSHIP_PROJECT_ID,
MEMBERSHIP_PROJECT_NAME,
MEMBERSHIP_TIER_DISPLAY_NAME,
MEMBERSHIP_TIER_CLASS
FROM ANALYTICS_DEV.LF_AOPEYEMI_PLATINUM_LFX_ONE.ORG_LENS_ACCOUNT_CONTEXT
WHERE ACCOUNT_ID IN (${placeholders})
ORDER BY ACCOUNT_NAME
`;
Comment on lines +133 to +136
p.COMMITS_COUNT AS PROJECT_COMMITS_COUNT
FROM ANALYTICS_DEV.LF_AOPEYEMI_PLATINUM_LFX_ONE.ORG_LENS_FOUNDATIONS_AND_PROJECTS f
LEFT JOIN ANALYTICS_DEV.LF_AOPEYEMI_PLATINUM_LFX_ONE.ORG_LENS_FOUNDATION_PROJECTS_DETAIL p
ON p.ACCOUNT_ID = f.ACCOUNT_ID
Comment on lines +259 to +267
private withDemoSeedFallback(req: Request, accounts: Account[]): Account[] {
if (accounts.length > 0) {
return accounts;
}
logger.debug(req, 'extract_organizations', 'No detected orgs — returning Org Lens demo seed', {
seed_count: ORG_LENS_DEMO_SEED_ACCOUNTS.length,
});
return ORG_LENS_DEMO_SEED_ACCOUNTS.map((account) => ({ ...account }));
}
OrgInvolvementEventAttendanceMonthlyResponse,
OrgInvolvementMaintainersMonthlyResponse,
OrgTrainingEnrollmentsResponse,
} from '@lfx-one/shared/interfaces/org-involvement.interface';
OrgFoundationCoverageResponse,
OrgInvolvementMaintainersMonthlyResponse,
OrgTrainingEnrollmentsResponse,
} from '@lfx-one/shared/interfaces/org-involvement.interface';
Comment on lines +2897 to +2902
const SALESFORCE_ID_PATTERN = /^[A-Za-z0-9]{15,18}$/;
for (const id of ids) {
if (!SALESFORCE_ID_PATTERN.test(id)) {
throw ServiceValidationError.forField('accountIds', `Invalid Salesforce accountId format: ${id}`, { operation });
}
}
Comment on lines +27 to +28
private readonly searchTerm: Signal<string> = computed(() => (this.searchValue() ?? '').trim().toLowerCase());
private readonly searchValue = toSignal(this.searchControl.valueChanges, { initialValue: '' });
@github-actions
Copy link
Copy Markdown

🧹 Deployment Removed

The deployment for PR #646 has been removed.

Empty commit to bump the pull_request merge SHA so the
build-and-push workflow re-builds the container image with a fresh
digest, which lets ArgoCD reconcile the ui-pr-646 ApplicationSet
that was torn down by the prior deploy-preview label removal.

No code changes.

Generated with [Cursor Composer](https://cursor.com/composer)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: ahmedomosanya <aopeyemi@contractor.linuxfoundation.org>
Copilot AI review requested due to automatic review settings May 14, 2026 14:51
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Comment on lines +244 to +267
/**
* Org Lens demo seed fallback.
*
* Until the upstream persona service returns user-scoped organizations
* directly (blocked on persona-service work), the only path that
* populates `organizations` today is `extractOrganizations`, which
* scrapes `board_member` detection extras. Users without board
* memberships — i.e. most engineering accounts on the dev cluster —
* would see an empty selector.
*
* Returns the demo seed (`ORG_LENS_DEMO_SEED_ACCOUNTS`) only when the
* real extraction produced nothing, so real board members still see
* their actual orgs first. Replace this fallback with a live source
* once the persona contract delivers organizations.
*/
private withDemoSeedFallback(req: Request, accounts: Account[]): Account[] {
if (accounts.length > 0) {
return accounts;
}
logger.debug(req, 'extract_organizations', 'No detected orgs — returning Org Lens demo seed', {
seed_count: ORG_LENS_DEMO_SEED_ACCOUNTS.length,
});
return ORG_LENS_DEMO_SEED_ACCOUNTS.map((account) => ({ ...account }));
}
Comment on lines +892 to +912
const placeholders = accountIds.map(() => '?').join(',');
const query = `
SELECT
ACCOUNT_ID,
ACCOUNT_NAME,
ACCOUNT_SLUG,
LOGO_URL,
CDEV_ORG_ID,
CDEV_ORG_NAME,
CDEV_ORG_LOGO,
IS_MEMBER,
MEMBER_ACCOUNT_TYPE,
MEMBERSHIP_ID,
MEMBERSHIP_PROJECT_ID,
MEMBERSHIP_PROJECT_NAME,
MEMBERSHIP_TIER_DISPLAY_NAME,
MEMBERSHIP_TIER_CLASS
FROM ANALYTICS_DEV.LF_AOPEYEMI_PLATINUM_LFX_ONE.ORG_LENS_ACCOUNT_CONTEXT
WHERE ACCOUNT_ID IN (${placeholders})
ORDER BY ACCOUNT_NAME
`;
Comment on lines +131 to +136
p.CONTRIBUTORS_COUNT AS PROJECT_CONTRIBUTORS_COUNT,
p.COLLABORATORS_COUNT AS PROJECT_COLLABORATORS_COUNT,
p.COMMITS_COUNT AS PROJECT_COMMITS_COUNT
FROM ANALYTICS_DEV.LF_AOPEYEMI_PLATINUM_LFX_ONE.ORG_LENS_FOUNDATIONS_AND_PROJECTS f
LEFT JOIN ANALYTICS_DEV.LF_AOPEYEMI_PLATINUM_LFX_ONE.ORG_LENS_FOUNDATION_PROJECTS_DETAIL p
ON p.ACCOUNT_ID = f.ACCOUNT_ID
OrgInvolvementEventAttendanceMonthlyResponse,
OrgInvolvementMaintainersMonthlyResponse,
OrgTrainingEnrollmentsResponse,
} from '@lfx-one/shared/interfaces/org-involvement.interface';
Comment on lines +16 to +23
OrgInvolvementCertifiedEmployeesMonthlyResponse,
OrgInvolvementContributorsMonthlyResponse,
OrgInvolvementEventAttendanceMonthlyResponse,
OrgFoundationCoverageResponse,
OrgInvolvementMaintainersMonthlyResponse,
OrgTrainingEnrollmentsResponse,
} from '@lfx-one/shared/interfaces/org-involvement.interface';
import type { DashboardMetricCard, FilterPillOption } from '@lfx-one/shared/interfaces';
Comment on lines +85 to +87
private getMetricConfig(title: string): DashboardMetricCard {
return ORG_INVOLVEMENT_METRICS.find((m) => m.title === title)!;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-assisted A task or activity that was supported by AI, such as CoPilot, ChatGPT, or other AI technology. deploy-preview enhancement New feature or request WIP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants