Skip to content

Commit 71f93b6

Browse files
authored
refactor(dashboards): add filters and carousel layout (#147)
* refactor(dashboards): add filters and carousel layout - Extract chart options to shared constants (SPARKLINE_CHART_OPTIONS, BAR_CHART_OPTIONS) - Refactor toSignal initializations to private initializer methods - Add filter pills component for metric categorization - Implement horizontal carousel with scroll controls - Display dynamic account name in section header - Remove unused getOrganizationSegmentOverview code across all layers - Remove function description comments from private methods LFXV2-717 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Asitha de Silva <asithade@gmail.com> * fix(dashboards): add null checks to carousel scroll methods Add safety checks to prevent runtime errors when carousel scroll buttons are clicked before ViewChild is initialized or when conditionally rendered. LFXV2-717 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Asitha de Silva <asithade@gmail.com> * refactor(dashboards): swap pending actions and my meetings layout Reverse the order of pending actions and my meetings in board member dashboard to show pending actions on the left and my meetings on the right. LFXV2-717 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Asitha de Silva <asithade@gmail.com> --------- Signed-off-by: Asitha de Silva <asithade@gmail.com>
1 parent 8f93946 commit 71f93b6

File tree

17 files changed

+415
-707
lines changed

17 files changed

+415
-707
lines changed

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,4 @@ Before starting any work or commits:
142142
4. **Link PR to JIRA ticket** when creating pull requests
143143

144144
- Always use sequential thinking mcp for planning before doing any changes
145+
- Always run yarn build to validate that your changes are building too for validation

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

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,24 +37,6 @@ export class MainLayoutComponent {
3737
icon: 'fa-light fa-video',
3838
routerLink: '/meetings',
3939
},
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-
},
5840
];
5941

6042
// Sidebar footer items
@@ -63,6 +45,7 @@ export class MainLayoutComponent {
6345
label: 'Documentation',
6446
icon: 'fa-light fa-file-lines',
6547
url: 'https://docs.lfx.linuxfoundation.org',
48+
disabled: true,
6649
},
6750
{
6851
label: 'Submit a Ticket',

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@
2727

2828
<!-- Middle Row - Two Cards -->
2929
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
30-
<!-- My Meetings -->
31-
<lfx-my-meetings class="h-full" />
32-
3330
<!-- Pending Actions -->
3431
<lfx-pending-actions class="h-full" />
32+
33+
<!-- My Meetings -->
34+
<lfx-my-meetings class="h-full" />
3535
</div>
3636

3737
<!-- Foundation Health - Full Width -->

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

Lines changed: 45 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,33 @@
22
<!-- SPDX-License-Identifier: MIT -->
33

44
<section data-testid="dashboard-organization-involvement-section">
5-
<div class="mb-4">
6-
<h2 class="font-['Roboto_Slab'] font-semibold text-[16px]">Organization Involvement</h2>
5+
<div class="flex items-center justify-between mb-4">
6+
<div class="flex flex-col md:flex-row md:items-center gap-3">
7+
<h2 class="font-['Roboto_Slab'] font-semibold text-[16px]">{{ accountName() }}'s Involvement</h2>
8+
9+
<!-- Filter Pills -->
10+
<lfx-filter-pills [options]="filterOptions" [selectedFilter]="selectedFilter()" (filterChange)="handleFilterChange($event)"></lfx-filter-pills>
11+
</div>
12+
13+
<!-- Carousel Controls -->
14+
<div class="flex items-center gap-2">
15+
<button
16+
type="button"
17+
(click)="scrollLeft()"
18+
class="h-8 w-8 p-0 flex items-center justify-center rounded border border-gray-300 bg-white text-gray-600 hover:bg-gray-100 hover:border-gray-400 transition-colors"
19+
data-testid="dashboard-involvement-scroll-left"
20+
aria-label="Scroll left">
21+
<i class="fa-light fa-chevron-left"></i>
22+
</button>
23+
<button
24+
type="button"
25+
(click)="scrollRight()"
26+
class="h-8 w-8 p-0 flex items-center justify-center rounded border border-gray-300 bg-white text-gray-600 hover:bg-gray-100 hover:border-gray-400 transition-colors"
27+
data-testid="dashboard-involvement-scroll-right"
28+
aria-label="Scroll right">
29+
<i class="fa-light fa-chevron-right"></i>
30+
</button>
31+
</div>
732
</div>
833

934
@if (isLoading()) {
@@ -15,29 +40,19 @@ <h2 class="font-['Roboto_Slab'] font-semibold text-[16px]">Organization Involvem
1540
</div>
1641
</div>
1742
} @else {
18-
<div class="space-y-4">
19-
<!-- Primary Metrics Row - 4 compact cards -->
20-
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
43+
<div class="overflow-hidden">
44+
<div #carouselScroll class="flex gap-4 overflow-x-auto pb-2 hide-scrollbar scroll-smooth" data-testid="dashboard-involvement-carousel">
2145
@for (metric of primaryMetrics(); track metric.title) {
2246
<!-- Membership Tier Card (Special) -->
2347
@if (metric.isMembershipTier) {
2448
<div
25-
class="p-3 bg-white rounded-lg border border-slate-200 hover:border-[#0094FF] transition-colors cursor-pointer"
49+
class="p-4 bg-white rounded-lg border border-slate-200 hover:border-[#0094FF] transition-colors cursor-pointer flex-shrink-0 w-80"
2650
[attr.data-testid]="'dashboard-involvement-metric-' + metric.title">
27-
<div class="space-y-2">
28-
<div class="flex items-center gap-2">
29-
<i class="fa-light fa-circle w-4 h-4 text-gray-500"></i>
30-
<h3 class="text-sm font-medium">{{ metric.title }}</h3>
31-
<span
32-
[class]="metric.isConnected ? 'text-green-500' : 'text-gray-400'"
33-
[pTooltip]="metric.isConnected ? 'Connected to live data' : 'Using placeholder data'"
34-
class="text-xs cursor-help">
35-
36-
</span>
37-
</div>
51+
<div class="space-y-3">
52+
<h5 class="text-sm font-medium w-full">{{ metric.title }}</h5>
3853

3954
<!-- Membership Info -->
40-
<div class="space-y-2 pt-1">
55+
<div class="space-y-2">
4156
<div class="flex items-center justify-between">
4257
<span class="text-sm text-gray-500">Tier</span>
4358
<span class="px-2 py-0.5 text-xs font-medium rounded bg-gradient-to-r from-gray-400 to-gray-300 text-white border border-gray-300">
@@ -56,34 +71,20 @@ <h3 class="text-sm font-medium">{{ metric.title }}</h3>
5671
</div>
5772
</div>
5873
} @else {
59-
<!-- Regular Compact Card -->
60-
<div
61-
class="p-3 bg-white rounded-lg border border-slate-200 hover:border-[#0094FF] transition-colors cursor-pointer"
62-
[attr.data-testid]="'dashboard-involvement-metric-' + metric.title">
63-
<div class="space-y-2">
64-
<div class="flex items-center gap-2">
65-
<i [class]="metric.icon + ' w-4 h-4 text-gray-500'"></i>
66-
<h3 class="text-sm font-medium">{{ metric.title }}</h3>
67-
<span
68-
[class]="metric.isConnected ? 'text-green-500' : 'text-gray-400'"
69-
[pTooltip]="metric.isConnected ? 'Connected to live data' : 'Using placeholder data'"
70-
class="text-xs cursor-help">
71-
72-
</span>
73-
</div>
74+
<!-- Regular Card -->
75+
<div class="p-4 bg-white rounded-lg border border-slate-200 flex-shrink-0 w-80" [attr.data-testid]="'dashboard-involvement-metric-' + metric.title">
76+
<div class="space-y-3">
77+
<h5 class="text-sm font-medium w-full">{{ metric.title }}</h5>
7478
@if (metric.chartData) {
75-
<!-- Bar chart for Active Contributors and Maintainers -->
76-
@if (metric.title === 'Active Contributors' || metric.title === 'Maintainers') {
77-
<div class="w-full h-8">
78-
<lfx-chart type="bar" [data]="metric.chartData" [options]="barChartOptions" height="100%"></lfx-chart>
79-
</div>
80-
} @else {
81-
<div class="w-full h-8">
82-
<lfx-chart type="line" [data]="metric.chartData" [options]="sparklineChartOptions" height="100%"></lfx-chart>
83-
</div>
84-
}
79+
<div class="w-full h-8">
80+
<lfx-chart
81+
[type]="metric.title === 'Active Contributors' || metric.title === 'Maintainers' ? 'bar' : 'line'"
82+
[data]="metric.chartData"
83+
[options]="metric.title === 'Active Contributors' || metric.title === 'Maintainers' ? barChartOptions : sparklineChartOptions"
84+
height="100%"></lfx-chart>
85+
</div>
8586
}
86-
<div class="space-y-0.5">
87+
<div class="space-y-1">
8788
<div class="text-xl font-medium">{{ metric.value }}</div>
8889
@if (metric.subtitle) {
8990
<div class="text-xs text-gray-500">{{ metric.subtitle }}</div>
@@ -94,53 +95,6 @@ <h3 class="text-sm font-medium">{{ metric.title }}</h3>
9495
}
9596
}
9697
</div>
97-
98-
<!-- Secondary Metrics Row - Two list tables -->
99-
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
100-
<!-- Our Contributions Table -->
101-
<div class="p-4 bg-white rounded-lg border border-slate-200">
102-
<h3 class="text-sm font-medium mb-3">Our Contributions</h3>
103-
<div class="space-y-0 -mb-4">
104-
@for (metric of contributionsMetrics(); track metric.title) {
105-
<div class="flex items-center justify-between w-full py-2.5 px-3 rounded-lg" [attr.data-testid]="'contributions-metric-' + metric.title">
106-
<span class="text-sm text-gray-500 flex items-center gap-1">
107-
{{ metric.title }}
108-
<i class="fa-light fa-circle-question w-3 h-3 cursor-help" [pTooltip]="metric.tooltip"></i>
109-
<span
110-
[class]="metric.isConnected ? 'text-green-500' : 'text-gray-400'"
111-
[pTooltip]="metric.isConnected ? 'Connected to live data' : 'Using placeholder data'"
112-
class="text-xs cursor-help">
113-
114-
</span>
115-
</span>
116-
<span class="text-sm font-medium">{{ metric.descriptiveValue }}</span>
117-
</div>
118-
}
119-
</div>
120-
</div>
121-
122-
<!-- Our Impact Table -->
123-
<div class="p-4 bg-white rounded-lg border border-slate-200">
124-
<h3 class="text-sm font-medium mb-3">Our Impact</h3>
125-
<div class="space-y-0 -mb-4">
126-
@for (metric of impactMetrics(); track metric.title) {
127-
<div class="flex items-center justify-between w-full py-2.5 px-3 rounded-lg" [attr.data-testid]="'impact-metric-' + metric.title">
128-
<span class="text-sm text-gray-500 flex items-center gap-1">
129-
{{ metric.title }}
130-
<i class="fa-light fa-circle-question w-3 h-3 cursor-help" [pTooltip]="metric.tooltip"></i>
131-
<span
132-
[class]="metric.isConnected ? 'text-green-500' : 'text-gray-400'"
133-
[pTooltip]="metric.isConnected ? 'Connected to live data' : 'Using placeholder data'"
134-
class="text-xs cursor-help">
135-
136-
</span>
137-
</span>
138-
<span class="text-sm font-medium">{{ metric.descriptiveValue }}</span>
139-
</div>
140-
}
141-
</div>
142-
</div>
143-
</div>
14498
</div>
14599
}
146100
</section>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,11 @@
11
// Copyright The Linux Foundation and each contributor to LFX.
22
// SPDX-License-Identifier: MIT
3+
4+
.hide-scrollbar {
5+
-ms-overflow-style: none; /* IE and Edge */
6+
scrollbar-width: none; /* Firefox */
7+
8+
&::-webkit-scrollbar {
9+
display: none; /* Chrome, Safari and Opera */
10+
}
11+
}

0 commit comments

Comments
 (0)