Skip to content

Conversation

@asithade
Copy link
Contributor

@asithade asithade commented Sep 9, 2025

Summary

Fix issues with query service tag filtering and improve committee data handling in the meetings functionality.

Changes Made

  • Interface Consolidation: Merged MeetingCommittee and MeetingCommitteePayload interfaces for better type safety
  • Committee Data Enrichment: Added committee name lookup when fetching meetings with associated committees
  • UI Component Updates: Updated meeting components to handle the consolidated committee structure
  • Service Improvements: Enhanced meeting service to properly enrich committee data
  • Form Handling: Better committee modal handling for voting status configurations

Files Modified (16 files)

  • Meeting components (HTML/TS files)
  • Server controllers and services
  • Shared package interfaces and constants

Testing

  • All lint and type checks pass
  • Build completes successfully
  • Committee data properly enriched and displayed
  • Backward compatibility maintained

JIRA Ticket

LFXV2-448

Generated with Claude Code

Signed-off-by: Asitha de Silva <asithade@gmail.com>
- Consolidate MeetingCommittee and MeetingCommitteePayload interfaces
- Add committee name enrichment when fetching meetings
- Update committee modal to handle voting status configurations
- Fix various UI components to handle updated committee structure
- Improve committee data display across meeting components

LFXV2-448

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

Signed-off-by: Asitha de Silva <asithade@gmail.com>
Copilot AI review requested due to automatic review settings September 9, 2025 16:08
@asithade asithade requested a review from jordane as a code owner September 9, 2025 16:08
@coderabbitai
Copy link

coderabbitai bot commented Sep 9, 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

Refactors meeting committee data from meeting_committees → committees across frontend and server, adds voting-status selection and filtering to the meeting-committee modal, renames meetingTool → platform in meeting forms, enriches meetings with committee names and registrant counts server-side, updates query tag formats, adjusts shared types/constants, revises E2E mocks/tests for writer permissions, and adds a Playwright setup action and workflow changes.

Changes

Cohort / File(s) Summary
Editor config
\.vscode/settings.json
Add "Uids" to cSpell.words.
Shared interfaces
packages/shared/src/interfaces/meeting.interface.ts
Replace old committee model with new MeetingCommittee (uid, allowed_voting_statuses?, name?); remove meeting_committees; change Meeting to use committees: MeetingCommittee[]; broaden nullability for many meeting fields (password, zoom_config, recurrence, visibility, and several booleans).
Shared constants
packages/shared/src/constants/meeting.constants.ts
Change MEETING_PLATFORMS .value entries to display names: "Zoom", "Microsoft Teams", "In-Person".
Frontend — committee bindings & UI tweaks
Upcoming & cards
apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.html · .../upcoming-committee-meeting.component.ts · apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.html · .../meeting-card.component.ts · apps/lfx-pcc/src/app/modules/project/meetings/meeting-dashboard/meeting-dashboard.component.ts
Replace meeting_committees usages with committees; update templates and TS logic to read committee names via committees; minor UI tweaks (icon color, link classes/tooltip removal); add null-safe name handling; small refactor computing modal header.
Meeting committee modal (voting)
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.html · .../meeting-committee-modal.component.ts
Add voting-status multi-select and form control; introduce votingStatusOptions, selectedVotingStatuses, and filteredCommitteeMembers signals; filter displayed committee members by selected voting statuses; include allowed_voting_statuses in update payload; conditional rendering of voting column; remove legacy color logic for voting badges. (New public properties added.)
Meeting manage / platform rename
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.ts · .../meeting-manage.component.html · apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-platform-features/meeting-platform-features.component.html · apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-resources-summary/meeting-resources-summary.component.html
Rename form control meetingToolplatform in form group, validation, data mapping and templates; adjust a tab panel value in manage template to align tab indices.
Client service (Angular)
apps/lfx-pcc/src/app/shared/services/meeting.service.ts
Change tags parameter to project_uid:${projectId} for meeting list endpoints (getMeetingsByProject/getUpcomingMeetingsByProject/getPastMeetingsByProject); add TODOs for upcoming/past filters.
Server — controller & service
apps/lfx-pcc/src/server/controllers/meeting.controller.ts · apps/lfx-pcc/src/server/services/meeting.service.ts
Simplify registrant counting by deriving individual vs committee counts from getMeetingRegistrants; add fallback population and error logging in getMeetingById; integrate CommitteeService to fetch committee names for unique UIDs via new getMeetingCommittees helper and enrich meeting.committees (preserving allowed_voting_statuses); adjust meeting query tags to use meeting_uid:${meetingUid}.
E2E tests & mocks
apps/lfx-pcc/e2e/fixtures/mock-data/projects.mock.ts · apps/lfx-pcc/e2e/helpers/api-mock.helper.ts · apps/lfx-pcc/e2e/project-dashboard.spec.ts
Add writer: boolean to mock projects; change ApiMockHelper.setupProjectSlugMock(page, options?) signature to accept { writer?: boolean } and optionally override project.writer; rewrite and expand project-dashboard.spec.ts into permission-aware ("With Write Permissions" / "Without Write Permissions") flows using the new mock option and consolidated navigation helper.
CI / Playwright action & workflow
.github/actions/setup-playwright/action.yml · .github/workflows/e2e-tests.yml
Add composite action to setup/cached Playwright browsers and OS deps; update e2e workflow to use the action, capture Playwright exit codes, support per-browser runs, and write test exit code outputs.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant UI as Client UI
  participant SVC as MeetingService (server)
  participant COM as CommitteeService
  participant ACL as AccessControl

  UI->>SVC: GET /meetings?tags=project_uid:${projectId}
  SVC->>SVC: Convert resources → meetings
  alt meetings contain committee UIDs
    SVC->>COM: fetch committees for unique UIDs
    COM-->>SVC: Committee { uid, name, allowed_voting_statuses? }
    SVC->>SVC: Enrich meetings' committees with names & voting info
  end
  SVC->>ACL: apply access control
  ACL-->>SVC: filtered/augmented meetings
  SVC-->>UI: return meetings (committees populated, registrant counts)
Loading
sequenceDiagram
  autonumber
  participant User as U
  participant Modal as MeetingCommitteeModalComponent
  participant API as Meeting API

  U->>Modal: open modal, select committees
  Modal->>Modal: check if any selected committee supports voting
  alt voting enabled
    Modal->>U: show Voting Status multi-select (votingStatusOptions)
    U->>Modal: choose voting statuses
    Modal->>Modal: compute filteredCommitteeMembers (by selected statuses)
  else no voting
    Modal->>Modal: filteredCommitteeMembers = all members
  end
  U->>Modal: Save
  Modal->>API: PUT /meetings/{id} with committees: [{uid, allowed_voting_statuses?}, ...]
  API-->>Modal: success/failure
  Modal-->>U: close or show error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Possibly related PRs

Pre-merge checks (4 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning Several modifications fall outside the scope of the linked issue and its objectives, including updates to the VSCode spell-checker settings, meeting platform display constants, new Playwright setup actions in CI, and extensive E2E test and mock adjustments unrelated to committee data handling and tag filtering fixes. To maintain focus on the issue objectives, consider extracting unrelated IDE settings, constant display labels, CI actions, and E2E test refactors into separate pull requests or clearly justify their inclusion here.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly references both query service tag filtering and committee data handling, accurately encapsulating the primary fixes made across the changeset and clearly signaling the scope of the changes to reviewers.
Linked Issues Check ✅ Passed The changes comprehensively address the objectives of LFXV2-448 by consolidating committee interfaces, enriching committee data in services and controllers, updating frontend components for the consolidated structure and voting-status handling, and preserving backward compatibility for meeting creation and updates.
Description Check ✅ Passed The pull request description outlines the key areas of change—including interface consolidation, backend service enrichment, UI updates, and form handling improvements—and directly relates to the files modified in this changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/LFXV2-448

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

Fix issues with query service tag filtering and improve committee data handling in the meetings functionality.

  • Merged MeetingCommittee and MeetingCommitteePayload interfaces for better type safety
  • Enhanced meeting service to properly enrich committee data during retrieval
  • Updated UI components to use the consolidated committee structure

Reviewed Changes

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

Show a summary per file
File Description
packages/shared/src/interfaces/meeting.interface.ts Consolidates committee interfaces and improves type definitions
packages/shared/src/constants/meeting.constants.ts Updates platform values to use proper casing
apps/lfx-pcc/src/server/services/meeting.service.ts Adds committee enrichment and fixes query service tag filtering
apps/lfx-pcc/src/server/controllers/meeting.controller.ts Improves registrant counting logic
apps/lfx-pcc/src/app/shared/services/meeting.service.ts Fixes tag filtering with proper prefixes
apps/lfx-pcc/src/app/modules/project/meetings/meeting-dashboard/meeting-dashboard.component.ts Updates to use consolidated committee structure
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-resources-summary/meeting-resources-summary.component.html Fixes form control reference
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-platform-features/meeting-platform-features.component.html Updates form control references
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.ts Updates form control names and validation
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.html Fixes tab panel value
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts Enhances committee modal with voting status handling
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.html Adds voting status selection UI
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts Updates to use committees property
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.html Updates template to use committees property
apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.ts Updates to use committees property
apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.html Updates template to use committees property

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@github-actions
Copy link

github-actions bot commented Sep 9, 2025

✅ E2E Tests Passed

Browser: chromium
Status: passed

All E2E tests passed successfully.

Test Configuration

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: 6

Caution

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

⚠️ Outside diff range comments (4)
apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.ts (1)

47-53: Avoid calling undefined signal; initialize committees after upcomingMeeting is created.

computed() currently calls this.upcomingMeeting() which is undefined until ngOnInit, risking a runtime error. Initialize committees after upcomingMeeting is assigned and guard against missing names.

Apply:

 export class UpcomingCommitteeMeetingComponent implements OnInit {
@@
   public committees!: Signal<string>;
 
   public constructor() {
-    this.committees = this.initializeCommittees();
+    // Defer committees initialization until upcomingMeeting is created in ngOnInit.
   }
 
   public ngOnInit() {
     runInInjectionContext(this.injector, () => {
       this.upcomingMeeting = this.initializeUpcomingMeeting();
     });
+    this.committees = this.initializeCommittees();
   }
@@
   private initializeCommittees() {
-    return computed(
-      () =>
-        this.upcomingMeeting()
-          ?.committees?.map((committee) => committee.name)
-          .join(', ') ?? ''
-    );
+    return computed(() => {
+      const meetingSignal = this.upcomingMeeting as Signal<Meeting | null> | undefined;
+      const meeting = meetingSignal ? meetingSignal() : null;
+      return (
+        meeting?.committees
+          ?.map((c) => c.name)
+          ?.filter(Boolean)
+          ?.join(', ') ?? ''
+      );
+    });
   }

Also applies to: 31-39

apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts (1)

257-269: Committee registrants in the list lack uid (breaks trackBy and data-testid).

Mapped committee members set id, but the template uses registrant.uid for tracking and test ids. This yields undefined keys and unstable DOM.

-                    return c.map((m) => ({
-                      id: m.uid,
+                    return c.map((m) => ({
+                      uid: m.uid,
                       meeting_id: this.meeting().uid,
                       first_name: m.first_name,
                       last_name: m.last_name,
                       email: m.email,
                       organization: m.organization?.name,
                       is_host: false,
                       type: 'committee',
                       invite_accepted: null,
                       attended: true,
                     }));
apps/lfx-pcc/src/server/services/meeting.service.ts (1)

213-216: Bug: wrong tag filter when fetching registrants (will return incorrect data).

Query service expects a key:value tag (e.g., meeting_uid:), not a bare UID.

-          tags: meetingUid,
+          tags: `meeting_uid:${meetingUid}`,
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.ts (1)

501-519: Editing flow misses populating platform (silent data drift on update).

populateFormWithMeetingData doesn’t patch platform, so editing a meeting can unintentionally reset the platform to the default. Patch the form with meeting.platform.

Outside selected lines; add:

// inside populateFormWithMeetingData patchValue(...)
platform: (meeting as any).platform || DEFAULT_MEETING_TOOL,
🧹 Nitpick comments (23)
.vscode/settings.json (1)

30-30: Prefer consistent acronym casing in cSpell entries.

Consider "UID" and "UIDs" (or lowercased "uid", "uids") instead of "Uids" to match common usage across the codebase and avoid adding multiple variants later.

apps/lfx-pcc/src/app/shared/services/meeting.service.ts (1)

42-42: Good tag filter fix; add ordering and date filters for correctness.

  • Upcoming/past queries currently lack ordering/temporal filters; results may not reflect “next”/“recent past.”
  • At minimum, sort upcoming by start_time.asc and past by start_time.desc. Add server-side date filters when available.

Apply this minimal ordering tweak:

   public getUpcomingMeetingsByProject(projectId: string, limit: number = 3): Observable<Meeting[]> {
-    let params = new HttpParams().set('tags', `project_uid:${projectId}`);
+    let params = new HttpParams().set('tags', `project_uid:${projectId}`).set('order', 'start_time.asc');
 
     // TODO: Add filter for upcoming meetings
     if (limit) {
       params = params.set('limit', limit.toString());
     }
 
     return this.getMeetings(params);
   }
 
   public getPastMeetingsByProject(projectId: string, limit: number = 3): Observable<Meeting[]> {
-    let params = new HttpParams().set('tags', `project_uid:${projectId}`);
+    let params = new HttpParams().set('tags', `project_uid:${projectId}`).set('order', 'start_time.desc');
 
     // TODO: Add filter for past meetings
     if (limit) {
       params = params.set('limit', limit.toString());
     }
 
     return this.getMeetings(params);
   }

Also confirm the tags format project_uid:${projectId} matches the API contract.

Also applies to: 60-63, 71-74

apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.ts (1)

56-86: Ensure the “next upcoming” meeting is actually the earliest future one.

When no committeeId is provided, the code takes the first future meeting without sorting. Sort by start_time ascending before selecting the first.

Apply:

-          // Return the next upcoming meeting by date in the future
-          return meetings.filter((meeting) => new Date(meeting.start_time).getTime() > new Date().getTime())[0];
+          // Return the next upcoming meeting by earliest future start time
+          const now = Date.now();
+          return (
+            meetings
+              .filter((m) => new Date(m.start_time).getTime() > now)
+              .sort((a, b) => new Date(a.start_time).getTime() - new Date(b.start_time).getTime())[0] ?? null
+          );
apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.html (1)

21-26: Add a test hook for committee info (optional).

For e2e stability, consider a data-testid on the committee display container.

Example:

-      <div class="text-xs text-gray-500">
+      <div class="text-xs text-gray-500" data-testid="upcoming-committee-committee-info">
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts (2)

142-146: Replace non-null assertions with optional chaining and avoid recomputation.

Safer and clearer to compute once and reuse the boolean.

-const header = this.meeting().committees && this.meeting().committees!.length > 0 ? 'Manage Committees' : 'Connect Committees';
+const hasCommittees = (this.meeting().committees?.length ?? 0) > 0;
+const header = hasCommittees ? 'Manage Committees' : 'Connect Committees';

323-326: Deduplicate the “Manage/Connect Committees” label logic.

Use optional chaining; consider extracting a tiny helper (hasCommittees or committeeActionLabel) to keep TS/HTML consistent.

- label: this.meeting().committees && this.meeting().committees!.length > 0 ? 'Manage Committees' : 'Connect Committees',
+ label: (this.meeting().committees?.length ?? 0) > 0 ? 'Manage Committees' : 'Connect Committees',

Optionally:

private hasCommittees(): boolean {
  return (this.meeting().committees?.length ?? 0) > 0;
}
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.html (1)

256-263: Use optional chaining instead of non-null assertions; add a test id hook.

Prevents potential runtime null issues and improves test targeting.

-@if (meeting().committees && meeting().committees!.length > 0) {
-  <div class="flex items-start gap-2 mb-4">
+@if (meeting().committees?.length > 0) {
+  <div class="flex items-start gap-2 mb-4" data-testid="meeting-committees">
     <i class="fa-light fa-people-group text-green-500 mt-0.5"></i>
     <div class="flex flex-wrap gap-1">
       <div class="text-sm text-gray-600">
-        @for (committee of meeting().committees!; track committee.uid; let isLast = $last) {
+        @for (committee of meeting().committees; track committee.uid; let isLast = $last) {
           <a [routerLink]="['/project', project()?.slug, 'committees', committee.uid]" class="text-primary hover:text-primary-600">
             {{ committee.name }}
           </a>
apps/lfx-pcc/src/server/controllers/meeting.controller.ts (1)

45-47: Nit: redundant nullish coalescing on .length.

length is always a number. Remove ?? 0.

apps/lfx-pcc/src/server/services/meeting.service.ts (2)

49-55: Committee enrichment is fine; avoid logging full meeting payloads at debug in prod.

Consider logging counts/ids only to reduce log volume/PII surface.


90-98: Simplify single-meeting handling; avoid array juggling.

Reduces cognitive load and minor allocations.

-    let meeting = resources.map((resource) => resource.data);
-
-    if (meeting[0].committees && meeting[0].committees.length > 0) {
-      meeting = await this.getMeetingCommittees(req, meeting);
-    }
-
-    return await this.accessCheckService.addAccessToResource(req, meeting[0], 'meeting', 'organizer');
+    let m = resources[0].data;
+    if (m.committees?.length) {
+      [m] = await this.getMeetingCommittees(req, [m]);
+    }
+    return await this.accessCheckService.addAccessToResource(req, m, 'meeting', 'organizer');
apps/lfx-pcc/src/app/modules/project/meetings/meeting-dashboard/meeting-dashboard.component.ts (3)

209-211: Committee options: guard missing names.

Some committees may lack names; consider a safer label.

- committeeMap.set(committee.uid, committee.name || '');
+ committeeMap.set(committee.uid, committee.name?.trim() || 'Unknown Committee');

321-323: Calendar title shows only first committee.

Optional: include multiple committees for clarity when applicable.

- const committeeName = meeting.committees?.[0]?.name;
- const displayTitle = committeeName ? `${meeting.title || 'Meeting'} (${committeeName})` : meeting.title || 'Meeting';
+ const committeeNames = (meeting.committees || []).map(c => c.name).filter(Boolean);
+ const suffix = committeeNames.length ? ` (${committeeNames.slice(0,2).join(', ')}${committeeNames.length>2?'…':''})` : '';
+ const displayTitle = `${meeting.title || 'Meeting'}${suffix}`;

336-337: extendedProps: expose all committees (optional).

If consumers need more than the first committee, add an array.

- committee: meeting.committees?.[0]?.name,
+ committee: meeting.committees?.[0]?.name,
+ committees: (meeting.committees || []).map(c => c.name).filter(Boolean),
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.html (2)

33-41: Prefer LFX tooltip wrapper over PrimeNG Tooltip.

Project guideline: use LFX wrappers instead of PrimeNG directly. Replace pTooltip with the LFX equivalent, or confirm no wrapper exists.


44-56: data-testid naming: align with convention.

Use [section]-[component]-[element]. Current id omits component name.

- data-testid="meeting-voting-status-multi-select"
+ data-testid="meeting-committee-modal-voting-status-multi-select"
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts (5)

11-11: Avoid barrel for constants if discouraged; keep consistent with repo.

If barrels are discouraged here, import VOTING_STATUSES from its constants file; otherwise keep as-is for consistency.

- import { VOTING_STATUSES } from '@lfx-pcc/shared';
+ import { VOTING_STATUSES } from '@lfx-pcc/shared/constants/committees.constants';

52-53: Type the signal to avoid any[].

Minor typing improvement.

- public filteredCommitteeMembers: Signal<CommitteeMemberDisplay[]> = signal([]);
+ public filteredCommitteeMembers: Signal<CommitteeMemberDisplay[]> = signal<CommitteeMemberDisplay[]>([]);

112-128: Initial voting-status seeding from meeting.

Deduping via Set is good; consider only seeding when any selected committee has voting enabled.


180-184: allowedVotingStatuses computed once for all committees.

Reasonable simplification; backend should accept empty array when voting disabled.


251-253: Re-initializing filtered signal inside load path.

Initialize the computed once; let it react to dependencies instead of reassigning in tap.

- tap(() => {
-   this.filteredCommitteeMembers = this.initializeFilteredCommitteeMembers();
- }),
+ tap(() => void 0),

Then in constructor (outside selected lines), add:

this.filteredCommitteeMembers = this.initializeFilteredCommitteeMembers();
packages/shared/src/interfaces/meeting.interface.ts (3)

66-73: Type-safe voting statuses and clarify response-only name

  • Consider a shared enum (e.g., CommitteeVotingStatus) instead of string[] for allowed_voting_statuses to enforce valid values across UI/server.
  • Clarify name as response-only to avoid clients posting it.

Apply this doc tweak while you wire in the enum:

   /** Allowed voting statuses for committee members */
-  allowed_voting_statuses?: string[];
+  allowed_voting_statuses?: string[]; // TODO: restrict to shared enum (CommitteeVotingStatus)

-  /** Committee name */
-  name?: string;
+  /** Committee name (response-only; server enriches) */
+  name?: string;

I can help add the enum to packages/shared/src/enums. Want me to open a patch for that?


127-127: Avoid optional + nullable on zoom_config in the response shape

Prefer a stable key with null when absent: zoom_config: ZoomConfig | null. This simplifies consumers vs handling undefined | null.

-  zoom_config?: ZoomConfig | null;
+  zoom_config: ZoomConfig | null;

156-157: Input type uses consolidated committee shape—document ignored fields

If the backend ignores name on input, note it explicitly to prevent clients from attempting to set it.

-  committees?: MeetingCommittee[]; // Associated committees with voting statuses
+  committees?: MeetingCommittee[]; // Associated committees (uid + allowed_voting_statuses); name is ignored on input
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • 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 1a3772e and 20e6b82.

📒 Files selected for processing (17)
  • .vscode/settings.json (1 hunks)
  • apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.html (1 hunks)
  • apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.ts (1 hunks)
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.html (1 hunks)
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts (2 hunks)
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.html (4 hunks)
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts (7 hunks)
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.html (1 hunks)
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.ts (3 hunks)
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-platform-features/meeting-platform-features.component.html (1 hunks)
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-resources-summary/meeting-resources-summary.component.html (1 hunks)
  • apps/lfx-pcc/src/app/modules/project/meetings/meeting-dashboard/meeting-dashboard.component.ts (5 hunks)
  • apps/lfx-pcc/src/app/shared/services/meeting.service.ts (3 hunks)
  • apps/lfx-pcc/src/server/controllers/meeting.controller.ts (2 hunks)
  • apps/lfx-pcc/src/server/services/meeting.service.ts (6 hunks)
  • packages/shared/src/constants/meeting.constants.ts (1 hunks)
  • packages/shared/src/interfaces/meeting.interface.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
apps/lfx-pcc/src/**/*.{ts,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Use LFX wrapper components instead of importing PrimeNG components directly

Files:

  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-resources-summary/meeting-resources-summary.component.html
  • apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.html
  • apps/lfx-pcc/src/app/shared/services/meeting.service.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.html
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts
  • apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.ts
  • apps/lfx-pcc/src/server/controllers/meeting.controller.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.ts
  • apps/lfx-pcc/src/server/services/meeting.service.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.html
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-platform-features/meeting-platform-features.component.html
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/meeting-dashboard/meeting-dashboard.component.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.html
apps/lfx-pcc/src/**/*.html

📄 CodeRabbit inference engine (CLAUDE.md)

apps/lfx-pcc/src/**/*.html: Add data-testid attributes to new components for reliable test targeting
Follow data-testid naming convention: [section]-[component]-[element]

Files:

  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-resources-summary/meeting-resources-summary.component.html
  • apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.html
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.html
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.html
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-platform-features/meeting-platform-features.component.html
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.html
**/*.{ts,tsx,js,jsx,html,scss,css}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-resources-summary/meeting-resources-summary.component.html
  • apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.html
  • apps/lfx-pcc/src/app/shared/services/meeting.service.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.html
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts
  • packages/shared/src/constants/meeting.constants.ts
  • apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.ts
  • apps/lfx-pcc/src/server/controllers/meeting.controller.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.ts
  • apps/lfx-pcc/src/server/services/meeting.service.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.html
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-platform-features/meeting-platform-features.component.html
  • packages/shared/src/interfaces/meeting.interface.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/meeting-dashboard/meeting-dashboard.component.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.html
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer TypeScript interfaces over union types when modeling shapes and contracts

Files:

  • apps/lfx-pcc/src/app/shared/services/meeting.service.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts
  • packages/shared/src/constants/meeting.constants.ts
  • apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.ts
  • apps/lfx-pcc/src/server/controllers/meeting.controller.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.ts
  • apps/lfx-pcc/src/server/services/meeting.service.ts
  • packages/shared/src/interfaces/meeting.interface.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/meeting-dashboard/meeting-dashboard.component.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • apps/lfx-pcc/src/app/shared/services/meeting.service.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts
  • packages/shared/src/constants/meeting.constants.ts
  • apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.ts
  • apps/lfx-pcc/src/server/controllers/meeting.controller.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.ts
  • apps/lfx-pcc/src/server/services/meeting.service.ts
  • packages/shared/src/interfaces/meeting.interface.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/meeting-dashboard/meeting-dashboard.component.ts
apps/lfx-pcc/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

apps/lfx-pcc/src/**/*.ts: In the Angular app, use direct imports for standalone components (no barrel imports)
When defining types for PrimeNG usage, reference PrimeNG’s component interfaces

Files:

  • apps/lfx-pcc/src/app/shared/services/meeting.service.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-card/meeting-card.component.ts
  • apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.ts
  • apps/lfx-pcc/src/server/controllers/meeting.controller.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.ts
  • apps/lfx-pcc/src/server/services/meeting.service.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts
  • apps/lfx-pcc/src/app/modules/project/meetings/meeting-dashboard/meeting-dashboard.component.ts
packages/shared/src/constants/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all reusable constants (design tokens, etc.) in the shared package

Files:

  • packages/shared/src/constants/meeting.constants.ts
packages/shared/src/interfaces/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all shared interfaces in the shared package

Files:

  • packages/shared/src/interfaces/meeting.interface.ts
🧠 Learnings (1)
📚 Learning: 2025-09-05T18:09:48.792Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-05T18:09:48.792Z
Learning: Applies to apps/lfx-pcc/src/**/*.{ts,html} : Use LFX wrapper components instead of importing PrimeNG components directly

Applied to files:

  • apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts
🧬 Code graph analysis (4)
apps/lfx-pcc/src/server/controllers/meeting.controller.ts (1)
apps/lfx-pcc/src/server/helpers/logger.ts (2)
  • error (52-65)
  • Logger (10-129)
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.ts (1)
packages/shared/src/constants/meeting.constants.ts (1)
  • DEFAULT_MEETING_TOOL (160-160)
apps/lfx-pcc/src/server/services/meeting.service.ts (3)
apps/lfx-pcc/src/server/services/committee.service.ts (1)
  • CommitteeService (24-351)
apps/lfx-pcc/src/server/services/access-check.service.ts (1)
  • AccessCheckService (13-189)
packages/shared/src/interfaces/meeting.interface.ts (1)
  • Meeting (75-142)
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts (1)
packages/shared/src/constants/committees.constants.ts (1)
  • VOTING_STATUSES (66-72)
⏰ 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: E2E Tests / Playwright E2E Tests
🔇 Additional comments (24)
apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-resources-summary/meeting-resources-summary.component.html (1)

191-191: Verify platform value vs. display label.

Now that the form binds to platform, ensure the value stored/sent matches backend expectations (slug vs. label). If the API expects slugs, map to labels only for display here.

apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-platform-features/meeting-platform-features.component.html (1)

17-17: LGTM: control rename to platform is consistent.

Binding and validation updated correctly.

Also applies to: 25-26

apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.html (1)

121-121: LGTM: tab value corrected.

Fix aligns tabpanel with tablist index; resolves mis-selection in edit mode.

apps/lfx-pcc/src/app/modules/project/committees/components/upcoming-committee-meeting/upcoming-committee-meeting.component.html (1)

21-26: LGTM: committees migration reflected in template.

Bindings and tooltip updated correctly to committees.

apps/lfx-pcc/src/server/services/meeting.service.ts (2)

19-20: Good: CommitteeService integration is localized and constructor-initialized.

Also applies to: 30-36


67-68: Good: switch to tag-based lookup for meeting by UID.

apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-manage/meeting-manage.component.ts (3)

303-304: Platform mapped correctly in payload.

Looks good switching to platform with DEFAULT_MEETING_TOOL fallback.


563-564: Step 3 validation updated to platform.

LGTM; validation now targets the correct control.


598-604: Form control renamed to platform with required validator.

Good alignment with payload and validation.

apps/lfx-pcc/src/app/modules/project/meetings/meeting-dashboard/meeting-dashboard.component.ts (2)

238-239: Search includes committee names.

Good null-safe match on committee.name.


251-252: Committee filter updated to committees[].uid.

Correct filter against new shape.

apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.html (5)

29-31: Helpful guidance text.

Clear instruction for users.


59-66: Concise selection summary.

Nice UX; reflects filtered count.


87-92: Table bound to filteredCommitteeMembers.

Correctly ties visibility to filtered set.


142-145: Voting status cell is robust.

Titlecase and fallback to “-” are fine.


165-174: Empty-state and counts match filtering.

Good conditional messaging for voting-status filters.

Also applies to: 168-184

apps/lfx-pcc/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts (4)

101-106: Form control for votingStatuses added.

LGTM; default empty array is correct.


141-148: Auto-clear statuses when no voting-enabled committees are selected.

Good UX guard.


187-192: Update payload structure matches new API shape.

LGTM.


304-320: Filtering logic by selected voting statuses.

Implementation is clean and reactive.

packages/shared/src/interfaces/meeting.interface.ts (4)

180-180: Allowing recurrence to be null in Update = good for clearing schedule

This enables explicit removal of recurrence. LGTM.


125-125: Audit consumer UI/forms for null-safe password handling
No direct .trim() or other string operations on password were found in the shared package; manually verify that all UI/form components consuming this interface (e.g. in webapp packages) guard against null before invoking string methods.


105-106: Initialize committees to an empty array for all meetings
In meeting.service.ts getMeetingCommittees, before returning, add:

meetings.forEach(m => { m.committees = m.committees ?? []; });

to guarantee Meeting.committees is never null/undefined.


182-188: Retain | null for UpdateMeetingRequest flags
Null distinguishes an explicit “clear” from omitting a field—removing it breaks the intended update semantics.

Likely an incorrect or invalid review comment.

- Add writer permission override option to ApiMockHelper.setupProjectSlugMock()
- Add comprehensive tests for users without write permissions
- Add writer property to mock project data for permission testing
- Restructure tests with permission-based describe blocks
- Fix GitHub Actions e2e workflow to use exit codes instead of .last-run.json
- Test Quick Actions menu visibility based on permissions
- Test empty state buttons (Create Meeting, Add Committee) are hidden for read-only
- Test read-only users can still access all view-only functionality
- Test responsive design for read-only users

🤖 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: 1

Caution

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

⚠️ Outside diff range comments (1)
apps/lfx-pcc/e2e/project-dashboard.spec.ts (1)

1-3: Add missing structural E2E test file
The project-dashboard suite currently only has the content-based test (project-dashboard.spec.ts); add its structural counterpart (project-dashboard-robust.spec.ts) under apps/lfx-pcc/e2e to satisfy dual E2E guidelines.

🧹 Nitpick comments (15)
.github/workflows/e2e-tests.yml (4)

246-263: Capture the exit code into a variable before writing it (minor robustness).

Storing $? first avoids accidental changes if more commands get added between the test run and the output write.

-            yarn ${{ inputs.test-command }} --reporter=list
-            echo "test_exit_code=$?" >> $GITHUB_OUTPUT
+            yarn ${{ inputs.test-command }} --reporter=list
+            EXIT_CODE=$?
+            echo "test_exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT

265-283: Same nit: assign $? before echoing output.

Keeps behavior stable if the step grows.

-            yarn ${{ inputs.test-command }} --project=${{ inputs.browser }} --reporter=list
-            echo "test_exit_code=$?" >> $GITHUB_OUTPUT
+            yarn ${{ inputs.test-command }} --project=${{ inputs.browser }} --reporter=list
+            EXIT_CODE=$?
+            echo "test_exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT

299-329: Fix YAML lint errors and prefer numeric comparison for exit code.

  • Remove trailing whitespace flagged by yamllint (Lines 314 and 321).
  • Use -eq for numeric comparison.
-            ALL_EXIT_CODE="${{ steps.run-tests-all.outputs.test_exit_code }}"
-            SPECIFIC_EXIT_CODE="${{ steps.run-tests-specific.outputs.test_exit_code }}"
-            
+            ALL_EXIT_CODE="${{ steps.run-tests-all.outputs.test_exit_code }}"
+            SPECIFIC_EXIT_CODE="${{ steps.run-tests-specific.outputs.test_exit_code }}"
+
             # Determine which test was run and check its exit code
             if [ "${{ inputs.browser }}" == "all" ]; then
               EXIT_CODE="$ALL_EXIT_CODE"
             else
               EXIT_CODE="$SPECIFIC_EXIT_CODE"
             fi
-            
-            if [ "$EXIT_CODE" == "0" ]; then
+
+            if [ "$EXIT_CODE" -eq 0 ]; then
               echo "✅ E2E tests completed successfully"
               echo "results=success" >> $GITHUB_OUTPUT
             else
               echo "❌ E2E tests failed (exit code: $EXIT_CODE)"
               echo "results=failure" >> $GITHUB_OUTPUT
             fi

331-404: PR comment step won’t run in a reusable workflow triggered via workflow_call.

In called workflows, github.event_name is workflow_call, so this step won’t execute even when the caller is a pull_request workflow. Consider moving this step to the caller, or pass pr-number as an input and gate on that.

Happy to propose a caller-side snippet if you share the calling workflow.

apps/lfx-pcc/e2e/fixtures/mock-data/projects.mock.ts (1)

32-32: Avoid nondeterministic dates in E2E fixtures.

updated_at: new Date().toISOString() can introduce flaky tests if any assertions or snapshots include it. Prefer a fixed ISO string or a helper constant.

Apply this diff:

-    updated_at: new Date().toISOString(),
+    // Fixed timestamp to keep E2E deterministic
+    updated_at: '2025-01-01T00:00:00.000Z',

Also applies to: 59-59, 85-85

apps/lfx-pcc/e2e/helpers/api-mock.helper.ts (2)

30-33: More robust slug parsing (handles trailing slashes and query).

Using URL + pathname filtering avoids edge cases like trailing slash or extra segments.

Apply this diff:

-      const pathSegments = url.split('/');
-      const slug = pathSegments[pathSegments.length - 1].split('?')[0]; // Remove query params
+      const { pathname } = new URL(url);
+      // Split, drop empty segments (e.g., trailing slash), take last
+      const parts = pathname.split('/').filter(Boolean);
+      const slug = parts[parts.length - 1];

21-27: Tighten route matcher; remove manual excludes.

Match only direct /api/projects/:slug to eliminate the need for skip checks.

Apply this diff:

-    await page.route('**/api/projects/*', async (route) => {
-      const url = route.request().url();
-
-      // Skip other endpoints - only handle direct slug requests
-      if (url.includes('/search') || url.includes('/recent-activity')) {
-        await route.continue();
-        return;
-      }
+    await page.route(/\/api\/projects\/[^/]+(\?.*)?$/i, async (route) => {
+      const url = route.request().url();
apps/lfx-pcc/e2e/project-dashboard.spec.ts (8)

8-30: Type page parameter; avoid any.

Use Playwright’s Page type for navigateToDashboard.

Apply this diff:

-import { expect, test } from '@playwright/test';
+import { expect, test } from '@playwright/test';
+import type { Page } from '@playwright/test';
@@
-async function navigateToDashboard(page: any) {
+async function navigateToDashboard(page: Page) {

41-45: Relax page title assertion to reduce brittleness.

Titles often change subtly; use a case-insensitive regex.

Apply this diff:

-        await expect(page).toHaveTitle('LFX Projects');
+        await expect(page).toHaveTitle(/lfx projects/i);

75-79: Prefer ARIA state over CSS class for active tab.

Class names are volatile; aria-current is more stable.

Apply this diff:

-        const dashboardTab = page.getByRole('link', { name: 'Dashboard' });
-        await expect(dashboardTab).toHaveClass(/bg-blue-50/);
+        const dashboardTab = page.getByRole('link', { name: 'Dashboard' });
+        await expect(dashboardTab).toHaveAttribute('aria-current', /page|true/);

95-99: Target project logo more robustly.

img().first() is brittle; prefer alt text or data-testid on the project logo.

Apply this diff (if alt text is available):

-        const projectImage = page.locator('img').first();
+        const projectImage = page.getByAltText(/academy software foundation|aswf/i);

If alt text isn’t available, consider adding data-testid="project-logo" to the component and assert on that.


237-242: Future-proof footer year assertion.

Hard-coding 2025 will break next year. Use a year-agnostic regex.

Apply this diff:

-        await expect(page.getByText(/Copyright © 2025 The Linux Foundation/)).toBeVisible();
+        await expect(page.getByText(/Copyright © \d{4} The Linux Foundation/)).toBeVisible();

Also applies to: 245-258


345-351: Assert absence strictly.

not.toBeVisible can pass with zero matches; assert count for stricter guarantees.

Apply this diff:

-      await expect(page.getByRole('menuitem', { name: 'Create Meeting' })).not.toBeVisible();
-      await expect(page.getByRole('menuitem', { name: 'Create Committee' })).not.toBeVisible();
+      await expect(page.getByRole('menuitem', { name: 'Create Meeting' })).toHaveCount(0);
+      await expect(page.getByRole('menuitem', { name: 'Create Committee' })).toHaveCount(0);

433-459: Avoid re-registering the same route.

setupProjectSlugMock is already called in beforeEach for this describe; calling it again can stack handlers. Remove the extra call.

Apply this diff:

-      await ApiMockHelper.setupProjectSlugMock(page, { writer: false });

282-332: DRY navigation in responsive tests.

Reuse navigateToDashboard after setting viewport to reduce duplication and keep flows consistent.

Example:

-        // Navigate to homepage and search for a project after viewport change
-        await page.goto('/');
-        await expect(page.getByRole('textbox', { name: 'Search projects, committees, meetings, or mailing lists...' })).toBeVisible({ timeout: 10000 });
-        await page.getByRole('textbox', { name: 'Search projects, committees, meetings, or mailing lists...' }).fill('aswf');
-        await page.keyboard.press('Enter');
-        await expect(page.locator('lfx-project-card').first()).toBeVisible({ timeout: 10000 });
-        await page.locator('lfx-project-card').filter({ hasText: 'Academy Software Foundation' }).click();
-        await expect(page).toHaveURL(/\/project\/[\w-]+$/, { timeout: 10000 });
-        await expect(page.getByRole('link', { name: 'Dashboard' })).toBeVisible();
-        await page.getByRole('link', { name: 'Dashboard' }).click();
+        await navigateToDashboard(page);

Note: If header search is hidden on mobile but a hero search remains, navigateToDashboard should still work. If not, consider parameterizing the helper for mobile vs desktop search boxes.

Also applies to: 433-459

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • 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 20e6b82 and ed46526.

📒 Files selected for processing (4)
  • .github/workflows/e2e-tests.yml (2 hunks)
  • apps/lfx-pcc/e2e/fixtures/mock-data/projects.mock.ts (3 hunks)
  • apps/lfx-pcc/e2e/helpers/api-mock.helper.ts (2 hunks)
  • apps/lfx-pcc/e2e/project-dashboard.spec.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer TypeScript interfaces over union types when modeling shapes and contracts

Files:

  • apps/lfx-pcc/e2e/fixtures/mock-data/projects.mock.ts
  • apps/lfx-pcc/e2e/helpers/api-mock.helper.ts
  • apps/lfx-pcc/e2e/project-dashboard.spec.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • apps/lfx-pcc/e2e/fixtures/mock-data/projects.mock.ts
  • apps/lfx-pcc/e2e/helpers/api-mock.helper.ts
  • apps/lfx-pcc/e2e/project-dashboard.spec.ts
**/*.{ts,tsx,js,jsx,html,scss,css}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • apps/lfx-pcc/e2e/fixtures/mock-data/projects.mock.ts
  • apps/lfx-pcc/e2e/helpers/api-mock.helper.ts
  • apps/lfx-pcc/e2e/project-dashboard.spec.ts
**/{*.spec.ts,*-robust.spec.ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Maintain dual E2E test architecture: content-based (.spec.ts) and structural (-robust.spec.ts) tests

Files:

  • apps/lfx-pcc/e2e/project-dashboard.spec.ts
🧠 Learnings (3)
📚 Learning: 2025-09-05T18:09:48.792Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-05T18:09:48.792Z
Learning: Applies to **/{*.spec.ts,*-robust.spec.ts} : Maintain dual E2E test architecture: content-based (*.spec.ts) and structural (*-robust.spec.ts) tests

Applied to files:

  • apps/lfx-pcc/e2e/project-dashboard.spec.ts
  • .github/workflows/e2e-tests.yml
📚 Learning: 2025-09-05T18:09:48.791Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-05T18:09:48.791Z
Learning: Test responsive behavior across mobile, tablet, and desktop viewports

Applied to files:

  • apps/lfx-pcc/e2e/project-dashboard.spec.ts
📚 Learning: 2025-09-05T18:09:48.791Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-05T18:09:48.791Z
Learning: Always run yarn e2e before major changes to ensure the full suite passes

Applied to files:

  • .github/workflows/e2e-tests.yml
🧬 Code graph analysis (1)
apps/lfx-pcc/e2e/project-dashboard.spec.ts (1)
apps/lfx-pcc/e2e/helpers/api-mock.helper.ts (1)
  • ApiMockHelper (12-62)
🪛 YAMLlint (1.37.1)
.github/workflows/e2e-tests.yml

[error] 314-314: trailing spaces

(trailing-spaces)


[error] 321-321: trailing spaces

(trailing-spaces)

⏰ 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: E2E Tests / Playwright E2E Tests
🔇 Additional comments (2)
apps/lfx-pcc/e2e/fixtures/mock-data/projects.mock.ts (1)

36-36: Writer flag in mocks — looks good.

The added writer property aligns with the permission-driven tests and the new mock override. No issues found.

Also applies to: 63-63, 89-89

apps/lfx-pcc/e2e/helpers/api-mock.helper.ts (1)

19-19: Options-based writer override is clean and contained.

Signature + override logic are straightforward and safe; response body uses the merged object as expected.

Also applies to: 49-54, 58-58

- Add composite action .github/actions/setup-playwright/action.yml
- Cache browser binaries based on OS and Playwright version
- Install browsers only on cache miss, OS deps only on cache hit
- Support selective browser installation (all, chromium, firefox, mobile-chrome)
- Update e2e-tests.yml workflow to use new composite action
- Reduce CI/CD pipeline time by avoiding redundant browser downloads

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 (5)
.github/actions/setup-playwright/action.yml (5)

14-14: Comment is misleading.

The step doesn’t run “npm ci”. Trim the comment to avoid confusion.

Apply:

-    # Run npm ci and get Playwright version
+    # Get Playwright version

26-30: Cache path isn’t Windows-safe.

The Playwright cache lives at ~/.cache/ms-playwright on Linux/macOS but at %LOCALAPPDATA%\ms-playwright on Windows. Use an OS-aware path to actually cache on Windows runners.

Apply:

-        path: "~/.cache/ms-playwright"
+        path: ${{ runner.os == 'Windows' && format('{0}\\ms-playwright', env.LOCALAPPDATA) || format('{0}/.cache/ms-playwright', env.HOME) }}

31-41: Harden shell execution.

Add strict mode to fail fast on errors.

Apply:

       run: |
+        set -euo pipefail
         if [ "${{ inputs.browser }}" == "all" ]; then
           npm exec -- playwright install --with-deps
         else
           npm exec -- playwright install --with-deps ${{ inputs.browser }}
         fi

42-51: Skip install-deps on Windows; add strict mode.

playwright install-deps isn’t supported on Windows and produces noise. Gate by OS and harden the script.

Apply:

-    - name: 🏗 Install Playwright OS dependencies
-      if: steps.playwright-cache.outputs.cache-hit == 'true'
+    - name: 🏗 Install Playwright OS dependencies
+      if: runner.os != 'Windows' && steps.playwright-cache.outputs.cache-hit == 'true'
       shell: bash
       run: |
+        set -euo pipefail
         if [ "${{ inputs.browser }}" == "all" ]; then
           npm exec -- playwright install-deps
         else
           npm exec -- playwright install-deps ${{ inputs.browser }}
         fi

51-51: Add a trailing newline.

Satisfies linters and POSIX conventions.

-        fi
+        fi
+
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • 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 ed46526 and 691d15d.

📒 Files selected for processing (2)
  • .github/actions/setup-playwright/action.yml (1 hunks)
  • .github/workflows/e2e-tests.yml (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/e2e-tests.yml
🧰 Additional context used
🪛 YAMLlint (1.37.1)
.github/actions/setup-playwright/action.yml

[error] 51-51: no new line character at the end of file

(new-line-at-end-of-file)

⏰ 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: E2E Tests / Playwright E2E Tests

@asithade asithade merged commit d0cfacc into main Sep 9, 2025
8 checks passed
@asithade asithade deleted the fix/LFXV2-448 branch September 9, 2025 17:40
@github-actions
Copy link

github-actions bot commented Sep 9, 2025

🧹 Deployment Removed

The deployment for PR #74 has been removed.

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