Skip to content

Commit 0318dfd

Browse files
authored
feat(ui): consolidate colors and add ssr organization filtering (#183)
* feat(ui): consolidate colors and add ssr organization filtering Migrate color system from semantic tokens to Tailwind standard colors, syncing with @linuxfoundation/lfx-ui-core primitives. Add SSR-compatible organization filtering based on committee memberships. Color System Changes: - Replace semantic colors (brand, negative, positive, warning, neutral) with Tailwind standard colors (blue, red, emerald, amber, gray) - Update all color constants in shared package - Remove tailwind safelist (no longer needed) - Update all HTML templates to use new color classes Organization Context Changes: - Add SSR cookie support for account selection - Filter organizations based on user's committee memberships - Add organization-matcher utility for fuzzy name matching - Enhance persona-helper to return organization names - Update server.ts for state transfer during SSR LFXV2-821 LFXV2-826 Signed-off-by: Asitha de Silva <asithade@gmail.com> * feat(committees): filter categories by persona type Add persona-based filtering for committee categories in the form. Maintainers see a filtered list while other personas see all categories. Board members are redirected to home when persona is set. LFXV2-826 Signed-off-by: Asitha de Silva <asithade@gmail.com> --------- Signed-off-by: Asitha de Silva <asithade@gmail.com>
1 parent 198e084 commit 0318dfd

File tree

40 files changed

+441
-405
lines changed

40 files changed

+441
-405
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { RouterOutlet } from '@angular/router';
77
import { AuthContext } from '@lfx-one/shared/interfaces';
88
import { ToastModule } from 'primeng/toast';
99

10+
import { AccountContextService } from './shared/services/account-context.service';
1011
import { FeatureFlagService } from './shared/services/feature-flag.service';
1112
import { PersonaService } from './shared/services/persona.service';
1213
import { SegmentService } from './shared/services/segment.service';
@@ -23,6 +24,7 @@ export class AppComponent {
2324
private readonly personaService = inject(PersonaService);
2425
private readonly segmentService = inject(SegmentService);
2526
private readonly featureFlagService = inject(FeatureFlagService);
27+
private readonly accountContextService = inject(AccountContextService);
2628

2729
public auth: AuthContext | undefined;
2830
public transferState = inject(TransferState);
@@ -49,6 +51,7 @@ export class AppComponent {
4951
authenticated: false,
5052
user: null,
5153
persona: null,
54+
organizations: [],
5255
});
5356

5457
if (this.auth?.authenticated && this.auth.user) {
@@ -58,6 +61,11 @@ export class AppComponent {
5861
// Initialize persona from backend (auto-detected from committee membership)
5962
this.personaService.initializeFromAuth(this.auth.persona);
6063

64+
// Initialize user organizations from backend (matched from committee memberships)
65+
if (this.auth.organizations && this.auth.organizations.length > 0) {
66+
this.accountContextService.initializeUserOrganizations(this.auth.organizations);
67+
}
68+
6169
// Identify user with Segment tracking (pass entire Auth0 user object)
6270
this.segmentService.identifyUser(this.auth.user);
6371

apps/lfx-one/src/app/modules/committees/committee-dashboard/committee-dashboard.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ <h1>{{ committeeLabelPlural }}</h1>
2626
</lfx-button>
2727
}
2828
</div>
29-
<p class="mt-2 text-neutral-500">A group is a team of people like committees, boards, or working groups organized to collaborate across your project</p>
29+
<p class="mt-2 text-gray-500">A group is a team of people like committees, boards, or working groups organized to collaborate across your project</p>
3030
</div>
3131

3232
<!-- Sticky Top Bar with Search and Filters -->

apps/lfx-one/src/app/modules/committees/components/committee-form/committee-form.component.html

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ <h2>Basic Information</h2>
1010

1111
<!-- Committee Name -->
1212
<div class="flex flex-col gap-2">
13-
<label for="committeeName" class="text-neutral-950 block text-sm font-medium"> {{ committeeLabel }} Name <span class="text-red-500">*</span> </label>
13+
<label for="committeeName" class="text-gray-950 block text-sm font-medium"> {{ committeeLabel }} Name <span class="text-red-500">*</span> </label>
1414
<lfx-input-text
1515
size="small"
1616
[form]="form()"
@@ -25,12 +25,12 @@ <h2>Basic Information</h2>
2525

2626
<!-- Category -->
2727
<div class="flex flex-col gap-2">
28-
<label for="category" class="text-neutral-950 block text-sm font-medium"> Category <span class="text-red-500">*</span> </label>
28+
<label for="category" class="text-gray-950 block text-sm font-medium"> Category <span class="text-red-500">*</span> </label>
2929
<lfx-select
3030
size="small"
3131
[form]="form()"
3232
control="category"
33-
[options]="categoryOptions"
33+
[options]="categoryOptions()"
3434
placeholder="Select a category"
3535
styleClass="w-full"
3636
id="category"></lfx-select>
@@ -41,7 +41,7 @@ <h2>Basic Information</h2>
4141

4242
<!-- Parent Committee -->
4343
<div class="flex flex-col gap-2">
44-
<label for="parentCommittee" class="text-neutral-950 block text-sm font-medium">Parent {{ committeeLabel }} (Optional)</label>
44+
<label for="parentCommittee" class="text-gray-950 block text-sm font-medium">Parent {{ committeeLabel }} (Optional)</label>
4545
<lfx-select
4646
size="small"
4747
[form]="form()"
@@ -59,7 +59,7 @@ <h2>Basic Information</h2>
5959

6060
<!-- Description -->
6161
<div class="flex flex-col gap-2">
62-
<label for="description" class="text-neutral-950 block text-sm font-medium">Description</label>
62+
<label for="description" class="text-gray-950 block text-sm font-medium">Description</label>
6363
<lfx-textarea
6464
[form]="form()"
6565
control="description"
@@ -71,7 +71,7 @@ <h2>Basic Information</h2>
7171

7272
<!-- Committee Website -->
7373
<div class="flex flex-col gap-2">
74-
<label for="website" class="text-neutral-950 block text-sm font-medium">{{ committeeLabel }} Website</label>
74+
<label for="website" class="text-gray-950 block text-sm font-medium">{{ committeeLabel }} Website</label>
7575
<lfx-input-text
7676
size="small"
7777
[form]="form()"
@@ -94,7 +94,7 @@ <h2 class="mb-4">Settings</h2>
9494
<!-- Business Email Required -->
9595
<div class="flex items-center justify-between">
9696
<div class="flex items-center gap-2">
97-
<label for="businessEmail" class="text-neutral-950 text-sm font-medium">Business Email Required</label>
97+
<label for="businessEmail" class="text-gray-950 text-sm font-medium">Business Email Required</label>
9898
<i
9999
class="fa-light fa-info-circle text-slate-400 cursor-help"
100100
pTooltip="Require members to have a business email address"
@@ -106,7 +106,7 @@ <h2 class="mb-4">Settings</h2>
106106
<!-- Enable Voting -->
107107
<div class="flex items-center justify-between">
108108
<div class="flex items-center gap-2">
109-
<label for="enableVoting" class="text-neutral-950 text-sm font-medium">Enable Voting</label>
109+
<label for="enableVoting" class="text-gray-950 text-sm font-medium">Enable Voting</label>
110110
<i class="fa-light fa-info-circle text-slate-400 cursor-help" pTooltip="Allow members to vote on committee matters" tooltipPosition="right"></i>
111111
</div>
112112
<lfx-toggle size="small" [form]="form()" control="enable_voting" id="enableVoting"></lfx-toggle>
@@ -115,15 +115,15 @@ <h2 class="mb-4">Settings</h2>
115115
<!-- Enable Audit -->
116116
<div class="flex items-center justify-between">
117117
<div class="flex items-center gap-2">
118-
<label for="enableAudit" class="text-neutral-950 text-sm font-medium">Enable Audit</label>
118+
<label for="enableAudit" class="text-gray-950 text-sm font-medium">Enable Audit</label>
119119
</div>
120120
<lfx-toggle size="small" [form]="form()" control="is_audit_enabled" id="enableAudit"></lfx-toggle>
121121
</div>
122122

123123
<!-- Joinable -->
124124
<div class="flex items-center justify-between">
125125
<div class="flex items-center gap-2">
126-
<label for="joinable" class="text-neutral-950 text-sm font-medium">Joinable</label>
126+
<label for="joinable" class="text-gray-950 text-sm font-medium">Joinable</label>
127127
<i
128128
class="fa-light fa-info-circle text-slate-400 cursor-help"
129129
pTooltip="Allow users to join the committee without invitation"
@@ -135,7 +135,7 @@ <h2 class="mb-4">Settings</h2>
135135
<!-- Make Committee Public -->
136136
<div class="flex items-center justify-between">
137137
<div class="flex items-center gap-2">
138-
<label for="makePublic" class="text-neutral-950 text-sm font-medium">Make {{ committeeLabel }} Public</label>
138+
<label for="makePublic" class="text-gray-950 text-sm font-medium">Make {{ committeeLabel }} Public</label>
139139
<i class="fa-light fa-info-circle text-slate-400 cursor-help" pTooltip="Make committee visible to all users" tooltipPosition="right"></i>
140140
</div>
141141
<lfx-toggle size="small" [form]="form()" control="public" id="makePublic"></lfx-toggle>
@@ -144,7 +144,7 @@ <h2 class="mb-4">Settings</h2>
144144
<!-- Display Name (Conditional) -->
145145
@if (form().get('public')?.value === true) {
146146
<div class="flex flex-col gap-2">
147-
<label for="displayName" class="text-neutral-950 block text-sm font-medium">Public Display Name</label>
147+
<label for="displayName" class="text-gray-950 block text-sm font-medium">Public Display Name</label>
148148
<lfx-input-text
149149
size="small"
150150
[form]="form()"
@@ -158,15 +158,15 @@ <h2 class="mb-4">Settings</h2>
158158
<!-- Enable SSO Group -->
159159
<div class="flex items-center justify-between">
160160
<div class="flex items-center gap-2">
161-
<label for="enableSSO" class="text-neutral-950 text-sm font-medium">Enable SSO Group</label>
161+
<label for="enableSSO" class="text-gray-950 text-sm font-medium">Enable SSO Group</label>
162162
</div>
163163
<lfx-toggle size="small" [form]="form()" control="sso_group_enabled" id="enableSSO"></lfx-toggle>
164164
</div>
165165

166166
<!-- SSO Group Name (Conditional) -->
167167
@if (form().get('sso_group_enabled')?.value === true) {
168168
<div class="flex flex-col gap-2">
169-
<label for="ssoGroupName" class="text-neutral-950 block text-sm font-medium">SSO Group Name</label>
169+
<label for="ssoGroupName" class="text-gray-950 block text-sm font-medium">SSO Group Name</label>
170170
<lfx-input-text
171171
size="small"
172172
[form]="form()"

apps/lfx-one/src/app/modules/committees/components/committee-form/committee-form.component.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ import { InputTextComponent } from '@components/input-text/input-text.component'
1010
import { SelectComponent } from '@components/select/select.component';
1111
import { TextareaComponent } from '@components/textarea/textarea.component';
1212
import { ToggleComponent } from '@components/toggle/toggle.component';
13-
import { COMMITTEE_LABEL, FILTERED_COMMITTEE_CATEGORIES } from '@lfx-one/shared/constants';
13+
import { COMMITTEE_CATEGORIES, COMMITTEE_LABEL, FILTERED_COMMITTEE_CATEGORIES } from '@lfx-one/shared/constants';
1414
import { Committee } from '@lfx-one/shared/interfaces';
1515
import { CommitteeService } from '@services/committee.service';
16+
import { PersonaService } from '@services/persona.service';
1617
import { ProjectContextService } from '@services/project-context.service';
1718
import { TooltipModule } from 'primeng/tooltip';
1819
import { map } from 'rxjs';
@@ -27,7 +28,7 @@ import { map } from 'rxjs';
2728
export class CommitteeFormComponent {
2829
private readonly committeeService = inject(CommitteeService);
2930
private readonly projectContextService = inject(ProjectContextService);
30-
31+
private readonly personaService = inject(PersonaService);
3132
// Signal inputs
3233
public form = input.required<FormGroup>();
3334
public isEditMode = input.required<boolean>();
@@ -39,7 +40,9 @@ export class CommitteeFormComponent {
3940
public readonly formCancel = output<void>();
4041

4142
// Category options from constants (using filtered list)
42-
public readonly categoryOptions = FILTERED_COMMITTEE_CATEGORIES;
43+
public readonly categoryOptions = computed(() => {
44+
return this.personaService.currentPersona() === 'maintainer' ? FILTERED_COMMITTEE_CATEGORIES : COMMITTEE_CATEGORIES;
45+
});
4346

4447
// Load parent committee options
4548
public parentCommitteeOptions: Signal<{ label: string; value: string | null }[]> = this.initializeParentCommitteeOptions();

apps/lfx-one/src/app/modules/committees/components/committee-table/committee-table.component.html

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
<table class="min-w-full" data-testid="committee-dashboard-table">
77
<thead>
88
<tr>
9-
<th class="px-3 py-3 text-left text-xs font-medium text-[#62748e] min-w-[250px]">{{ committeeLabel() }}</th>
10-
<th class="px-3 py-3 text-left text-xs font-medium text-[#62748e] min-w-[300px]">Description</th>
11-
<th class="px-3 py-3 text-left text-xs font-medium text-[#62748e] w-[80px]">Members</th>
12-
<th class="px-3 py-3 text-left text-xs font-medium text-[#62748e] w-[80px]">Voting</th>
13-
<th class="px-3 py-3 text-left text-xs font-medium text-[#62748e] w-[100px]">Last Updated</th>
14-
<th class="px-3 py-3 text-left text-xs font-medium text-[#62748e] w-[120px]"></th>
9+
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 min-w-[250px]">{{ committeeLabel() }}</th>
10+
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 min-w-[300px]">Description</th>
11+
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 w-[80px]">Members</th>
12+
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 w-[80px]">Voting</th>
13+
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 w-[100px]">Last Updated</th>
14+
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 w-[120px]"></th>
1515
</tr>
1616
</thead>
1717
<tbody>
@@ -21,7 +21,7 @@
2121
<div class="flex flex-col gap-1">
2222
<lfx-tag [value]="committee.category || 'Other'" [severity]="getCategorySeverity(committee.category || 'Other')"></lfx-tag>
2323
<div class="flex items-center gap-2">
24-
<p class="font-inter font-medium leading-[16px] not-italic text-[#0f172b] text-[12px] text-nowrap whitespace-pre">
24+
<p class="font-inter font-medium leading-[16px] not-italic text-gray-900 text-[12px] text-nowrap whitespace-pre">
2525
{{ committee.name }}
2626
</p>
2727
@if (!committee.public) {
@@ -32,16 +32,16 @@
3232
</td>
3333
<td class="px-3 py-3 text-xs min-w-[300px]">{{ committee.description || '-' }}</td>
3434
<td class="px-3 py-3 w-[140px]">
35-
<a [routerLink]="['/groups', committee.uid]" class="text-xs text-brand-500 hover:text-brand-600 hover:underline cursor-pointer">
35+
<a [routerLink]="['/groups', committee.uid]" class="text-xs text-blue-500 hover:text-blue-600 hover:underline cursor-pointer">
3636
{{ committee.total_members || 0 }}
3737
</a>
3838
</td>
39-
<td class="px-3 py-3 text-xs text-[#0f172b] w-[80px]">
39+
<td class="px-3 py-3 text-xs text-gray-900 w-[80px]">
4040
@if (committee.enable_voting) {
4141
<i class="fa-light fa-check w-4 h-4 text-green-600"></i>
4242
}
4343
</td>
44-
<td class="px-3 py-3 text-xs text-[#0f172b] w-[100px] whitespace-nowrap">{{ committee.updated_at | date: 'MMM d, y' }}</td>
44+
<td class="px-3 py-3 text-xs text-gray-900 w-[100px] whitespace-nowrap">{{ committee.updated_at | date: 'MMM d, y' }}</td>
4545
<td class="px-3 py-3 text-xs w-[120px]">
4646
@if (canManageCommittee()) {
4747
<div class="flex items-center gap-1">

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,10 @@ <h1>{{ selectedFoundation()?.name }} Overview</h1>
3636

3737
<!-- Middle Row - Two Cards -->
3838
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
39-
<!-- Pending Actions -->
40-
<lfx-pending-actions class="h-full" [pendingActions]="boardMemberActions()" (actionClick)="handleActionClick()" />
41-
4239
<!-- My Meetings -->
4340
<lfx-my-meetings class="h-full" />
41+
<!-- Pending Actions -->
42+
<lfx-pending-actions class="h-full" [pendingActions]="boardMemberActions()" (actionClick)="handleActionClick()" />
4443
</div>
4544

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

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

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,11 @@ export class FoundationHealthComponent {
110110
const distribution = this.healthScoresData();
111111

112112
const data = [
113-
{ category: 'Critical', count: distribution.critical, color: lfxColors.negative[500] },
114-
{ category: 'Unsteady', count: distribution.unsteady, color: lfxColors.warning[400] },
115-
{ category: 'Stable', count: distribution.stable, color: lfxColors.warning[500] },
116-
{ category: 'Healthy', count: distribution.healthy, color: lfxColors.brand[500] },
117-
{ category: 'Excellent', count: distribution.excellent, color: lfxColors.positive[500] },
113+
{ category: 'Critical', count: distribution.critical, color: lfxColors.red[500] },
114+
{ category: 'Unsteady', count: distribution.unsteady, color: lfxColors.amber[400] },
115+
{ category: 'Stable', count: distribution.stable, color: lfxColors.amber[500] },
116+
{ category: 'Healthy', count: distribution.healthy, color: lfxColors.blue[500] },
117+
{ category: 'Excellent', count: distribution.excellent, color: lfxColors.emerald[500] },
118118
];
119119

120120
const maxCount = Math.max(...data.map((d) => d.count));
@@ -205,8 +205,8 @@ export class FoundationHealthComponent {
205205
datasets: [
206206
{
207207
data: data.monthlyData,
208-
borderColor: metric.sparklineColor || lfxColors.brand[500],
209-
backgroundColor: hexToRgba(metric.sparklineColor || lfxColors.brand[500], 0.1),
208+
borderColor: metric.sparklineColor || lfxColors.blue[500],
209+
backgroundColor: hexToRgba(metric.sparklineColor || lfxColors.blue[500], 0.1),
210210
fill: true,
211211
tension: 0.4,
212212
borderWidth: 2,
@@ -249,8 +249,8 @@ export class FoundationHealthComponent {
249249
datasets: [
250250
{
251251
data: data.monthlyData,
252-
borderColor: metric.sparklineColor || lfxColors.brand[500],
253-
backgroundColor: hexToRgba(metric.sparklineColor || lfxColors.brand[500], 0.1),
252+
borderColor: metric.sparklineColor || lfxColors.blue[500],
253+
backgroundColor: hexToRgba(metric.sparklineColor || lfxColors.blue[500], 0.1),
254254
fill: true,
255255
tension: 0.4,
256256
borderWidth: 2,
@@ -320,7 +320,7 @@ export class FoundationHealthComponent {
320320
category: metric.category as MetricCategory,
321321
testId: metric.testId,
322322
customContentType: metric.customContentType,
323-
chartData: this.createSparklineData(metrics.activeContributorsData, metric.sparklineColor || lfxColors.brand[500]),
323+
chartData: this.createSparklineData(metrics.activeContributorsData, metric.sparklineColor || lfxColors.blue[500]),
324324
};
325325
}
326326

@@ -340,8 +340,8 @@ export class FoundationHealthComponent {
340340
datasets: [
341341
{
342342
data: data.trendData,
343-
borderColor: metric.sparklineColor || lfxColors.brand[500],
344-
backgroundColor: hexToRgba(metric.sparklineColor || lfxColors.brand[500], 0.1),
343+
borderColor: metric.sparklineColor || lfxColors.blue[500],
344+
backgroundColor: hexToRgba(metric.sparklineColor || lfxColors.blue[500], 0.1),
345345
fill: true,
346346
tension: 0.4,
347347
borderWidth: 2,
@@ -380,7 +380,7 @@ export class FoundationHealthComponent {
380380
category: metric.category as MetricCategory,
381381
testId: metric.testId,
382382
customContentType: metric.customContentType,
383-
chartData: this.createBarChartData(metrics.eventsMonthlyData, metric.chartColor || lfxColors.brand[500]),
383+
chartData: this.createBarChartData(metrics.eventsMonthlyData, metric.chartColor || lfxColors.blue[500]),
384384
};
385385
}
386386

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ <h2 class="font-display font-semibold text-[16px]">My Projects</h2>
1010
@if (loading()) {
1111
<div class="absolute inset-0 bg-white/60 flex items-center justify-center z-10" data-testid="dashboard-my-projects-loading">
1212
<div class="flex flex-col items-center gap-2">
13-
<i class="fa-solid fa-spinner fa-spin text-brand-500 text-2xl"></i>
13+
<i class="fa-solid fa-spinner fa-spin text-blue-500 text-2xl"></i>
1414
<span class="text-sm text-gray-600">Loading...</span>
1515
</div>
1616
</div>
@@ -61,7 +61,7 @@ <h2 class="font-display font-semibold text-[16px]">My Projects</h2>
6161
}
6262
</div>
6363
<div class="min-w-0">
64-
<div class="font-medium text-sm text-brand-500 truncate">{{ project.name }}</div>
64+
<div class="font-medium text-sm text-blue-500 truncate">{{ project.name }}</div>
6565
<div class="text-xs text-muted-foreground truncate">{{ project.role }}</div>
6666
</div>
6767
</div>

0 commit comments

Comments
 (0)