Skip to content

Conversation

@asithade
Copy link
Contributor

@asithade asithade commented Oct 24, 2025

Summary

Implements server-side pagination for the My Projects dashboard to improve performance and loading times when dealing with large datasets.

JIRA

LFXV2-682

Changes Made

Backend

  • Added pagination query parameters (page, limit) to analytics controller
  • Implemented efficient two-query approach: count total projects, then fetch paginated data
  • Used CTE with LIMIT/OFFSET for optimal Snowflake query performance
  • Added comprehensive logging for pagination metrics

Frontend Service

  • Updated getMyProjects() to accept page and limit parameters
  • Passes pagination parameters as query string params

Component

  • Refactored to use Angular 19 reactive patterns: BehaviorSubject + toSignal
  • Removed manual .subscribe() calls for better memory management
  • Added loading signal with tap/finalize operators
  • Removed verbose comments for cleaner code
  • Implemented automatic request cancellation via switchMap

Template

  • Added loading overlay with spinner during data fetch
  • Enabled PrimeNG lazy loading mode with pagination controls
  • Shows "Showing X to Y of Z projects" pagination report

Technical Details

  • Uses BehaviorSubject to trigger pagination changes
  • toSignal converts Observable to Signal for seamless Angular 19 integration
  • switchMap automatically cancels previous requests
  • Loading state managed via signals with tap (set true) and finalize (set false)

Performance Benefits

  • Reduced network payload by fetching only required page
  • Reduced memory usage on frontend
  • Better UX with loading indicators
  • Scalable for large project lists

Test Plan

  • Verify pagination controls work correctly
  • Verify loading indicator appears during data fetch
  • Verify page changes trigger server requests
  • Verify total record count displays correctly
  • All linting, formatting, and type checks pass
  • Build completes successfully

- Add pagination query parameters (page, limit) to analytics controller
- Implement efficient two-query approach with CTE for Snowflake
- Refactor component to use BehaviorSubject + toSignal pattern
- Remove manual subscriptions for better memory management
- Add loading indicator with signal-based state management
- Enable PrimeNG lazy loading mode with pagination controls
- Remove verbose comments for cleaner code

LFXV2-682

Signed-off-by: Asitha de Silva <[email protected]>
@asithade asithade requested a review from jordane as a code owner October 24, 2025 18:04
Copilot AI review requested due to automatic review settings October 24, 2025 18:04
@coderabbitai
Copy link

coderabbitai bot commented Oct 24, 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

Implements API-driven, paginated my-projects UI with loading overlay; adds AnalyticsService.getMyProjects, server GET /api/analytics/my-projects endpoint and route, and new shared interfaces for project activity and paginated responses. Duplicate controller implementation observed in diff.

Changes

Cohort / File(s) Summary
Frontend: Component
apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.html, apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.ts
Replaced static table with <lfx-table> supporting lazy loading, pagination, rowsPerPage options, onLazyLoad handler and loading overlay. Component converted to reactive signals/computed, fetches paginated projects from AnalyticsService, exposes rows, projects, paginatedProjects, totalRecords, and onPageChange. chartOptions visibility changed to public.
Frontend: Service
apps/lfx-one/src/app/shared/services/analytics.service.ts
Added getMyProjects(page?: number, limit?: number): Observable<UserProjectsResponse> which calls /api/analytics/my-projects with pagination and returns a safe default on error.
Backend: Controller
apps/lfx-one/src/server/controllers/analytics.controller.ts
Added getMyProjects controller method (GET /api/analytics/my-projects) implementing pagination, total project count query and paginated project activity retrieval (CTE/joins/aggregation), returning UserProjectsResponse. Note: duplicate implementation block present in file diff.
Backend: Route
apps/lfx-one/src/server/routes/analytics.route.ts
Registered new route /my-projects mapping to AnalyticsController.getMyProjects.
Shared Interfaces
packages/shared/src/interfaces/analytics-data.interface.ts, packages/shared/src/interfaces/components.interface.ts
Added UserProjectActivityRow and UserProjectsResponse interfaces; added ProjectItemWithCharts extending ProjectItem to include codeActivitiesChartData and nonCodeActivitiesChartData.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Component
    participant Service
    participant Controller
    participant DB

    Note over Component,Service: Initial load / pagination flow
    User->>Component: Open My Projects
    Component->>Component: set loading = true
    Component->>Service: getMyProjects(page=1, limit=10)
    Service->>Controller: GET /api/analytics/my-projects?page=1&limit=10
    Controller->>DB: Query totalProjects and paginated project activity (CTE + aggregates)
    DB-->>Controller: ProjectItem[] + totalProjects
    Controller-->>Service: UserProjectsResponse
    Service-->>Component: Observable<UserProjectsResponse]
    Component->>Component: update signals (projectsResponse → projects, totalRecords)
    Component->>Component: set loading = false
    Component-->>User: Render table page

    alt User changes page or rows
        User->>Component: onPageChange({first, rows})
        Component->>Component: update pagination state
        Component->>Service: getMyProjects(newPage, newLimit)
        Service->>Controller: GET /api/analytics/my-projects?page=X&limit=Y
        Controller->>DB: Query with new pagination
        DB-->>Controller: ProjectItem[] + totalProjects
        Controller-->>Service: UserProjectsResponse
        Service-->>Component: Observable<UserProjectsResponse]
        Component->>Component: update display
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

deploy-preview

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "feat(dashboard): implement server-side pagination for my projects" directly and clearly summarizes the primary objective of the changeset. It concisely describes the main feature being implemented without vague terminology or unnecessary detail. The title accurately reflects the scope of changes across the backend (pagination parameters and query logic), frontend service (parameter acceptance), component (reactive refactoring), and template (pagination UI), making it immediately clear what the PR accomplishes.
Linked Issues Check ✅ Passed The implementation comprehensively addresses all objectives from linked issue LFXV2-682. Backend changes include pagination parameters (page, limit) in the analytics controller, a two-query approach with total count followed by paginated data fetch, CTE with LIMIT/OFFSET for Snowflake optimization, and pagination logging. Frontend service now accepts and forwards pagination parameters. The component uses Angular 19 reactive patterns with BehaviorSubject and toSignal, removes manual subscriptions, implements switchMap for request cancellation, and manages loading state with tap/finalize. The template adds a loading overlay with spinner, enables PrimeNG lazy loading with pagination controls, and displays the "Showing X to Y of Z projects" report. All coding requirements are fulfilled.
Out of Scope Changes Check ✅ Passed The primary changes are all directly related to implementing server-side pagination for the My Projects dashboard, as specified in linked issue LFXV2-682. The PR includes backend pagination logic, frontend service updates, component refactoring to reactive patterns, template pagination UI, and necessary interface definitions. However, the analytics controller changes include updates to database source references (ANALYTICS_DEV.DEV_JEVANS_PLATINUM_LFX_ONE to ANALYTICS.PLATINUM_LFX_ONE) for existing queries, which are not explicitly mentioned in either the PR description's "Changes Made" section or the linked issue objectives. While these reference updates may be necessary supporting infrastructure, they appear to be incidental changes worth clarifying.
Description Check ✅ Passed The pull request description is comprehensive and directly related to the changeset. It provides a clear summary of the implementation, includes the linked JIRA issue reference, details all significant changes organized by component (Backend, Frontend Service, Component, Template), explains the technical approach and performance benefits, and references a completed test plan. The description meaningfully explains the changes rather than being vague or generic, allowing reviewers to understand the scope and intent.
✨ 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-682

📜 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 c152c2b and 46fff4b.

📒 Files selected for processing (4)
  • apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.ts (3 hunks)
  • apps/lfx-one/src/server/controllers/analytics.controller.ts (4 hunks)
  • packages/shared/src/interfaces/components.interface.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
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/components.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/components.interface.ts
  • apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.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/components.interface.ts
  • apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.html
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • packages/shared/src/interfaces/components.interface.ts
  • apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.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/my-projects/my-projects.component.html
🧬 Code graph analysis (2)
apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.ts (1)
packages/shared/src/interfaces/components.interface.ts (1)
  • ProjectItemWithCharts (389-394)
apps/lfx-one/src/server/controllers/analytics.controller.ts (2)
packages/shared/src/interfaces/analytics-data.interface.ts (2)
  • UserProjectActivityRow (128-163)
  • UserProjectsResponse (168-178)
packages/shared/src/interfaces/components.interface.ts (1)
  • ProjectItem (368-383)
🔇 Additional comments (11)
packages/shared/src/interfaces/components.interface.ts (1)

385-394: LGTM! Well-structured interface extension.

The interface correctly extends ProjectItem and adds type-safe Chart.js data properties for the dashboard charts. Documentation is clear and the line chart type constraint is appropriate.

apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.html (2)

19-29: Pagination configuration is correct.

The lfx-table configuration properly enables lazy loading and pagination with appropriate bindings for rows, totalRecords, and page options. The currentPageReportTemplate provides clear feedback to users.


49-89: Well-structured table body template.

The template correctly renders project data with conditional logo handling, affiliations, and chart visualizations. Good use of test IDs and accessibility attributes (alt text for images).

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

4-14: Imports are correct.

The new interface imports (ProjectItem, UserProjectActivityRow, UserProjectsResponse) are properly added from the shared package.


120-120: Schema migration to production is correct for existing endpoints.

The updates to use ANALYTICS.PLATINUM_LFX_ONE schema for pull requests and code commits endpoints are appropriate.


319-335: Response building and logging are well-structured.

The logic correctly transforms the projects map to an array, constructs the response object, and logs comprehensive pagination metrics for observability.

apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.ts (5)

4-14: Imports are correct and complete.

All necessary Angular 19 reactive primitives, RxJS operators, PrimeNG types, and shared interfaces are properly imported for the pagination implementation.


24-48: Excellent reactive pattern implementation.

The setup correctly uses Angular 19 reactive primitives:

  • BehaviorSubject triggers pagination changes
  • toSignal converts Observable to Signal
  • switchMap automatically cancels previous requests
  • tap/finalize manage loading state without manual subscription
  • initialValue prevents undefined state

50-59: Computed properties correctly transform API data.

The projects computed properly maps API response to ProjectItemWithCharts with chart data, and totalRecords provides the pagination total. Good color choices for code (blue) vs non-code (green) activities.


61-65: Page change handler is correctly implemented.

The handler properly uses LazyLoadEvent type (addressing past review feedback), correctly calculates 1-based page from 0-based offset, updates the rows signal, and triggers pagination via BehaviorSubject. Nullish coalescing provides safe defaults.


67-82: Chart data helper is clean and reusable.

The private helper correctly generates Chart.js line chart configurations with appropriate styling (smooth curves with tension 0.4, clean lines with pointRadius 0). Good reusability for both code and non-code activity charts.


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 server-side pagination for the "My Projects" dashboard to improve performance when handling large datasets. The implementation uses Angular 19 reactive patterns with signals and observables for efficient state management and automatic request cancellation.

Key Changes:

  • Backend implements two-query pagination approach with count and paginated data fetch using Snowflake CTEs
  • Frontend refactored to use BehaviorSubject + toSignal pattern with automatic request cancellation via switchMap
  • Added loading indicators and PrimeNG pagination controls with lazy loading mode

Reviewed Changes

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

Show a summary per file
File Description
packages/shared/src/interfaces/analytics-data.interface.ts Added UserProjectActivityRow and UserProjectsResponse interfaces for paginated project data
apps/lfx-one/src/server/routes/analytics.route.ts Added /my-projects route endpoint
apps/lfx-one/src/server/controllers/analytics.controller.ts Implemented getMyProjects controller with pagination logic and CTE-based queries
apps/lfx-one/src/app/shared/services/analytics.service.ts Added getMyProjects service method with pagination parameters
apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.ts Refactored to use reactive patterns with BehaviorSubject, toSignal, and computed signals
apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.html Added loading overlay and PrimeNG pagination controls

💡 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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/lfx-one/src/server/controllers/analytics.controller.ts (1)

120-124: Replace DEV schema references with production ANALYTICS schema

DEV schema references remain in the codebase and must be replaced before merging:

  • Line 48: ANALYTICS_DEV.DEV_JEVANS_PLATINUM_LFX_ONE.ACTIVE_WEEKS_STREAK
  • Line 246: ANALYTICS_DEV.DEV_JEVANS_PLATINUM.PROJECT_CODE_ACTIVITY
  • Line 274: ANALYTICS_DEV.DEV_JEVANS_PLATINUM.PROJECT_CODE_ACTIVITY
  • Line 288: ANALYTICS_DEV.DEV_JEVANS_PLATINUM.PROJECT_CODE_ACTIVITY

Update all occurrences to use ANALYTICS.PLATINUM_LFX_ONE (matching the pattern shown at lines 120-124).

🧹 Nitpick comments (7)
apps/lfx-one/src/server/controllers/analytics.controller.ts (2)

299-317: UI-coupled DTO and placeholder fields

Server returns UI-oriented ProjectItem with placeholder logo/role/affiliations/status. Prefer a backend DTO (e.g., UserProjectItem) and let the client adapt to view needs, or populate real values if available.


329-333: Log hygiene: avoid PII; include request id

Good metrics. Ensure no PII beyond counts is logged; include a request correlation id if available.

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

70-87: Keep type annotations if using HttpParams refactor

The component pagination correctly converts to 1-based page/limit. The service implementation works, and HttpParams usage would be a valid optional improvement for consistent parameter encoding—but the suggested diff removes type annotations, which should be preserved.

  public getMyProjects(page: number = 1, limit: number = 10): Observable<UserProjectsResponse> {
-   const params = { page: page.toString(), limit: limit.toString() };
+   const params = new HttpParams().set('page', String(page)).set('limit', String(limit));
    return this.http.get<UserProjectsResponse>('/api/analytics/my-projects', { params }).pipe(

Add HttpParams to the imports from @angular/common/http if adopting this change.

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

9-11: Prep imports for reliability fix.

If you adopt the error-handling/loader refactor below, add catchError and of to these imports (RxJS 7+ re-exports operators from 'rxjs'). Otherwise, current imports are fine.


42-42: Single source of truth for page size.

rows duplicates paginationState.limit. Either derive rows from the subject/signal or keep only one state to avoid drift.

-  public readonly rows = signal(10);
+  public readonly rows = signal(10); // If kept, always update together with paginationState

54-61: Defensive fallback for activity arrays (optional).

If ProjectItem.codeActivities/nonCodeActivities can be null/undefined, guard to avoid Chart.js errors.

-    return response.data.map((project) => ({
+    return response.data.map((project) => ({
       ...project,
-      codeActivitiesChartData: this.createChartData(project.codeActivities, '#009AFF', 'rgba(0, 154, 255, 0.1)'),
-      nonCodeActivitiesChartData: this.createChartData(project.nonCodeActivities, '#10b981', 'rgba(16, 185, 129, 0.1)'),
+      codeActivitiesChartData: this.createChartData(project.codeActivities ?? [], '#009AFF', 'rgba(0, 154, 255, 0.1)'),
+      nonCodeActivitiesChartData: this.createChartData(project.nonCodeActivities ?? [], '#10b981', 'rgba(16, 185, 129, 0.1)'),
     }));

Confirm these fields are always arrays in the API; if so, ignore.


63-65: Remove redundant alias or document intent.

paginatedProjects just proxies projects. Drop it or leave a comment if the template relies on it for future slicing.

-  public readonly paginatedProjects = computed<ProjectItemWithCharts[]>(() => this.projects());
+  // Alias retained for template compatibility; remove when not needed.
+  public readonly paginatedProjects = computed<ProjectItemWithCharts[]>(() => this.projects());
📜 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 f89bab0 and c152c2b.

📒 Files selected for processing (6)
  • apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.html (1 hunks)
  • apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.ts (3 hunks)
  • apps/lfx-one/src/app/shared/services/analytics.service.ts (2 hunks)
  • apps/lfx-one/src/server/controllers/analytics.controller.ts (4 hunks)
  • apps/lfx-one/src/server/routes/analytics.route.ts (1 hunks)
  • packages/shared/src/interfaces/analytics-data.interface.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
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
**/*.{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/analytics-data.interface.ts
  • apps/lfx-one/src/app/shared/services/analytics.service.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • apps/lfx-one/src/server/routes/analytics.route.ts
  • apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.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/interfaces/analytics-data.interface.ts
  • apps/lfx-one/src/app/shared/services/analytics.service.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • apps/lfx-one/src/server/routes/analytics.route.ts
  • apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.ts
  • apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.html
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • packages/shared/src/interfaces/analytics-data.interface.ts
  • apps/lfx-one/src/app/shared/services/analytics.service.ts
  • apps/lfx-one/src/server/controllers/analytics.controller.ts
  • apps/lfx-one/src/server/routes/analytics.route.ts
  • apps/lfx-one/src/app/modules/dashboards/components/my-projects/my-projects.component.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/my-projects/my-projects.component.html
🧬 Code graph analysis (3)
packages/shared/src/interfaces/analytics-data.interface.ts (1)
packages/shared/src/interfaces/components.interface.ts (1)
  • ProjectItem (368-383)
apps/lfx-one/src/app/shared/services/analytics.service.ts (1)
packages/shared/src/interfaces/analytics-data.interface.ts (1)
  • UserProjectsResponse (168-178)
apps/lfx-one/src/server/controllers/analytics.controller.ts (2)
packages/shared/src/interfaces/analytics-data.interface.ts (2)
  • UserProjectActivityRow (128-163)
  • UserProjectsResponse (168-178)
packages/shared/src/interfaces/components.interface.ts (1)
  • ProjectItem (368-383)
🔇 Additional comments (8)
apps/lfx-one/src/server/routes/analytics.route.ts (1)

16-16: Route addition looks good

Endpoint name aligns with client service and router conventions.

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

4-5: Interfaces added correctly and placed in shared

Shapes are clear and documented; import is type-only.

Also applies to: 124-178

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

277-278: Confirm Snowflake bind support for LIMIT/OFFSET

Some drivers require numeric literals or CAST for LIMIT/OFFSET. If binds fail, inline sanitized integers or use CAST.

Try:

LIMIT CAST(? AS INTEGER) OFFSET CAST(? AS INTEGER)

If not supported, build literals from validated numbers (page>=1, 1<=limit<=100).

Also applies to: 294-295

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

76-86: No issues found—chart bindings properly handled

The component correctly extends ProjectItem with a local ProjectItemWithCharts interface that explicitly types codeActivitiesChartData and nonCodeActivitiesChartData as ChartData<'line'>. The mapping transforms the base codeActivities and nonCodeActivities arrays into chart datasets via this.createChartData(). This approach appropriately separates the shared data model from the component's view model.

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

5-7: Solid move to Angular 19 signals.

Adoption of inject/signal/toSignal looks good and aligns with reactive best practices.


32-40: Chart options look fine.

No issues. Consider keeping options small to minimize re-renders; current config is lean.


28-31: Loader flicker issue is valid; catchError claim needs clarification.

The core concern about finalize() causing a race condition is accurate—when switchMap cancels the previous request, finalize() sets loading=false before the new request starts, creating a flicker.

However, the review comment's claim about missing error handling is misleading. AnalyticsService.getMyProjects() already implements catchError at lines 79-84, returning the exact fallback response { data: [], totalProjects: 0 }. Errors won't cause toSignal to throw.

The refactoring suggestion (using a pendingRequests counter + computed loading signal) is still sound for eliminating the flicker. The suggested catchError in the component's switchMap would be defensive but isn't strictly required given the service-level error handling.

-import { BehaviorSubject, finalize, switchMap, tap } from 'rxjs';
+import { BehaviorSubject, finalize, of, switchMap, tap } from 'rxjs';
-  protected readonly loading = signal(true);
+  private readonly pendingRequests = signal(0);
+  public readonly loading = computed(() => this.pendingRequests() > 0);
-  private readonly projectsResponse = toSignal(
+  private readonly projectsResponse = toSignal<UserProjectsResponse>(
     this.paginationState$.pipe(
-      tap(() => this.loading.set(true)),
-      switchMap(({ page, limit }) => this.analyticsService.getMyProjects(page, limit).pipe(finalize(() => this.loading.set(false))))
+      tap(() => this.pendingRequests.update(n => n + 1)),
+      switchMap(({ page, limit }) =>
+        this.analyticsService.getMyProjects(page, limit).pipe(
+          finalize(() => this.pendingRequests.update(n => Math.max(0, n - 1)))
+        )
+      )
     ),
     {
       initialValue: { data: [], totalProjects: 0 },
     }
   );
-import type { ProjectItem } from '@lfx-one/shared/interfaces';
+import type { ProjectItem, UserProjectsResponse } from '@lfx-one/shared/interfaces';

Apply the pending-requests counter pattern to fix the flicker at lines 28–31 and 44–52.


66-70: I'll verify the correct PrimeNG type and backend pagination expectations.

Now let me check the component file to see how the pagination data is sent to the backend:

Let me check the component file to see the backend API calls and verify the page number expectations:

Use TableLazyLoadEvent from 'primeng/table' for the pagination event type.

The review comment suggests two options (PaginatorState or TableLazyLoadEvent), but only TableLazyLoadEvent should be imported from 'primeng/table'. Since the template uses (onLazyLoad)="onPageChange($event)" on the p-table component, the event is TableLazyLoadEvent, not a paginator event.

The page calculation (Math.floor(event.first / event.rows) + 1) follows the common formula offset = (page - 1) * pageSize, which is correct for 1-based pagination. However, verify that your backend API endpoint expects 1-based page numbers (not 0-based) to ensure the calculation aligns with backend expectations.

Replace the inline type with:

import type { TableLazyLoadEvent } from 'primeng/table';

public onPageChange(event: TableLazyLoadEvent): void {
  const page = Math.floor(event.first / event.rows) + 1;
  this.rows.set(event.rows);
  this.paginationState$.next({ page, limit: event.rows });
}

- Add PROJECT_ID as tie-breaker in ORDER BY for deterministic pagination
- Import and use PrimeNG LazyLoadEvent type instead of inline object
- Add null coalescing operators for safer LazyLoadEvent property access
- Move ProjectItemWithCharts interface to shared package
- Remove redundant paginatedProjects computed signal
- Use projects() signal directly in template

LFXV2-682

Signed-off-by: Asitha de Silva <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants