Skip to content

Conversation

@asithade
Copy link
Contributor

Summary

Implement Board Member persona dashboard with three key components: Organization Involvement, Foundation Health, and Pending Actions. Integrates with Snowflake data warehouse for real-time organization metrics.

Components Implemented

1. Board Member Dashboard

  • Created new board-member-dashboard component with three-column layout
  • Integrated persona-specific content with dashboard routing
  • Added to persona switcher and navigation system

2. Organization Involvement Component

Snowflake Integration:

  • Organization maintainers count and project statistics
  • Membership tier details (tier level, dates, pricing)

Primary Metrics (4 compact cards):

  • Membership Tier (dynamic from Snowflake)
  • Event Sponsorship ($250K, 8 events)
  • Active Contributors (847)
  • Maintainers (dynamic from Snowflake)

Secondary Metrics:

  • Our Contributions (4 metrics)
  • Our Impact (4 metrics)

Features:

  • Single unified loading indicator
  • Sparkline charts with Chart.js
  • Null-safe data handling

3. Foundation Health Component

  • Health score tag with color-coded severity
  • Project health metrics table (15 projects)
  • Comprehensive health indicators (score, security, dependencies, quality, coverage)
  • Responsive grid layout with tooltips

4. Pending Actions Component

  • Persona-aware action items (board member specific)
  • Priority-based categorization (high/medium/low)
  • Action type icons and formatting

Backend Implementation

Analytics Controller

  • getOrganizationMaintainers(): Query maintainers count and projects
  • getMembershipTier(): Fetch membership tier details with pricing
  • Optimized SQL queries with lowercase column aliases
  • Proper error handling with ResourceNotFoundError

Routes

  • /api/analytics/organization-maintainers
  • /api/analytics/membership-tier

Shared Package Updates

Interfaces

  • OrganizationMaintainersResponse
  • MembershipTierResponse
  • OrganizationInvolvementMetricWithChart
  • FoundationHealthMetric

Constants

  • PRIMARY_INVOLVEMENT_METRICS (4 metrics)
  • CONTRIBUTIONS_METRICS (4 metrics)
  • IMPACT_METRICS (4 metrics)
  • FOUNDATION_HEALTH_METRICS (15 metrics)
  • Updated PERSONA_CONFIG with board member

Technical Highlights

  • Angular 19 signals with toSignal and computed signals
  • Single loading state using computed signal
  • Null-safe operators for optional data handling
  • Chart.js integration with sparkline configurations
  • Tailwind CSS responsive design
  • Type-safe interfaces across frontend/backend
  • Optimized Snowflake queries with parameterization

Files Changed

Backend:

  • analytics.controller.ts (2 new endpoints)
  • analytics.service.ts (2 new methods)
  • analytics.route.ts (2 new routes)

Frontend:

  • New: board-member-dashboard component
  • New: organization-involvement component
  • New: foundation-health component
  • New: health-score-tag component
  • Modified: dashboard routing and persona integration
  • Modified: pending-actions (persona-aware)

Shared:

  • analytics-data.interface.ts (2 new response interfaces)
  • dashboard.interface.ts (2 new metric interfaces)
  • persona.interface.ts (updated config)
  • New: organization-involvement.constants.ts
  • New: foundation-health.constants.ts

Testing

  • ✅ All components follow existing test patterns
  • ✅ Data-testid attributes for E2E testing
  • ✅ Responsive behavior validated
  • ✅ Lint passed
  • ✅ Build passed
  • ✅ Type checking passed

Related Issue

LFXV2-687

Generated with Claude Code

Copilot AI review requested due to automatic review settings October 27, 2025 20:04
@asithade asithade requested a review from jordane as a code owner October 27, 2025 20:04
@coderabbitai
Copy link

coderabbitai bot commented Oct 27, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a "board-member" persona and dashboard with new UI components (organization involvement, foundation health, health‑score tag), account context service, client/server organization analytics endpoints, shared constants/interfaces/utils (including color helpers and mock foundation data), Snowflake service and lock-manager updates, and a cSpell word addition.

Changes

Cohort / File(s) Summary
Board Member Dashboard
apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts, .../board-member-dashboard.component.html, .../board-member-dashboard.component.scss
New standalone Angular component for the board-member dashboard with account selector and composed child components.
Organization Involvement
apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/*
New standalone component that queries organization analytics, builds metric groups, prepares chart datasets, and renders responsive metric cards with loading state.
Foundation Health
apps/lfx-one/src/app/modules/dashboards/components/foundation-health/*
New component and template that transforms FOUNDATION_HEALTH_DATA into display rows with formatted values and chart data (sparklines, bars, pie paths) and optional view-all callback.
Health Score Tag
apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/*
New presentational component mapping health score to badge classes and label.
Dashboard integration
apps/lfx-one/src/app/modules/dashboards/dashboard.component.ts, .../dashboard.component.html
Imports and renders lfx-board-member-dashboard when dashboardType() is board-member.
Pending Actions
apps/lfx-one/src/app/modules/dashboards/components/pending-actions/pending-actions.component.ts
Added board-member persona case to return BOARD_MEMBER_ACTION_ITEMS.
Account context service
apps/lfx-one/src/app/shared/services/account-context.service.ts
New service exposing writable selectedAccount, availableAccounts, setAccount() and getAccountId() with localStorage persistence.
Analytics client methods
apps/lfx-one/src/app/shared/services/analytics.service.ts
Added methods: getOrganizationMaintainers, getOrganizationContributors, getMembershipTier, getOrganizationEventAttendance, getOrganizationTechnicalCommittee with HTTP GET and fallback defaults.
Analytics backend controller & routes
apps/lfx-one/src/server/controllers/analytics.controller.ts, apps/lfx-one/src/server/routes/analytics.route.ts
New controller methods and GET routes for organization maintainers, contributors, event attendance, technical committee, and membership tier; updated Snowflake query typing for project counts.
Shared constants (dashboard data & accounts)
packages/shared/src/constants/...
New exported constants: PRIMARY_INVOLVEMENT_METRICS, CONTRIBUTIONS_METRICS, IMPACT_METRICS, FOUNDATION_HEALTH_DATA, BOARD_MEMBER_ACTION_ITEMS, ACCOUNTS, DEFAULT_ACCOUNT; added re-exports in constants index.
Shared interfaces & persona types
packages/shared/src/interfaces/*
New interfaces/types for dashboard metrics and foundation models, analytics row/response types, Account interface; added 'board-member' to PersonaType and re-exported account interface.
Shared utils (color)
packages/shared/src/utils/color.utils.ts, packages/shared/src/utils/index.ts
Added isValidHexColor and hexToRgba utilities and re-export via utils index.
Snowflake service & lock manager
apps/lfx-one/src/server/services/snowflake.service.ts, apps/lfx-one/src/server/utils/lock-manager.ts
Strengthened Snowflake environment validation, pool options, MicroserviceError wrapping on errors; lock-manager now deletes in-memory locks immediately in finally block.
Config
.vscode/settings.json
Added "sparkline" to cSpell.words.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant UI as Board‑Member Dashboard (UI)
    participant BoardComp as BoardMemberDashboardComponent
    participant OrgComp as OrganizationInvolvementComponent
    participant AnalyticsSvc as AnalyticsService (client)
    participant API as AnalyticsController (server)
    participant DB as Snowflake

    UI->>BoardComp: mount
    BoardComp->>OrgComp: render(selected account)
    OrgComp->>AnalyticsSvc: request organization analytics
    AnalyticsSvc->>API: GET /api/analytics/organization-*
    API->>DB: execute queries
    DB-->>API: rows
    API-->>AnalyticsSvc: JSON responses
    AnalyticsSvc-->>OrgComp: observables (or defaults)
    OrgComp->>OrgComp: compute metrics & chart datasets
    OrgComp-->>BoardComp: present metrics & charts
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing focused review:
    • FoundationHealthComponent: chart math (pie path generation), formatting, and class/color mapping.
    • AnalyticsController & routes: Snowflake queries, row↔response typing, error handling.
    • OrganizationInvolvementComponent: signal/observable composition and chart dataset construction.
    • Shared interfaces/constants: ensure server responses, client fallbacks, and mock data shapes align.
    • Snowflake service: env validation, pool option impacts, and MicroserviceError payloads.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Out of Scope Changes Check ❓ Inconclusive Most changes align with the stated objectives; however, two sets of modifications warrant clarification: (1) significant updates to apps/lfx-one/src/server/services/snowflake.service.ts including enhanced error handling, environment variable validation, and connection pool configuration improvements, and (2) a behavior change in apps/lfx-one/src/server/utils/lock-manager.ts modifying lock cleanup from buffered to immediate deletion. These infrastructure changes are not mentioned in the PR description's "Files Changed" section and do not appear as explicit requirements in the linked issue objectives, though they may provide supporting improvements for the new Snowflake integration. Clarification is needed on whether these changes are necessary prerequisites for the board member dashboard feature or should be separated into a distinct infrastructure improvement PR. The reviewer should confirm whether the snowflake.service.ts and lock-manager.ts changes are required dependencies for the board member dashboard feature or represent separate infrastructure improvements. If these changes are supporting enhancements not strictly necessary for the feature, consider moving them to a separate PR for better change isolation and clarity. If they are necessary prerequisites, the PR description should be updated to document why these infrastructure changes are required for this feature.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "feat(dashboards): add board member persona with snowflake integration" clearly and concisely describes the main change in the changeset. The title directly references the primary feature being implemented—a new board member persona dashboard with Snowflake integration—which aligns with the core objective of this PR. The title is specific enough that a teammate scanning commit history would immediately understand the primary contribution without needing additional context.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/LFXV2-687

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 27924da and ce2b577.

📒 Files selected for processing (1)
  • apps/lfx-one/src/server/services/snowflake.service.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces

Files:

  • apps/lfx-one/src/server/services/snowflake.service.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • apps/lfx-one/src/server/services/snowflake.service.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • apps/lfx-one/src/server/services/snowflake.service.ts
🧬 Code graph analysis (1)
apps/lfx-one/src/server/services/snowflake.service.ts (2)
apps/lfx-one/src/server/errors/index.ts (1)
  • MicroserviceError (6-6)
packages/shared/src/constants/snowflake.constant.ts (1)
  • SNOWFLAKE_CONFIG (7-57)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-push
🔇 Additional comments (6)
apps/lfx-one/src/server/services/snowflake.service.ts (6)

9-9: LGTM: Clean import addition.

The MicroserviceError import is properly scoped and necessary for the enhanced error handling implemented throughout this file.


252-283: Excellent defensive programming for configuration validation.

The upfront validation of all required environment variables (lines 252-283) is a solid improvement that ensures the service fails fast with clear diagnostics when misconfigured. The structured error logging includes both missing_variables and all_required fields, making it easy for operators to identify configuration gaps.


285-302: Consistent use of validated environment variables.

Lines 285-302 correctly use the requiredEnvVars object throughout the connection configuration. The non-null assertions are safe because the validation at lines 262-283 guarantees all values are present at this point. This is clean and maintainable.


307-316: LGTM: Pool configuration options are well-chosen.

The extended pool configuration (lines 307-316) adds important reliability features:

  • testOnBorrow: true catches terminated connections before use
  • Eviction settings (evictionRunIntervalMillis, idleTimeoutMillis) prevent connection staleness
  • maxWaitingClients prevents unbounded request queuing
  • acquireTimeoutMillis prevents indefinite hangs

All values are reasonable for production, and the inline comments clearly document each option.


326-332: Past review comment resolved: Logging now uses validated environment variables.

Lines 329-331 correctly reference requiredEnvVars instead of direct process.env access, ensuring logged values match the configuration actually used by the connection pool. This addresses the inconsistency flagged in the previous review.

Based on past review comments.


117-140: Incorrect review comment – references unverifiable past suggestion that contradicts recent intentional fix.

The current code at line 139 using error instanceof Error ? error : undefined was intentionally introduced in commit ce2b577 (Oct 30, 2025) specifically to "preserve stack traces and use validated env vars." The review comment references a "past review comment" suggesting new Error(String(error)), but no such past review is provided in context to verify this claim.

The current pattern is consistent throughout the file and was an intentional recent fix, not a deviation. Wrapping non-Error objects with new Error() would create a stack trace from the wrapping point rather than preserving original error context. Reverting this would undo the recent commit's purpose.

Likely an incorrect or invalid review comment.


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

Copy link
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

This PR implements a comprehensive Board Member persona dashboard with three main components: Organization Involvement, Foundation Health, and Pending Actions. The implementation integrates with Snowflake for real-time data retrieval and provides board members with visibility into their organization's engagement and foundation ecosystem health.

Key Changes:

  • Added Board Member persona with Snowflake-backed Organization Involvement metrics
  • Implemented Foundation Health monitoring across multiple foundations
  • Extended analytics service with organization maintainers and membership tier endpoints

Reviewed Changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/shared/src/interfaces/persona.interface.ts Added 'board-member' to PersonaType union
packages/shared/src/interfaces/dashboard.interface.ts Added comprehensive interfaces for organization involvement and foundation health metrics
packages/shared/src/interfaces/analytics-data.interface.ts Added OrganizationMaintainersResponse and MembershipTierResponse interfaces
packages/shared/src/constants/persona.constants.ts Added board member persona configuration
packages/shared/src/constants/organization-involvement.constants.ts New file with primary involvement, contribution, and impact metric constants
packages/shared/src/constants/foundation-health.constants.ts New file with foundation health data and mock metrics
packages/shared/src/constants/action-items.constants.ts Added board member-specific action items
apps/lfx-one/src/server/routes/analytics.route.ts Added routes for organization maintainers and membership tier
apps/lfx-one/src/server/controllers/analytics.controller.ts Implemented Snowflake query methods for organization metrics
apps/lfx-one/src/app/shared/services/analytics.service.ts Added frontend service methods for new analytics endpoints
apps/lfx-one/src/app/modules/dashboards/dashboard.component.ts Integrated BoardMemberDashboardComponent
apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/* New component with Snowflake integration and Chart.js sparklines
apps/lfx-one/src/app/modules/dashboards/components/foundation-health/* New component displaying foundation health metrics table
apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/* New reusable component for health score badges
apps/lfx-one/src/app/modules/dashboards/board-member/* New board member dashboard component with three-column layout

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (1)

155-164: Consider adding input validation.

The hexToRgba method assumes valid hex format. While colors currently come from constants, adding defensive validation would improve robustness.

Apply this diff to add validation:

 private hexToRgba(hex: string, alpha: number): string {
+  if (!hex || !hex.match(/^#[0-9A-Fa-f]{6}$/)) {
+    console.warn(`Invalid hex color: ${hex}`);
+    return `rgba(0, 0, 0, ${alpha})`;
+  }
   const r = parseInt(hex.slice(1, 3), 16);
   const g = parseInt(hex.slice(3, 5), 16);
   const b = parseInt(hex.slice(5, 7), 16);
   return `rgba(${r}, ${g}, ${b}, ${alpha})`;
 }
apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (1)

12-49: Consider extracting chart data structures to reusable types.

The inline chart data structure definitions (lines 18-41) are verbose and duplicated. If Chart.js types are available in your project, consider referencing them directly. Alternatively, extract a shared SparklineChartData interface to improve maintainability.

Example refactor:

interface SparklineChartData {
  labels: string[];
  datasets: {
    data: number[];
    borderColor: string;
    backgroundColor: string;
    fill: boolean;
    tension: number;
    borderWidth: number;
    pointRadius: number;
  }[];
}

interface FoundationDisplay extends Foundation {
  softwareValueFormatted: string;
  totalMembersFormatted: string;
  activeContributorsAvg: string;
  maintainersAvg: string;
  eventsTotal: number;
  activeContributorsChartData: SparklineChartData;
  maintainersChartData: SparklineChartData;
  // ... rest of fields
}
packages/shared/src/interfaces/dashboard.interface.ts (2)

59-88: Consider using discriminated unions for better type safety.

The PrimaryInvolvementMetric interface uses many optional fields to handle both regular metrics and membership tier metrics. A discriminated union would provide better type safety and clearer intent.

Example refactor:

interface BasePrimaryInvolvementMetric {
  title: string;
  value: string;
  subtitle: string;
}

interface RegularMetric extends BasePrimaryInvolvementMetric {
  type: 'regular';
  icon: string;
  sparklineData?: number[];
  sparklineColor?: string;
  chartType?: 'bar' | 'line';
}

interface MembershipTierMetric extends BasePrimaryInvolvementMetric {
  type: 'membershipTier';
  tier: string;
  tierSince: string;
  annualFee: string;
  nextDue: string;
}

type PrimaryInvolvementMetric = RegularMetric | MembershipTierMetric;

116-161: Consider extracting the chart data structure to a reusable type.

The inline chartData structure (lines 130-150) is verbose and could be reused across multiple interfaces. Consider extracting it to a shared type.

Example:

export interface SparklineChartDataset {
  data: number[];
  borderColor: string;
  backgroundColor: string;
  fill: boolean;
  tension: number;
  borderWidth: number;
  pointRadius: number;
}

export interface SparklineChartData {
  labels: string[];
  datasets: SparklineChartDataset[];
}

export interface OrganizationInvolvementMetricWithChart {
  title: string;
  value: string;
  subtitle: string;
  icon: string;
  chartData?: SparklineChartData;
  // ... rest of fields
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 42e9854 and 529a49e.

📒 Files selected for processing (27)
  • .vscode/settings.json (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.scss (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.scss (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.scss (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.scss (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/pending-actions/pending-actions.component.ts (2 hunks)
  • apps/lfx-one/src/app/modules/dashboards/dashboard.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/dashboard.component.ts (2 hunks)
  • apps/lfx-one/src/app/shared/services/analytics.service.ts (2 hunks)
  • apps/lfx-one/src/server/controllers/analytics.controller.ts (2 hunks)
  • apps/lfx-one/src/server/routes/analytics.route.ts (1 hunks)
  • packages/shared/src/constants/action-items.constants.ts (1 hunks)
  • packages/shared/src/constants/foundation-health.constants.ts (1 hunks)
  • packages/shared/src/constants/index.ts (1 hunks)
  • packages/shared/src/constants/organization-involvement.constants.ts (1 hunks)
  • packages/shared/src/constants/persona.constants.ts (1 hunks)
  • packages/shared/src/interfaces/analytics-data.interface.ts (1 hunks)
  • packages/shared/src/interfaces/dashboard.interface.ts (1 hunks)
  • packages/shared/src/interfaces/persona.interface.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces

Files:

  • apps/lfx-one/src/app/modules/dashboards/components/pending-actions/pending-actions.component.ts
  • packages/shared/src/interfaces/analytics-data.interface.ts
  • packages/shared/src/constants/action-items.constants.ts
  • packages/shared/src/constants/index.ts
  • packages/shared/src/interfaces/persona.interface.ts
  • apps/lfx-one/src/app/shared/services/analytics.service.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts
  • packages/shared/src/constants/persona.constants.ts
  • packages/shared/src/constants/foundation-health.constants.ts
  • packages/shared/src/interfaces/dashboard.interface.ts
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts
  • apps/lfx-one/src/app/modules/dashboards/dashboard.component.ts
  • packages/shared/src/constants/organization-involvement.constants.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts
  • apps/lfx-one/src/server/routes/analytics.route.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • apps/lfx-one/src/app/modules/dashboards/components/pending-actions/pending-actions.component.ts
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.scss
  • packages/shared/src/interfaces/analytics-data.interface.ts
  • apps/lfx-one/src/app/modules/dashboards/dashboard.component.html
  • packages/shared/src/constants/action-items.constants.ts
  • packages/shared/src/constants/index.ts
  • packages/shared/src/interfaces/persona.interface.ts
  • apps/lfx-one/src/app/shared/services/analytics.service.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.scss
  • packages/shared/src/constants/persona.constants.ts
  • packages/shared/src/constants/foundation-health.constants.ts
  • packages/shared/src/interfaces/dashboard.interface.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.scss
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.html
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.html
  • apps/lfx-one/src/app/modules/dashboards/dashboard.component.ts
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.html
  • packages/shared/src/constants/organization-involvement.constants.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.html
  • apps/lfx-one/src/server/routes/analytics.route.ts
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.scss
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • apps/lfx-one/src/app/modules/dashboards/components/pending-actions/pending-actions.component.ts
  • packages/shared/src/interfaces/analytics-data.interface.ts
  • packages/shared/src/constants/action-items.constants.ts
  • packages/shared/src/constants/index.ts
  • packages/shared/src/interfaces/persona.interface.ts
  • apps/lfx-one/src/app/shared/services/analytics.service.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts
  • packages/shared/src/constants/persona.constants.ts
  • packages/shared/src/constants/foundation-health.constants.ts
  • packages/shared/src/interfaces/dashboard.interface.ts
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts
  • apps/lfx-one/src/app/modules/dashboards/dashboard.component.ts
  • packages/shared/src/constants/organization-involvement.constants.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts
  • apps/lfx-one/src/server/routes/analytics.route.ts
packages/shared/src/interfaces/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all TypeScript interfaces in the shared package at packages/shared/src/interfaces

Files:

  • packages/shared/src/interfaces/analytics-data.interface.ts
  • packages/shared/src/interfaces/persona.interface.ts
  • packages/shared/src/interfaces/dashboard.interface.ts
apps/lfx-one/src/**/*.html

📄 CodeRabbit inference engine (CLAUDE.md)

apps/lfx-one/src/**/*.html: Always add data-testid attributes when creating new Angular components for reliable test targeting
Use data-testid naming convention [section]-[component]-[element]

Files:

  • apps/lfx-one/src/app/modules/dashboards/dashboard.component.html
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.html
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.html
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.html
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.html
packages/shared/src/constants/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all reusable constants in the shared package at packages/shared/src/constants

Files:

  • packages/shared/src/constants/action-items.constants.ts
  • packages/shared/src/constants/index.ts
  • packages/shared/src/constants/persona.constants.ts
  • packages/shared/src/constants/foundation-health.constants.ts
  • packages/shared/src/constants/organization-involvement.constants.ts
**/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Do not use barrel exports; always use direct imports for standalone components

Files:

  • packages/shared/src/constants/index.ts
🧬 Code graph analysis (10)
apps/lfx-one/src/app/modules/dashboards/components/pending-actions/pending-actions.component.ts (1)
packages/shared/src/constants/action-items.constants.ts (1)
  • BOARD_MEMBER_ACTION_ITEMS (69-86)
packages/shared/src/constants/action-items.constants.ts (1)
packages/shared/src/interfaces/components.interface.ts (1)
  • PendingActionItem (336-349)
apps/lfx-one/src/app/shared/services/analytics.service.ts (1)
packages/shared/src/interfaces/analytics-data.interface.ts (2)
  • OrganizationMaintainersResponse (184-199)
  • MembershipTierResponse (205-235)
apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (3)
apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts (1)
  • Component (10-16)
packages/shared/src/constants/organization-involvement.constants.ts (3)
  • CONTRIBUTIONS_METRICS (66-87)
  • IMPACT_METRICS (93-114)
  • PRIMARY_INVOLVEMENT_METRICS (20-60)
packages/shared/src/interfaces/dashboard.interface.ts (1)
  • OrganizationInvolvementMetricWithChart (120-161)
packages/shared/src/constants/foundation-health.constants.ts (1)
packages/shared/src/interfaces/dashboard.interface.ts (1)
  • Foundation (222-251)
apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (3)
packages/shared/src/interfaces/dashboard.interface.ts (2)
  • Foundation (222-251)
  • OrgDependencyRiskLevel (173-173)
apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts (1)
  • Component (8-42)
packages/shared/src/constants/foundation-health.constants.ts (1)
  • FOUNDATION_HEALTH_DATA (31-161)
apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts (2)
apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (1)
  • Component (51-231)
packages/shared/src/interfaces/dashboard.interface.ts (1)
  • FoundationHealthScore (167-167)
packages/shared/src/constants/organization-involvement.constants.ts (1)
packages/shared/src/interfaces/dashboard.interface.ts (3)
  • PrimaryInvolvementMetric (63-88)
  • ContributionMetric (94-101)
  • ImpactMetric (107-114)
apps/lfx-one/src/server/controllers/analytics.controller.ts (2)
packages/shared/src/interfaces/analytics-data.interface.ts (2)
  • OrganizationMaintainersResponse (184-199)
  • MembershipTierResponse (205-235)
apps/lfx-one/src/server/errors/index.ts (1)
  • ResourceNotFoundError (7-7)
apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts (4)
apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (1)
  • Component (51-231)
apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (1)
  • Component (12-164)
apps/lfx-one/src/app/modules/dashboards/components/pending-actions/pending-actions.component.ts (1)
  • Component (12-49)
apps/lfx-one/src/app/modules/dashboards/dashboard.component.ts (1)
  • Component (17-34)
🔇 Additional comments (41)
.vscode/settings.json (1)

28-28: Appropriate spell-check vocabulary update.

Adding "sparkline" to the cSpell.words vocabulary is a proper housekeeping change that aligns with the introduction of sparkline chart terminology throughout the new dashboard components in this PR. The word is correctly placed in alphabetical order.

apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.scss (1)

1-6: LGTM!

The license header is correct, and the inline-block display is appropriate for a tag component.

apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.html (1)

1-6: LGTM!

The template correctly implements data-testid attributes following the required naming convention and uses proper Angular bindings.

packages/shared/src/constants/action-items.constants.ts (1)

66-86: LGTM!

The new board member action items follow the established pattern and correctly implement the PendingActionItem interface with appropriate values for the board-member persona.

packages/shared/src/constants/foundation-health.constants.ts (2)

13-25: LGTM!

The helper function correctly generates smooth time-series data with appropriate clamping and rounding for realistic trend visualization.


31-161: LGTM!

The foundation health mock data is well-structured with appropriate time-series data points (365 daily, 12 monthly) and varied health scores for comprehensive UI testing.

apps/lfx-one/src/app/modules/dashboards/components/pending-actions/pending-actions.component.ts (2)

8-8: LGTM!

The import correctly adds the board member action items from the shared constants package.


34-35: LGTM!

The board-member case is correctly integrated into the existing persona-based action item selection pattern.

apps/lfx-one/src/app/modules/dashboards/dashboard.component.html (1)

11-13: LGTM!

The board-member dashboard case is correctly integrated into the existing persona-based routing pattern.

apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.scss (1)

1-2: LGTM!

The license header is correctly included per coding guidelines.

apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.scss (1)

1-2: LGTM!

The license header is correctly included per coding guidelines.

apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.scss (1)

1-6: LGTM!

The stylesheet includes the required license header and follows Angular best practices with a minimal host selector rule.

packages/shared/src/interfaces/persona.interface.ts (1)

8-8: LGTM!

The addition of 'board-member' to the PersonaType union is appropriate and aligns with the PR objectives. String literal unions are the idiomatic TypeScript pattern for enumeration types like this.

apps/lfx-one/src/app/modules/dashboards/dashboard.component.ts (1)

9-9: LGTM!

The import follows the coding guideline to use direct imports rather than barrel exports for standalone components. The change correctly integrates the new board member dashboard component.

Also applies to: 20-20

packages/shared/src/constants/index.ts (1)

20-21: LGTM!

The new constant exports follow the established pattern in this index file and are appropriate for a shared constants package.

packages/shared/src/constants/persona.constants.ts (1)

25-29: LGTM!

The new board member persona option is structured consistently with existing options and aligns with the expanded PersonaType union.

apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.html (1)

1-22: LGTM!

The template follows all coding guidelines:

  • Includes required license header
  • Uses data-testid attributes for reliable test targeting
  • Implements responsive layout with Tailwind CSS
  • Clean, maintainable structure
apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts (1)

1-16: LGTM! Clean container component implementation.

The component follows Angular best practices by delegating all logic to child components. The empty class body is appropriate for a pure container component.

packages/shared/src/interfaces/analytics-data.interface.ts (2)

180-199: LGTM! Well-documented interface.

The interface is properly structured with appropriate types and comprehensive JSDoc documentation.


201-235: LGTM! Well-documented interface.

The interface properly defines membership tier data with clear documentation, including date format specifications.

apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.html (3)

4-17: LGTM! Good loading state implementation.

The loading indicator provides clear feedback to users with both a spinner and descriptive message.


20-80: LGTM! Well-structured responsive grid.

The template properly handles different metric types (membership tier vs regular) with appropriate conditional rendering and null-safe chart display.


82-116: LGTM! Clean secondary metrics layout.

The contribution and impact metrics are properly structured with helpful tooltips and test attributes for reliable testing.

apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts (2)

1-34: LGTM! Type-safe score tag implementation.

The component properly uses input.required for type safety and provides a complete mapping of score levels to CSS classes.


36-42: LGTM! Simple and effective label formatting.

The capitalization logic correctly transforms score values for display.

apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (3)

1-37: LGTM! Modern Angular reactive patterns.

The component effectively uses Angular 19 signals and toSignal for reactive data management with a unified loading state.


39-60: LGTM! Appropriate sparkline configuration.

The chart options correctly configure minimalist sparklines by disabling unnecessary UI elements.


62-153: LGTM! Robust data merging with null-safety.

The computed signal properly handles data from multiple sources with appropriate null-checks and fallback to placeholder data when real data is unavailable.

apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.html (3)

4-73: LGTM! Well-structured table with good UX.

The table header properly implements sticky columns and helpful tooltips for metric explanations.


74-155: LGTM! Comprehensive foundation metrics display.

The template properly handles different data structures with conditional rendering and effectively uses child components for visualizations.


157-178: LGTM! Effective risk visualization.

The organization dependency visualization clearly communicates risk levels through color-coding and detailed metrics.

packages/shared/src/constants/organization-involvement.constants.ts (3)

6-14: LGTM! Effective trend data generator.

The helper function creates realistic-looking trend data for placeholder sparklines with both linear trend and random variation.


16-60: LGTM! Well-documented placeholder metrics.

The constants clearly indicate which values are placeholders to be replaced with real Snowflake data, and provide appropriate sparkline data for visualization.


62-114: LGTM! Clear metric definitions with helpful tooltips.

Both contribution and impact metrics are well-structured with descriptive tooltips that explain each metric's meaning.

apps/lfx-one/src/server/controllers/analytics.controller.ts (2)

344-393: LGTM with a note on consistency.

The method properly uses parameterized queries and parallel execution for efficiency. The TODO comment appropriately flags the hardcoded accountId for future resolution.

Note: Unlike other methods in this controller, this endpoint returns zeros when no data is found rather than throwing a ResourceNotFoundError. This may be intentional for the board member dashboard use case, but consider documenting this behavior.


395-469: LGTM! Secure and well-structured endpoint.

The method properly uses parameterized queries, handles missing data with appropriate 404 errors, and includes a reasonable transformation of tier names. The TODO comment appropriately flags hardcoded IDs for future resolution.

apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (4)

71-89: LGTM - Computed signal is well-structured.

The computed foundations signal appropriately filters and transforms the data with good separation of concerns through helper methods. The computation should perform well for the expected data volumes (15 foundations based on the constants file).


152-164: LGTM - Good defensive programming.

The edge case handling (lines 158-160) for when all values are equal prevents division by zero and ensures consistent rendering. The minimum height of 10% ensures bars remain visible.


214-220: LGTM - Pie chart angle calculation is correct.

The conversion topPercentage * 3.6 correctly maps percentage (0-100) to degrees (0-360), and the two slices properly divide the circle based on the organization dependency percentage.


107-230: LGTM - Helper methods are well-implemented.

All helper methods follow good practices:

  • Proper use of Record types for risk level mappings (lines 170-174, 182-186)
  • Correct mathematical transformations for charts and SVG paths
  • Appropriate number formatting and calculations
packages/shared/src/interfaces/dashboard.interface.ts (1)

90-114: LGTM - Well-designed and documented interfaces.

The interfaces are clearly structured with appropriate JSDoc documentation. The use of optional vs required fields is well-considered (e.g., projectCount and projectBreakdown being optional in Foundation to handle different foundation types).

Also applies to: 175-251

@github-actions
Copy link

github-actions bot commented Oct 28, 2025

🚀 Deployment Status

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

Deployment Details:

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

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (6)
packages/shared/src/utils/color.utils.ts (1)

28-55: Good extraction and strict validation.

Centralizing hexToRgba with format and alpha checks resolves prior duplication and avoids rgba(NaN,…) pitfalls. Nice.

apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (1)

9-9: Nice reuse of shared color util.

Importing hexToRgba resolves the earlier duplication concern.

apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (1)

271-279: Avoid throwing when sparklineColor is missing/invalid.

hexToRgba('') throws. Add a guard with a safe fallback.

-            backgroundColor: hexToRgba(metric.sparklineColor ?? '', 0.1),
+            backgroundColor: isValidHexColor(metric.sparklineColor ?? '')
+              ? hexToRgba(metric.sparklineColor as string, 0.1)
+              : 'rgba(0, 148, 255, 0.1)',
apps/lfx-one/src/server/routes/analytics.route.ts (1)

17-21: Route definitions look correct.

The new routes follow the existing pattern and are properly integrated. The authorization concern regarding hardcoded organization context in the controllers has already been flagged in the past review.

apps/lfx-one/src/app/shared/services/analytics.service.ts (1)

99-188: Silent error handling masks failures (already flagged).

The error handling pattern in these organization-scoped methods returns default empty values, which masks authentication, authorization, and network failures. This issue was comprehensively identified in the previous review.

apps/lfx-one/src/server/controllers/analytics.controller.ts (1)

352-612: Hardcoded organization identifiers (already flagged).

All five new controller methods use hardcoded ACCOUNT_ID and PROJECT_ID values instead of extracting them from the authenticated user context. This prevents proper authorization and multi-tenant isolation, as comprehensively identified in the previous review on the routes file.

🧹 Nitpick comments (9)
packages/shared/src/utils/color.utils.ts (1)

9-13: Hoist the regex to a module constant (optional), consider 4/8‑digit hex support.

Avoid re-allocating the regex per call and optionally accept #RGBA/#RRGGBBAA if you plan to support embedded alpha.

Apply:

+// Match 3- or 6-digit hex color with # prefix
+const HEX_COLOR_REGEX = /^#(?:[A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/;
+
 export function isValidHexColor(hex: string): boolean {
-  // Match 3-digit or 6-digit hex color with # prefix
-  const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
-  return hexRegex.test(hex);
+  return HEX_COLOR_REGEX.test(hex);
 }
packages/shared/src/utils/index.ts (1)

4-4: Confirm barrel export policy for index.ts in utils.

Guideline states “Do not use barrel exports; always use direct imports for standalone components.” Since this is a utils index, confirm if barrels are allowed here. If not, remove this re‑export and import from '.../utils/color.utils' directly.

As per coding guidelines.

packages/shared/src/interfaces/dashboard.interface.ts (2)

173-174: Replace string unions with enums for maintainability.

Prefer enums (or interface-backed constants) over unions to align with the codebase standard and ease refactors.

Apply:

-export type FoundationHealthScore = 'excellent' | 'healthy' | 'stable' | 'unsteady' | 'critical';
+export enum FoundationHealthScore {
+  Excellent = 'excellent',
+  Healthy = 'healthy',
+  Stable = 'stable',
+  Unsteady = 'unsteady',
+  Critical = 'critical',
+}
 
-export type OrgDependencyRiskLevel = 'low' | 'moderate' | 'high';
+export enum OrgDependencyRiskLevel {
+  Low = 'low',
+  Moderate = 'moderate',
+  High = 'high',
+}

Note: Update usages (e.g., inputs and maps) accordingly.

As per coding guidelines.

Also applies to: 179-180


131-133: Make icon optional to match actual usage.

You often pass metric.icon ?? ''. Model this in the type to avoid empty strings.

-  /** Icon class for the metric */
-  icon: string;
+  /** Icon class for the metric (optional for membership tier) */
+  icon?: string;
apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (2)

153-165: Handle empty input in calculateBarHeights.

Math.max(...[]) → -Infinity and Math.min(...[]) → Infinity; downstream math yields NaN.

-  private calculateBarHeights(data: number[]): number[] {
+  private calculateBarHeights(data: number[]): number[] {
+    if (!data.length) return [];
     const maxValue = Math.max(...data);
     const minValue = Math.min(...data);
     const range = maxValue - minValue;
 
     return data.map((value) => {
       if (range === 0) {
         return 50;
       }
       const heightPercent = ((value - minValue) / range) * 100;
       return Math.max(heightPercent, 10);
     });
   }

215-221: Clamp topPercentage to [0, 100] for pie paths.

Prevents negative/overflow angles if upstream data is out of range.

-  private createPieChartPaths(topPercentage: number): { otherPath: string; topPath: string } {
-    const otherAngle = 360 - topPercentage * 3.6;
+  private createPieChartPaths(topPercentage: number): { otherPath: string; topPath: string } {
+    const pct = Math.max(0, Math.min(100, topPercentage));
+    const otherAngle = 360 - pct * 3.6;
     return {
       otherPath: this.createPieSlice(0, otherAngle),
       topPath: this.createPieSlice(otherAngle, 360),
     };
   }
apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (3)

19-19: Import isValidHexColor to guard conversions (used below).

To avoid exceptions when colors are missing/invalid.

-import { hexToRgba } from '@lfx-one/shared/utils';
+import { hexToRgba, isValidHexColor } from '@lfx-one/shared/utils';

184-196: Use translucent fill for consistency with other charts.

Align backgroundColor with shared hexToRgba for a lighter area fill.

         datasets: [
           {
             data: metric.sparklineData ?? [],
             borderColor: metric.sparklineColor ?? '',
-            backgroundColor: metric.sparklineColor ?? '',
+            backgroundColor: hexToRgba(metric.sparklineColor ?? '#0094FF', 0.1),
             fill: true,
             tension: 0.4,
             borderWidth: 2,
             pointRadius: 0,
           },
         ],

212-224: Same translucent fill for Maintainers.

Keep styling consistent across primary metrics.

         datasets: [
           {
             data: metric.sparklineData ?? [],
             borderColor: metric.sparklineColor ?? '',
-            backgroundColor: metric.sparklineColor ?? '',
+            backgroundColor: hexToRgba(metric.sparklineColor ?? '#0094FF', 0.1),
             fill: true,
             tension: 0.4,
             borderWidth: 2,
             pointRadius: 0,
           },
         ],
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 529a49e and 58dd6d0.

📒 Files selected for processing (10)
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (1 hunks)
  • apps/lfx-one/src/app/shared/services/analytics.service.ts (2 hunks)
  • apps/lfx-one/src/server/controllers/analytics.controller.ts (3 hunks)
  • apps/lfx-one/src/server/routes/analytics.route.ts (1 hunks)
  • packages/shared/src/interfaces/analytics-data.interface.ts (1 hunks)
  • packages/shared/src/interfaces/dashboard.interface.ts (1 hunks)
  • packages/shared/src/utils/color.utils.ts (1 hunks)
  • packages/shared/src/utils/index.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.html
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces

Files:

  • packages/shared/src/utils/color.utils.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts
  • apps/lfx-one/src/server/routes/analytics.route.ts
  • packages/shared/src/utils/index.ts
  • packages/shared/src/interfaces/dashboard.interface.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • packages/shared/src/interfaces/analytics-data.interface.ts
  • apps/lfx-one/src/app/shared/services/analytics.service.ts
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • packages/shared/src/utils/color.utils.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts
  • apps/lfx-one/src/server/routes/analytics.route.ts
  • packages/shared/src/utils/index.ts
  • packages/shared/src/interfaces/dashboard.interface.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • packages/shared/src/interfaces/analytics-data.interface.ts
  • apps/lfx-one/src/app/shared/services/analytics.service.ts
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • packages/shared/src/utils/color.utils.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts
  • apps/lfx-one/src/server/routes/analytics.route.ts
  • packages/shared/src/utils/index.ts
  • packages/shared/src/interfaces/dashboard.interface.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • packages/shared/src/interfaces/analytics-data.interface.ts
  • apps/lfx-one/src/app/shared/services/analytics.service.ts
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts
**/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Do not use barrel exports; always use direct imports for standalone components

Files:

  • packages/shared/src/utils/index.ts
packages/shared/src/interfaces/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all TypeScript interfaces in the shared package at packages/shared/src/interfaces

Files:

  • packages/shared/src/interfaces/dashboard.interface.ts
  • packages/shared/src/interfaces/analytics-data.interface.ts
🧬 Code graph analysis (4)
apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (5)
apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts (1)
  • Component (10-16)
packages/shared/src/interfaces/dashboard.interface.ts (4)
  • ContributionMetric (94-103)
  • ImpactMetric (109-118)
  • OrganizationInvolvementMetricWithChart (124-167)
  • PrimaryInvolvementMetric (63-88)
packages/shared/src/constants/organization-involvement.constants.ts (3)
  • CONTRIBUTIONS_METRICS (66-87)
  • IMPACT_METRICS (93-114)
  • PRIMARY_INVOLVEMENT_METRICS (20-60)
packages/shared/src/interfaces/analytics-data.interface.ts (3)
  • OrganizationContributorsResponse (241-261)
  • OrganizationMaintainersResponse (184-199)
  • MembershipTierResponse (205-235)
packages/shared/src/utils/color.utils.ts (1)
  • hexToRgba (28-56)
apps/lfx-one/src/server/controllers/analytics.controller.ts (2)
packages/shared/src/interfaces/analytics-data.interface.ts (11)
  • ProjectCountRow (307-309)
  • MemberDashboardMaintainersRow (267-272)
  • OrganizationMaintainersResponse (184-199)
  • MembershipTierRow (278-290)
  • MembershipTierResponse (205-235)
  • OrganizationContributorsRow (296-301)
  • OrganizationContributorsResponse (241-261)
  • OrganizationEventAttendanceRow (328-334)
  • OrganizationEventAttendanceResponse (340-365)
  • OrganizationTechnicalCommitteeRow (381-385)
  • OrganizationTechnicalCommitteeResponse (391-406)
apps/lfx-one/src/server/errors/index.ts (1)
  • ResourceNotFoundError (7-7)
apps/lfx-one/src/app/shared/services/analytics.service.ts (1)
packages/shared/src/interfaces/analytics-data.interface.ts (5)
  • OrganizationMaintainersResponse (184-199)
  • OrganizationContributorsResponse (241-261)
  • MembershipTierResponse (205-235)
  • OrganizationEventAttendanceResponse (340-365)
  • OrganizationTechnicalCommitteeResponse (391-406)
apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (4)
packages/shared/src/interfaces/dashboard.interface.ts (2)
  • Foundation (228-257)
  • OrgDependencyRiskLevel (179-179)
apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts (1)
  • Component (8-42)
packages/shared/src/constants/foundation-health.constants.ts (1)
  • FOUNDATION_HEALTH_DATA (31-161)
packages/shared/src/utils/color.utils.ts (1)
  • hexToRgba (28-56)
🔇 Additional comments (1)
packages/shared/src/interfaces/analytics-data.interface.ts (1)

180-406: Well-structured interface definitions.

The new analytics interfaces follow consistent patterns: Row interfaces use SCREAMING_SNAKE_CASE for Snowflake raw data, while Response interfaces use camelCase for API contracts. All interfaces are properly documented with JSDoc comments and follow the coding guidelines.

asithade and others added 3 commits October 29, 2025 14:19
Implement Board Member persona dashboard with three key components:
- Organization Involvement with Snowflake integration
- Foundation Health metrics
- Pending Actions (persona-aware)

Backend changes:
- Add organization maintainers endpoint
- Add membership tier endpoint
- Integrate Snowflake queries with proper error handling

Frontend changes:
- Create board-member-dashboard component
- Create organization-involvement component with loading state
- Create foundation-health component
- Create health-score-tag component
- Add persona routing and navigation

Shared package updates:
- Add OrganizationMaintainersResponse interface
- Add MembershipTierResponse interface
- Add organization involvement constants
- Add foundation health constants
- Update persona configuration

LFXV2-687

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <asithade@gmail.com>
- Add organization contributors, event attendance, and technical committee endpoints
- Implement visual connection status indicators for live vs placeholder data
- Update bar charts for Active Contributors and Maintainers with solid fills and rounded corners
- Refactor membership tier to use consolidated dashboard table
- Create shared color utility functions with validation
- Add comprehensive TypeScript interfaces for Snowflake data

LFXV2-687

Signed-off-by: Asitha de Silva <asithade@gmail.com>
Add dynamic organization selection dropdown to board member dashboard that allows
users to filter analytics data by different organizations. The dropdown displays
12 predefined organizations and persists the selection to localStorage.

Key changes:
- Add Account interface and constants with 12 organizations
- Create AccountContextService to manage selected organization state
- Add organization dropdown to board member dashboard header
- Update analytics service methods to accept optional accountId parameter
- Modify backend analytics controller to read accountId from query params
- Fix reactive data flow using toObservable and RxJS operators
- Update membership tier to use correct Snowflake column names
  (CURRENT_MEMBERSHIP_START_DATE, CURRENT_MEMBERSHIP_END_DATE)

The implementation uses Angular signals for reactive state management,
automatically refreshing all dashboard metrics when organization changes.

Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Jordan Evans <jevans@linuxfoundation.org>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (2)
apps/lfx-one/src/app/shared/services/analytics.service.ts (1)

99-198: Error handling pattern is consistent with existing methods.

All five new organization analytics methods follow the established error-handling pattern of returning default empty values on failure. As noted in previous reviews, this pattern masks authentication, authorization, network, and backend errors by making them indistinguishable from legitimate empty data.

Since this pattern is consistent with the existing methods in this service (lines 30-94), the trade-off between consistency and error visibility appears intentional. However, for organization-scoped endpoints that require authorization, consider whether proper error propagation would provide better UX for distinguishing between "no data" and "access denied" scenarios.

apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (1)

126-128: Guard against empty arrays in calculateAverage.

This issue was previously flagged: when data.length === 0, the division results in NaN. Add a guard to return a sensible default (e.g., 0) before performing the calculation.

Apply this diff to fix:

 private calculateAverage(data: number[]): number {
+  if (!data.length) return 0;
   return Math.round(data.reduce((sum, val) => sum + val, 0) / data.length);
 }
🧹 Nitpick comments (5)
packages/shared/src/constants/accounts.constants.ts (1)

10-32: Consider whether account data should be fetched dynamically.

The hardcoded list of 12 organizations with Salesforce account IDs creates a maintenance burden if accounts are added, removed, or updated. Any changes to organization names or account IDs will require code modifications and redeployment.

Consider whether this data should be:

  1. Fetched from a backend endpoint (recommended if the list changes periodically)
  2. Kept as hardcoded constants (acceptable if the list is truly static and managed by board governance)

If hardcoding is intentional for a fixed board member roster, this is acceptable but should be documented as such.

apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts (1)

32-38: Consider using proper typing for the event parameter.

The event parameter is typed as any, which bypasses TypeScript's type safety. While this may work with PrimeNG's select component, consider defining a more specific interface or using PrimeNG's event types if available.

Example improvement:

protected handleAccountChange(event: { value: string }): void {
  const selectedAccountId = event.value;
  const selectedAccount = this.accountContextService.availableAccounts.find((acc) => acc.accountId === selectedAccountId);
  if (selectedAccount) {
    this.accountContextService.setAccount(selectedAccount);
  }
}
apps/lfx-one/src/app/shared/services/account-context.service.ts (1)

24-27: Consider validating account membership in setAccount.

The setAccount method doesn't verify that the provided account exists in availableAccounts. While this may be fine for the current use case, adding validation could prevent potential issues if called with invalid account data.

Example:

public setAccount(account: Account): void {
  if (!this.availableAccounts.some(acc => acc.accountId === account.accountId)) {
    console.warn('Attempted to set invalid account:', account);
    return;
  }
  this.selectedAccount.set(account);
  this.persistAccount(account);
}
apps/lfx-one/src/server/controllers/analytics.controller.ts (2)

409-410: Address TODO: Hardcoded projectId needs dynamic resolution.

The hardcoded projectId with an inline TODO indicates this should be resolved from user profile or session. Until implemented, this limits the endpoint to a single project context.

Do you want me to open a new issue to track implementing dynamic projectId resolution from user context?


415-415: Consider explicit column selection instead of SELECT *.

While SELECT * works for a controlled table structure, explicitly listing required columns (MEMBERSHIP_TIER, CURRENT_MEMBERSHIP_START_DATE, CURRENT_MEMBERSHIP_END_DATE, MEMBERSHIP_PRICE, MEMBERSHIP_STATUS, ACCOUNT_ID) would:

  • Document the expected schema
  • Reduce payload if table schema expands
  • Make the query more maintainable
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 58dd6d0 and f130ddd.

📒 Files selected for processing (33)
  • .vscode/settings.json (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.scss (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.scss (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.scss (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.scss (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/pending-actions/pending-actions.component.ts (2 hunks)
  • apps/lfx-one/src/app/modules/dashboards/dashboard.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/dashboard.component.ts (2 hunks)
  • apps/lfx-one/src/app/shared/services/account-context.service.ts (1 hunks)
  • apps/lfx-one/src/app/shared/services/analytics.service.ts (2 hunks)
  • apps/lfx-one/src/server/controllers/analytics.controller.ts (3 hunks)
  • apps/lfx-one/src/server/routes/analytics.route.ts (1 hunks)
  • packages/shared/src/constants/accounts.constants.ts (1 hunks)
  • packages/shared/src/constants/action-items.constants.ts (1 hunks)
  • packages/shared/src/constants/foundation-health.constants.ts (1 hunks)
  • packages/shared/src/constants/index.ts (1 hunks)
  • packages/shared/src/constants/organization-involvement.constants.ts (1 hunks)
  • packages/shared/src/constants/persona.constants.ts (1 hunks)
  • packages/shared/src/interfaces/account.interface.ts (1 hunks)
  • packages/shared/src/interfaces/analytics-data.interface.ts (1 hunks)
  • packages/shared/src/interfaces/dashboard.interface.ts (1 hunks)
  • packages/shared/src/interfaces/index.ts (1 hunks)
  • packages/shared/src/interfaces/persona.interface.ts (1 hunks)
  • packages/shared/src/utils/color.utils.ts (1 hunks)
  • packages/shared/src/utils/index.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (14)
  • .vscode/settings.json
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.html
  • apps/lfx-one/src/app/modules/dashboards/components/pending-actions/pending-actions.component.ts
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.scss
  • packages/shared/src/constants/foundation-health.constants.ts
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.scss
  • apps/lfx-one/src/app/modules/dashboards/dashboard.component.html
  • packages/shared/src/utils/color.utils.ts
  • apps/lfx-one/src/app/modules/dashboards/dashboard.component.ts
  • packages/shared/src/utils/index.ts
  • packages/shared/src/constants/organization-involvement.constants.ts
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.html
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.scss
  • packages/shared/src/interfaces/dashboard.interface.ts
🧰 Additional context used
📓 Path-based instructions (7)
packages/shared/src/interfaces/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all TypeScript interfaces in the shared package at packages/shared/src/interfaces

Files:

  • packages/shared/src/interfaces/account.interface.ts
  • packages/shared/src/interfaces/index.ts
  • packages/shared/src/interfaces/persona.interface.ts
  • packages/shared/src/interfaces/analytics-data.interface.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces

Files:

  • packages/shared/src/interfaces/account.interface.ts
  • packages/shared/src/interfaces/index.ts
  • apps/lfx-one/src/app/shared/services/analytics.service.ts
  • packages/shared/src/interfaces/persona.interface.ts
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts
  • apps/lfx-one/src/server/routes/analytics.route.ts
  • packages/shared/src/constants/accounts.constants.ts
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts
  • packages/shared/src/constants/action-items.constants.ts
  • apps/lfx-one/src/app/shared/services/account-context.service.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts
  • packages/shared/src/constants/persona.constants.ts
  • packages/shared/src/interfaces/analytics-data.interface.ts
  • packages/shared/src/constants/index.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • packages/shared/src/interfaces/account.interface.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.scss
  • packages/shared/src/interfaces/index.ts
  • apps/lfx-one/src/app/shared/services/analytics.service.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.html
  • packages/shared/src/interfaces/persona.interface.ts
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts
  • apps/lfx-one/src/server/routes/analytics.route.ts
  • packages/shared/src/constants/accounts.constants.ts
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts
  • packages/shared/src/constants/action-items.constants.ts
  • apps/lfx-one/src/app/shared/services/account-context.service.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts
  • packages/shared/src/constants/persona.constants.ts
  • packages/shared/src/interfaces/analytics-data.interface.ts
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.html
  • packages/shared/src/constants/index.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • packages/shared/src/interfaces/account.interface.ts
  • packages/shared/src/interfaces/index.ts
  • apps/lfx-one/src/app/shared/services/analytics.service.ts
  • packages/shared/src/interfaces/persona.interface.ts
  • apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts
  • apps/lfx-one/src/server/routes/analytics.route.ts
  • packages/shared/src/constants/accounts.constants.ts
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts
  • packages/shared/src/constants/action-items.constants.ts
  • apps/lfx-one/src/app/shared/services/account-context.service.ts
  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts
  • packages/shared/src/constants/persona.constants.ts
  • packages/shared/src/interfaces/analytics-data.interface.ts
  • packages/shared/src/constants/index.ts
**/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Do not use barrel exports; always use direct imports for standalone components

Files:

  • packages/shared/src/interfaces/index.ts
  • packages/shared/src/constants/index.ts
apps/lfx-one/src/**/*.html

📄 CodeRabbit inference engine (CLAUDE.md)

apps/lfx-one/src/**/*.html: Always add data-testid attributes when creating new Angular components for reliable test targeting
Use data-testid naming convention [section]-[component]-[element]

Files:

  • apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.html
  • apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.html
packages/shared/src/constants/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all reusable constants in the shared package at packages/shared/src/constants

Files:

  • packages/shared/src/constants/accounts.constants.ts
  • packages/shared/src/constants/action-items.constants.ts
  • packages/shared/src/constants/persona.constants.ts
  • packages/shared/src/constants/index.ts
🧠 Learnings (3)
📚 Learning: 2025-09-16T03:32:46.518Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T03:32:46.518Z
Learning: Applies to packages/shared/src/interfaces/**/*.ts : Place all TypeScript interfaces in the shared package at packages/shared/src/interfaces

Applied to files:

  • packages/shared/src/interfaces/index.ts
📚 Learning: 2025-09-16T03:32:46.518Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T03:32:46.518Z
Learning: Applies to packages/shared/src/constants/**/*.ts : Place all reusable constants in the shared package at packages/shared/src/constants

Applied to files:

  • packages/shared/src/constants/accounts.constants.ts
  • packages/shared/src/constants/index.ts
📚 Learning: 2025-09-16T03:32:46.518Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T03:32:46.518Z
Learning: Applies to apps/lfx-one/src/**/*.html : Always add data-testid attributes when creating new Angular components for reliable test targeting

Applied to files:

  • apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts
🧬 Code graph analysis (9)
apps/lfx-one/src/app/shared/services/analytics.service.ts (1)
packages/shared/src/interfaces/analytics-data.interface.ts (5)
  • OrganizationMaintainersResponse (184-199)
  • OrganizationContributorsResponse (241-261)
  • MembershipTierResponse (205-235)
  • OrganizationEventAttendanceResponse (340-365)
  • OrganizationTechnicalCommitteeResponse (391-406)
apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts (4)
apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (1)
  • Component (23-309)
apps/lfx-one/src/app/modules/dashboards/components/pending-actions/pending-actions.component.ts (1)
  • Component (12-49)
apps/lfx-one/src/app/modules/dashboards/dashboard.component.ts (1)
  • Component (17-34)
packages/shared/src/interfaces/account.interface.ts (1)
  • Account (8-13)
packages/shared/src/constants/accounts.constants.ts (1)
packages/shared/src/interfaces/account.interface.ts (1)
  • Account (8-13)
apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (3)
packages/shared/src/interfaces/dashboard.interface.ts (2)
  • Foundation (228-257)
  • OrgDependencyRiskLevel (179-179)
packages/shared/src/constants/foundation-health.constants.ts (1)
  • FOUNDATION_HEALTH_DATA (31-161)
packages/shared/src/utils/color.utils.ts (1)
  • hexToRgba (28-56)
packages/shared/src/constants/action-items.constants.ts (1)
packages/shared/src/interfaces/components.interface.ts (1)
  • PendingActionItem (336-349)
apps/lfx-one/src/app/shared/services/account-context.service.ts (2)
packages/shared/src/interfaces/account.interface.ts (1)
  • Account (8-13)
packages/shared/src/constants/accounts.constants.ts (2)
  • ACCOUNTS (10-23)
  • DEFAULT_ACCOUNT (29-32)
apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (5)
apps/lfx-one/src/app/modules/dashboards/board-member/board-member-dashboard.component.ts (1)
  • Component (14-39)
packages/shared/src/interfaces/dashboard.interface.ts (4)
  • ContributionMetric (94-103)
  • ImpactMetric (109-118)
  • OrganizationInvolvementMetricWithChart (124-167)
  • PrimaryInvolvementMetric (63-88)
packages/shared/src/constants/organization-involvement.constants.ts (3)
  • CONTRIBUTIONS_METRICS (66-87)
  • IMPACT_METRICS (93-114)
  • PRIMARY_INVOLVEMENT_METRICS (20-60)
packages/shared/src/interfaces/analytics-data.interface.ts (3)
  • OrganizationContributorsResponse (241-261)
  • OrganizationMaintainersResponse (184-199)
  • MembershipTierResponse (205-235)
packages/shared/src/utils/color.utils.ts (1)
  • hexToRgba (28-56)
apps/lfx-one/src/server/controllers/analytics.controller.ts (2)
packages/shared/src/interfaces/analytics-data.interface.ts (11)
  • ProjectCountRow (307-309)
  • MemberDashboardMaintainersRow (267-272)
  • OrganizationMaintainersResponse (184-199)
  • MembershipTierRow (278-290)
  • MembershipTierResponse (205-235)
  • OrganizationContributorsRow (296-301)
  • OrganizationContributorsResponse (241-261)
  • OrganizationEventAttendanceRow (328-334)
  • OrganizationEventAttendanceResponse (340-365)
  • OrganizationTechnicalCommitteeRow (381-385)
  • OrganizationTechnicalCommitteeResponse (391-406)
apps/lfx-one/src/server/errors/index.ts (1)
  • ResourceNotFoundError (7-7)
apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts (2)
apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.ts (1)
  • Component (52-222)
packages/shared/src/interfaces/dashboard.interface.ts (1)
  • FoundationHealthScore (173-173)
🔇 Additional comments (18)
apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.scss (1)

1-2: License header correctly applied. The required copyright notice and SPDX-License-Identifier are properly formatted per coding guidelines.

packages/shared/src/interfaces/analytics-data.interface.ts (1)

180-406: LGTM! Well-structured interface definitions.

The new interfaces follow proper conventions:

  • Snowflake row interfaces use UPPERCASE field names matching database columns
  • API response interfaces use camelCase for JavaScript consumption
  • Comprehensive JSDoc documentation for all fields
  • Clear separation between raw database rows and transformed API responses
packages/shared/src/interfaces/index.ts (1)

68-69: LGTM! Proper barrel export addition.

The new account interface export follows the established pattern and aligns with the coding guideline to place all TypeScript interfaces in the shared package.

packages/shared/src/interfaces/persona.interface.ts (1)

8-8: LGTM! Type extension supports new persona.

The addition of 'board-member' to the PersonaType union cleanly enables the new board member dashboard flows.

packages/shared/src/constants/persona.constants.ts (1)

25-29: LGTM! Persona option aligns with type definition.

The new board member option is consistent with other persona definitions and properly integrates with the updated PersonaType union.

packages/shared/src/interfaces/account.interface.ts (1)

1-13: LGTM! Clean interface definition.

The Account interface is well-documented and follows established patterns for the shared interfaces package.

packages/shared/src/constants/index.ts (1)

20-22: LGTM! Proper constant exports.

The new barrel exports follow the established pattern and align with the coding guideline to place all reusable constants in the shared package.

packages/shared/src/constants/action-items.constants.ts (1)

66-86: LGTM!

The board member action items follow the same structure and conventions as existing persona action items, with appropriate fields and type-safe implementation.

apps/lfx-one/src/app/modules/dashboards/components/health-score-tag/health-score-tag.component.ts (1)

1-42: LGTM!

The component implementation is clean, type-safe, and follows Angular best practices. The CSS class mapping and label formatting logic are straightforward and correct.

apps/lfx-one/src/app/modules/dashboards/components/foundation-health/foundation-health.component.html (1)

1-184: LGTM!

The template is well-structured with proper Angular control flow, comprehensive data-testid attributes for testing, accessibility features (tooltips and help icons), and a responsive layout. The implementation follows all coding guidelines.

apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.html (1)

1-149: LGTM!

The template provides a comprehensive organization involvement view with proper loading states, data-testid attributes for testing, accessibility features, and responsive layout. The implementation follows Angular best practices and coding guidelines.

apps/lfx-one/src/app/shared/services/account-context.service.ts (1)

40-50: LGTM!

The loadStoredAccount method includes proper error handling for JSON parsing errors, safely returning null to fall back to the default account.

apps/lfx-one/src/app/modules/dashboards/components/organization-involvement/organization-involvement.component.ts (1)

250-284: LGTM!

The membership tier transformation includes proper date parsing, formatting, and null-safe handling with appropriate fallbacks.

apps/lfx-one/src/server/controllers/analytics.controller.ts (5)

261-261: LGTM: Type-safe query result.

The change to ProjectCountRow correctly aligns with the query's TOTAL_PROJECTS column and improves type safety.


362-362: Verify the hardcoded fallback accountId pattern.

Multiple endpoints (lines 362, 411, 470, 522, 577) use the same hardcoded fallback accountId: '0014100000Te0OKAAZ'. While this may be acceptable for development with Microsoft Corporation as default, ensure this aligns with production requirements and consider:

  • Whether a fallback should exist in production
  • If the default should be configurable via environment variable
  • Whether missing accountId should return an error instead

465-510: LGTM: Consistent implementation pattern.

The endpoint follows the same well-structured pattern as other analytics endpoints with parameterized queries, proper error handling, and comprehensive logging.


517-565: LGTM: Proper SQL aggregation.

The endpoint correctly uses SQL aggregation (SUM, COUNT) with appropriate handling for grouped columns via MAX(). The parameterized query, error handling, and logging are all well-implemented.


572-619: LGTM: Well-structured aggregation query.

The endpoint follows the established pattern with appropriate SQL aggregation for technical committee statistics. Implementation is consistent with other analytics endpoints.

- Add pool configuration for connection validation (testOnBorrow, evictionRunIntervalMillis, idleTimeoutMillis)
- Remove lock TTL buffer to prevent false deduplication hits on first requests
- Add comprehensive environment variable validation with clear error messages
- Wrap Snowflake SDK errors in MicroserviceError for proper ERROR-level logging
- Fix "Unhandled API error" by providing structured error responses

Resolves issues:
- "Unable to perform operation using terminated connection" errors
- False "Query deduplication hit" messages on first-time requests
- Missing SNOWFLAKE_USER validation causing unclear error messages
- INFO-level logging for errors instead of proper ERROR-level logs

LFXV2-687

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <asithade@gmail.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
apps/lfx-one/src/server/services/snowflake.service.ts (2)

251-282: LGTM: Comprehensive environment validation.

The upfront validation of all required environment variables with detailed error reporting significantly improves debuggability. The requiredEnvVars object approach is clean and makes subsequent usage clear.

Consider using a type guard or assertion function to avoid non-null assertions later. For example:

type ValidatedEnvVars = {
  [K in keyof typeof requiredEnvVars]: string;
};

function validateEnvVars(): ValidatedEnvVars {
  const requiredEnvVars = {
    SNOWFLAKE_ACCOUNT: process.env['SNOWFLAKE_ACCOUNT'],
    SNOWFLAKE_USER: process.env['SNOWFLAKE_USER'],
    // ... rest
  };
  
  const missingVars = Object.entries(requiredEnvVars)
    .filter(([, value]) => !value)
    .map(([key]) => key);

  if (missingVars.length > 0) {
    // throw error
  }
  
  return requiredEnvVars as ValidatedEnvVars;
}

This eliminates the need for ! assertions on lines 284, 292-299.


288-289: Add validation for numeric environment variables.

Number() returns NaN for invalid input, which would silently fall back to defaults. Consider validating that parsed values are valid numbers and logging a warning if environment variables are set but invalid.

const parseNumericEnv = (key: string, defaultValue: number): number => {
  const value = process.env[key];
  if (!value) return defaultValue;
  
  const parsed = Number(value);
  if (isNaN(parsed)) {
    serverLogger.warn(
      { key, value, default: defaultValue },
      'Invalid numeric environment variable, using default'
    );
    return defaultValue;
  }
  return parsed;
};

const minConnections = parseNumericEnv('SNOWFLAKE_MIN_CONNECTIONS', SNOWFLAKE_CONFIG.MIN_CONNECTIONS);
const maxConnections = parseNumericEnv('SNOWFLAKE_MAX_CONNECTIONS', SNOWFLAKE_CONFIG.MAX_CONNECTIONS);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f130ddd and 27924da.

📒 Files selected for processing (2)
  • apps/lfx-one/src/server/services/snowflake.service.ts (5 hunks)
  • apps/lfx-one/src/server/utils/lock-manager.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces

Files:

  • apps/lfx-one/src/server/services/snowflake.service.ts
  • apps/lfx-one/src/server/utils/lock-manager.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • apps/lfx-one/src/server/services/snowflake.service.ts
  • apps/lfx-one/src/server/utils/lock-manager.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • apps/lfx-one/src/server/services/snowflake.service.ts
  • apps/lfx-one/src/server/utils/lock-manager.ts
🧬 Code graph analysis (1)
apps/lfx-one/src/server/services/snowflake.service.ts (2)
apps/lfx-one/src/server/errors/index.ts (1)
  • MicroserviceError (6-6)
packages/shared/src/constants/snowflake.constant.ts (1)
  • SNOWFLAKE_CONFIG (7-57)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-push
🔇 Additional comments (4)
apps/lfx-one/src/server/utils/lock-manager.ts (1)

165-167: LGTM! Immediate lock cleanup is correct for non-caching deduplication.

The immediate deletion is safe because the promise has already resolved by the time the finally block executes, ensuring all waiters receive the result. This change reduces memory footprint while maintaining the fetch lock pattern's core benefit: preventing duplicate concurrent executions. The periodic cleanup (lines 225-243) now serves as a safety mechanism for hung queries rather than the primary cleanup path, which is an appropriate design.

apps/lfx-one/src/server/services/snowflake.service.ts (3)

9-9: LGTM: Standardized error handling.

The import of MicroserviceError enables consistent error wrapping throughout the service, which aligns with the broader error handling improvements in this PR.


303-316: LGTM: Robust pool configuration.

The extended pool options (testOnBorrow, eviction intervals, timeouts) improve connection health and resource management. Setting testOnBorrow: true adds a small latency cost but prevents using stale connections, which is appropriate for production reliability.


336-353: LGTM: Consistent error wrapping pattern.

The error handling follows the same MicroserviceError wrapping pattern used in the execute method, providing consistent error structure and debugging metadata across the service.

Note: The inconsistent use of process.env['SNOWFLAKE_ACCOUNT'] on line 350 (instead of requiredEnvVars.SNOWFLAKE_ACCOUNT) was already flagged in an earlier comment.

- Pass originalError to MicroserviceError constructor to preserve full stack traces
- Use validated requiredEnvVars instead of direct process.env access in logging
- Ensures consistency between logged values and actual configuration used

LFXV2-687

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <asithade@gmail.com>
@dealako dealako merged commit 53a3893 into main Oct 30, 2025
6 checks passed
@dealako dealako deleted the feat/LFXV2-687 branch October 30, 2025 15:17
@github-actions
Copy link

🧹 Deployment Removed

The deployment for PR #134 has been removed.

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.

4 participants