Skip to content

Commit 5bb417e

Browse files
jordaneclaudeasithade
authored andcommitted
feat(dashboard): initial core persona developer dashboard implementation (#119)
* wip(dashboard): initial core persona developer dashboard implementation Work in progress implementation for LFXV2-644. Adding foundational components and structure for the Core Developer Persona dashboard. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> Signed-off-by: Jordan Evans <[email protected]> * feat(dashboard): improve core developer persona dashboard UI Reduce section header sizes from text-xl to text-lg for better visual hierarchy. Enhance meetings section with modern card design, calendar icons, participant badges, and Join buttons. Fix ESLint member ordering issues for LFXV2-644. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> Signed-off-by: Jordan Evans <[email protected]> * fix(layout): prevent sidebar from floating during horizontal scroll Change sidebar from fixed to sticky positioning within a flex container. This ensures the sidebar stays in its designated column and doesn't cover content during horizontal scrolling. Updates for LFXV2-644. - Wrap sidebar in flex-shrink-0 container with fixed width - Change sidebar positioning from fixed to sticky - Remove margin-left from main content, use min-w-0 for proper scrolling - Maintain sticky behavior for vertical scrolling within column 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> Signed-off-by: Jordan Evans <[email protected]> * style(dashboard): further reduce section header sizes Change section headers from text-lg to text-base for a more compact and modern dashboard appearance. Reduces visual hierarchy emphasis on section titles in favor of content focus for LFXV2-644. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> Signed-off-by: Jordan Evans <[email protected]> * feat(dashboard): integrate meetings API with occurrence-based filtering Replace hardcoded meeting data with live API integration that properly handles: - Meeting occurrences for recurring meetings - Time-based filtering with 40-minute buffer after meeting end - Sorting by earliest time first - Frontend limit to 5 meetings maximum - Smart time formatting (Today/Tomorrow/Date) - Total attendee count from registrants and committee members 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * feat(dashboard): implement persona-based dashboard architecture - Replace home-new component with modular dashboard architecture - Add persona-specific dashboard components (my-meetings, my-projects, pending-actions, recent-progress) - Implement persona service with reactive persona selection - Update sidebar with footer navigation support and improved styling - Match sidebar border/shadow styling with PrimeNG card components - Add persona selector component with dropdown interface - Update header to integrate persona selector - Add persona constants to shared package - Update main layout to support dynamic persona-based routing - Update profile layout to handle persona changes - Server-side: Fix user profile persona field mapping Technical improvements: - Sidebar: Remove border, update border-radius to 12px, match card shadow - Sidebar: Add footer items support with separate navigation section - Sidebar: Improve accessibility with consistent text sizing (text-sm) - Remove icon hover animations for visual consistency LFXV2-644 Signed-off-by: Asitha de Silva <[email protected]> * refactor(sidebar): replace function calls with computed signals - Remove getTestId() function calls from template - Add testId property to SidebarMenuItem interface - Create computed signals (itemsWithTestIds, footerItemsWithTestIds) for test ID generation - Use Angular signals pattern for better performance and change detection Performance improvements: - Computed signals only recalculate when input changes - Eliminates repeated function calls during template rendering - Leverages Angular 19 zoneless change detection optimization LFXV2-644 Signed-off-by: Asitha de Silva <[email protected]> * fix(dashboard): resolve pr comments Signed-off-by: Asitha de Silva <[email protected]> * fix(yarn): yarn.lock update Signed-off-by: Asitha de Silva <[email protected]> * feat(dashboard): implement dashboard meeting card component - Create reusable DashboardMeetingCardComponent for displaying meeting information - Update MyMeetingsComponent to use new card component with Today/Upcoming sections - Add conditional section rendering (hide sections when empty) - Match React component styling with white card background, gray icons, rounded-xl borders - Implement smart date filtering for today's meetings vs upcoming meetings - Add meeting feature icons (YouTube, Recording, Transcripts, AI, Public/Private) - Add DashboardMeetingCardProps and DashboardMeetingFeatures interfaces to shared package - Update RecentProgressComponent styling to match React design - Remove PrimeNG Card dependency in favor of semantic HTML with Tailwind LFXV2-644 Signed-off-by: Asitha de Silva <[email protected]> * refactor(dashboard): update pending actions and meeting card layout - Remove LFX card wrapper from pending actions component - Add consistent header with "View All" button to pending actions - Simplify pending action button styling to white background with slate-100 hover - Update dashboard meeting card to use project_name from meeting data - Add project_name enrichment in meeting service - Remove projectName input from dashboard meeting card component - Add project_name field to Meeting interface Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Asitha de Silva <[email protected]> * refactor(dashboard): update my-projects with table layout - Replace card-based layout with lfx-table component - Implement 4-column table structure (Project, Affiliations, Code Activities, Non-Code Activities) - Apply React-style formatting: - Equal column widths (w-1/4 for each column) - Fixed chart container width (12.5rem) - Grey borders (border-gray-200) on table cells - Rounded table container with overflow handling - Blue project name links (#009aff) - Help icons for activity columns - Update chart colors: - Code Activities: #009AFF (blue) - Non-Code Activities: #10b981 (green) - Add generateLabels() helper method for dynamic chart labels - Remove unused CardComponent import - Maintain all existing test IDs for E2E compatibility Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> Signed-off-by: Asitha de Silva <[email protected]> * ci(gha): disable automatic quality check workflow Disabled automatic PR quality checks as project is moving away from old UI. Changed trigger from pull_request to workflow_dispatch for manual runs only. LFXV2-644 Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Asitha de Silva <[email protected]> --------- Signed-off-by: Jordan Evans <[email protected]> Signed-off-by: Asitha de Silva <[email protected]> Co-authored-by: Claude <[email protected]> Co-authored-by: Asitha de Silva <[email protected]>
1 parent d299020 commit 5bb417e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1833
-33
lines changed

.github/workflows/quality-check.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33

44
name: Quality Checks
55

6+
# DISABLED: Moving away from old UI - quality checks no longer needed
7+
# Changed to manual trigger only - will not run automatically on PRs
68
on:
7-
pull_request:
8-
branches: [main]
9-
types: [opened, synchronize, reopened]
9+
workflow_dispatch:
1010

1111
jobs:
1212
quality-checks:
@@ -23,8 +23,8 @@ jobs:
2323
- name: Setup Node.js
2424
uses: actions/setup-node@v4
2525
with:
26-
node-version: '22'
27-
cache: 'yarn'
26+
node-version: "22"
27+
cache: "yarn"
2828

2929
- name: Install dependencies
3030
run: yarn install --immutable
@@ -46,9 +46,9 @@ jobs:
4646
needs: quality-checks
4747
uses: ./.github/workflows/e2e-tests.yml
4848
with:
49-
node-version: '22'
50-
test-command: 'e2e'
51-
browser: 'chromium' # Use only Chromium for PR testing for faster feedback
49+
node-version: "22"
50+
test-command: "e2e"
51+
browser: "chromium" # Use only Chromium for PR testing for faster feedback
5252
skip-build: false
5353
secrets:
5454
TEST_USERNAME: ${{ secrets.TEST_USERNAME }}

apps/lfx-one/src/app/app.routes.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,24 @@ import { authGuard } from './shared/guards/auth.guard';
88
export const routes: Routes = [
99
{
1010
path: '',
11-
loadComponent: () => import('./modules/pages/home/home.component').then((m) => m.HomeComponent),
1211
canActivate: [authGuard],
12+
loadComponent: () => import('./layouts/main-layout/main-layout.component').then((m) => m.MainLayoutComponent),
13+
children: [
14+
{
15+
path: '',
16+
loadComponent: () => import('./modules/pages/dashboard/dashboard.component').then((m) => m.DashboardComponent),
17+
},
18+
{
19+
path: 'projects',
20+
loadComponent: () => import('./modules/pages/home/home.component').then((m) => m.HomeComponent),
21+
},
22+
],
23+
},
24+
// Old UI route - shows when "Old UI" persona is selected
25+
{
26+
path: 'old-ui',
27+
canActivate: [authGuard],
28+
loadComponent: () => import('./modules/pages/home/home.component').then((m) => m.HomeComponent),
1329
},
1430
{
1531
path: 'meetings',
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!-- Copyright The Linux Foundation and each contributor to LFX. -->
2+
<!-- SPDX-License-Identifier: MIT -->
3+
4+
<div class="flex min-h-screen pt-4">
5+
<!-- Sidebar - Desktop -->
6+
<div class="hidden lg:block w-72 flex-shrink-0 fixed top-[6rem] left-0">
7+
<lfx-sidebar [items]="sidebarItems" [footerItems]="sidebarFooterItems"></lfx-sidebar>
8+
</div>
9+
10+
<!-- Sidebar - Mobile Overlay -->
11+
@if (showMobileSidebar()) {
12+
<div class="lg:hidden fixed inset-0 z-40 bg-black bg-opacity-50" data-testid="mobile-sidebar-overlay" (click)="closeMobileSidebar()">
13+
<div class="absolute top-0 left-0 bottom-0 w-72 bg-white shadow-xl" (click)="$event.stopPropagation()" data-testid="mobile-sidebar">
14+
<div class="flex items-center justify-between p-4 border-b border-gray-200">
15+
<h2 class="text-lg font-semibold text-gray-900">Menu</h2>
16+
<button
17+
type="button"
18+
class="hover:opacity-80 transition-opacity p-2"
19+
(click)="closeMobileSidebar()"
20+
aria-label="Close menu"
21+
data-testid="mobile-sidebar-close">
22+
<i class="fa-light fa-times text-gray-600 text-xl"></i>
23+
</button>
24+
</div>
25+
<div class="overflow-y-auto h-[calc(100vh-4rem)]">
26+
<lfx-sidebar [items]="sidebarItems" [footerItems]="sidebarFooterItems"></lfx-sidebar>
27+
</div>
28+
</div>
29+
</div>
30+
}
31+
32+
<!-- Main Content Area -->
33+
<main class="flex-1 min-w-0 transition-all duration-300 lg:ml-72" data-testid="main-content">
34+
<router-outlet />
35+
</main>
36+
</div>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright The Linux Foundation and each contributor to LFX.
2+
// SPDX-License-Identifier: MIT
3+
4+
:host {
5+
display: block;
6+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright The Linux Foundation and each contributor to LFX.
2+
// SPDX-License-Identifier: MIT
3+
4+
import { CommonModule } from '@angular/common';
5+
import { Component, inject } from '@angular/core';
6+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
7+
import { NavigationEnd, Router, RouterModule } from '@angular/router';
8+
import { AppService } from '@app/shared/services/app.service';
9+
import { SidebarComponent } from '@components/sidebar/sidebar.component';
10+
import { SidebarMenuItem } from '@lfx-one/shared/interfaces';
11+
import { filter } from 'rxjs';
12+
13+
@Component({
14+
selector: 'lfx-main-layout',
15+
standalone: true,
16+
imports: [CommonModule, RouterModule, SidebarComponent],
17+
templateUrl: './main-layout.component.html',
18+
styleUrl: './main-layout.component.scss',
19+
})
20+
export class MainLayoutComponent {
21+
private readonly router = inject(Router);
22+
private readonly appService = inject(AppService);
23+
24+
// Expose mobile sidebar state from service
25+
protected readonly showMobileSidebar = this.appService.showMobileSidebar;
26+
27+
// Sidebar navigation items
28+
protected readonly sidebarItems: SidebarMenuItem[] = [
29+
{
30+
label: 'Home',
31+
icon: 'fa-light fa-house',
32+
routerLink: '/',
33+
},
34+
{
35+
label: 'My Meetings',
36+
icon: 'fa-light fa-video',
37+
routerLink: '/my-meetings',
38+
disabled: true,
39+
},
40+
{
41+
label: 'Project Health',
42+
icon: 'fa-light fa-heart-pulse',
43+
routerLink: '/project-health',
44+
disabled: true,
45+
},
46+
{
47+
label: 'Events & Community',
48+
icon: 'fa-light fa-calendar',
49+
routerLink: '/events-community',
50+
disabled: true,
51+
},
52+
{
53+
label: 'Training & Certification',
54+
icon: 'fa-light fa-book-open',
55+
routerLink: '/training-certification',
56+
disabled: true,
57+
},
58+
];
59+
60+
// Sidebar footer items
61+
protected readonly sidebarFooterItems: SidebarMenuItem[] = [
62+
{
63+
label: 'Documentation',
64+
icon: 'fa-light fa-file-lines',
65+
url: 'https://docs.lfx.linuxfoundation.org',
66+
},
67+
{
68+
label: 'Submit a Ticket',
69+
icon: 'fa-light fa-circle-question',
70+
url: 'https://jira.linuxfoundation.org/plugins/servlet/theme/portal/4',
71+
},
72+
{
73+
label: 'Changelog',
74+
icon: 'fa-light fa-rectangle-history',
75+
routerLink: '/changelog',
76+
disabled: true,
77+
},
78+
{
79+
label: 'Settings',
80+
icon: 'fa-light fa-gear',
81+
routerLink: '/settings',
82+
disabled: true,
83+
},
84+
{
85+
label: 'Profile',
86+
icon: 'fa-light fa-user',
87+
routerLink: '/profile',
88+
},
89+
];
90+
91+
public constructor() {
92+
// Close mobile sidebar on navigation
93+
this.router.events
94+
.pipe(
95+
filter((event) => event instanceof NavigationEnd),
96+
takeUntilDestroyed()
97+
)
98+
.subscribe(() => {
99+
this.appService.closeMobileSidebar();
100+
});
101+
}
102+
103+
public closeMobileSidebar(): void {
104+
this.appService.closeMobileSidebar();
105+
}
106+
}

apps/lfx-one/src/app/layouts/profile-layout/profile-layout.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export class ProfileLayoutComponent {
145145
const profile = this.profile();
146146
if (!profile?.profile) return '';
147147

148-
return profile.profile.job_title || '';
148+
return profile.profile.title || '';
149149
});
150150
}
151151

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<!-- Copyright The Linux Foundation and each contributor to LFX. -->
2+
<!-- SPDX-License-Identifier: MIT -->
3+
4+
<section class="flex flex-col flex-1" data-testid="dashboard-my-meetings-section">
5+
<!-- Header -->
6+
<div class="flex items-center justify-between mb-4">
7+
<h2 class="font-display font-semibold text-gray-900">My Meetings</h2>
8+
<lfx-button
9+
label="View All"
10+
icon="fa-light fa-chevron-right"
11+
iconPos="right"
12+
(onClick)="handleViewAll()"
13+
styleClass="!text-sm !font-normal"
14+
[text]="true"
15+
size="small"
16+
data-testid="dashboard-my-meetings-view-all" />
17+
</div>
18+
19+
<!-- Scrollable Content -->
20+
<div class="flex flex-col flex-1">
21+
<div class="flex flex-col gap-6" data-testid="dashboard-my-meetings-list">
22+
@if (todayMeetings().length > 0 || upcomingMeetings().length > 0) {
23+
<!-- TODAY Section - only show if there are meetings today -->
24+
@if (todayMeetings().length > 0) {
25+
<div>
26+
<h4 class="text-xs font-medium text-gray-500 mb-3 uppercase tracking-wide">Today</h4>
27+
<div class="flex flex-col gap-3">
28+
@for (item of todayMeetings(); track item.meeting.uid) {
29+
<lfx-dashboard-meeting-card
30+
[meeting]="item.meeting"
31+
[occurrence]="item.occurrence"
32+
(onSeeMeeting)="handleSeeMeeting($event)"
33+
[attr.data-testid]="'dashboard-my-meetings-today-item-' + item.meeting.uid" />
34+
}
35+
</div>
36+
</div>
37+
}
38+
39+
<!-- UPCOMING Section - only show if there are upcoming meetings -->
40+
@if (upcomingMeetings().length > 0) {
41+
<div>
42+
<h4 class="text-xs font-medium text-gray-500 mb-3 uppercase tracking-wide">Upcoming</h4>
43+
<div class="flex flex-col gap-3">
44+
@for (item of upcomingMeetings(); track item.meeting.uid) {
45+
<lfx-dashboard-meeting-card
46+
[meeting]="item.meeting"
47+
[occurrence]="item.occurrence"
48+
(onSeeMeeting)="handleSeeMeeting($event)"
49+
[attr.data-testid]="'dashboard-my-meetings-upcoming-item-' + item.meeting.uid" />
50+
}
51+
</div>
52+
</div>
53+
}
54+
} @else {
55+
<!-- Global empty state - only shows when no meetings at all -->
56+
<div class="text-xs text-gray-500 py-8 text-center border-2 border-dashed border-gray-300 rounded-lg" data-testid="dashboard-my-meetings-empty">
57+
No meetings scheduled
58+
</div>
59+
}
60+
</div>
61+
</div>
62+
</section>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Copyright The Linux Foundation and each contributor to LFX.
2+
// SPDX-License-Identifier: MIT

0 commit comments

Comments
 (0)