Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"cSpell.words": [
"ADESILVA",
"animateonscroll",
"aswf",
"AUTHELIA",
Expand All @@ -16,6 +17,7 @@
"fullcalendar",
"iconfield",
"inputicon",
"JEVANS",
"Linkify",
"litellm",
"networkidle",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,115 +40,134 @@ <h2>{{ title() }}</h2>
</div>
</div>

<!-- Carousel Container -->
<div class="overflow-hidden">
<div #carouselScroll class="flex gap-4 overflow-x-auto pb-2 hide-scrollbar scroll-smooth" data-testid="foundation-health-carousel">
@for (card of metricCards(); track card.title) {
<div class="p-4 bg-white rounded-lg border border-slate-200 flex-shrink-0 w-[calc(100vw-3rem)] md:w-80" [attr.data-testid]="card.testId">
<div class="flex flex-col h-full justify-between">
<!-- Card Header -->
<div class="flex items-center gap-2">
<i [class]="card.icon + ' w-4 h-4 text-muted-foreground'"></i>
<h5 class="text-sm font-medium">{{ card.title }}</h5>
</div>
@if (!hasFoundationSelected()) {
<!-- No Foundation Selected State -->
<div class="flex items-center justify-center p-12">
<div class="text-center space-y-3">
<i class="fa-light fa-circle-exclamation text-4xl text-gray-400"></i>
<p class="text-sm text-gray-600 font-medium">Please select a foundation project to view foundation health data</p>
<p class="text-xs text-gray-500">Use the project selector in the sidebar to choose a foundation</p>
</div>
</div>
} @else if (isLoading() && !metricCards()) {
<!-- Loading State -->
<div class="flex items-center justify-center p-12">
<div class="text-center space-y-3">
<i class="fa-light fa-spinner-third fa-spin text-4xl text-[#0094FF]"></i>
<p class="text-sm text-gray-500">Loading foundation health data...</p>
</div>
</div>
} @else {
<!-- Carousel Container -->
<div class="overflow-hidden">
<div #carouselScroll class="flex gap-4 overflow-x-auto pb-2 hide-scrollbar scroll-smooth" data-testid="foundation-health-carousel">
@for (card of metricCards(); track card.title) {
<div class="p-4 bg-white rounded-lg border border-slate-200 flex-shrink-0 w-[calc(100vw-3rem)] md:w-80" [attr.data-testid]="card.testId">
<div class="flex flex-col h-full justify-between">
<!-- Card Header -->
<div class="flex items-center gap-2">
<i [class]="card.icon + ' w-4 h-4 text-muted-foreground'"></i>
<h5 class="text-sm font-medium">{{ card.title }}</h5>
</div>

<!-- Custom Content -->
@switch (card.customContentType) {
<!-- Sparkline Chart -->
@case ('sparkline') {
@if (card.chartData) {
<div class="mt-3 w-full h-16">
<lfx-chart [type]="'line'" [data]="card.chartData" [options]="sparklineOptions" height="100%"></lfx-chart>
</div>
<!-- Custom Content -->
@switch (card.customContentType) {
<!-- Sparkline Chart -->
@case ('sparkline') {
@if (card.chartData) {
<div class="mt-3 w-full h-16">
<lfx-chart [type]="'line'" [data]="card.chartData" [options]="card.chartOptions || sparklineOptions" height="100%"></lfx-chart>
</div>
}
}
}

<!-- Bar Chart -->
@case ('bar-chart') {
@if (card.chartData) {
<div class="mt-3 flex justify-center">
<div class="w-[200px] h-[60px]">
<lfx-chart [type]="'bar'" [data]="card.chartData" [options]="barChartOptions" height="100%"></lfx-chart>
<!-- Bar Chart -->
@case ('bar-chart') {
@if (card.chartData) {
<div class="mt-3 flex justify-center">
<div class="w-[200px] h-[60px]">
<lfx-chart [type]="'bar'" [data]="card.chartData" [options]="barChartOptions" height="100%"></lfx-chart>
</div>
</div>
</div>
}
}
}

<!-- Top Projects List -->
@case ('top-projects') {
@if (card.topProjects) {
<div class="space-y-0.5 p-0 pr-5 pl-[60px] m-0 mb-[5px]">
<div class="text-xs font-medium text-muted-foreground">Top 3 Projects by Value</div>
@for (project of card.topProjects; track project.name) {
<div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ project.name }}</span>
<span class="font-medium">{{ project.formattedValue }}</span>
</div>
}
</div>
<!-- Top Projects List -->
@case ('top-projects') {
@if (card.topProjects) {
<div class="space-y-0.5 p-0 pl-[60px] m-0 mb-[5px]">
<div class="text-xs font-medium text-muted-foreground">Top 3 Projects by Value</div>
@for (project of card.topProjects; track project.name) {
<div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ project.name }}</span>
<span class="font-medium">{{ project.formattedValue }}</span>
</div>
}
</div>
}
}
}

<!-- Company Bus Factor (Inline) -->
@case ('bus-factor') {
@if (card.busFactor) {
<div class="flex-1 flex flex-col justify-end pb-2">
<div class="flex gap-0">
<!-- Top Companies Section -->
<div [style.width.%]="card.busFactor.topCompaniesPercentage" class="flex flex-col gap-1">
<div class="text-xs font-medium text-slate-700">
{{ card.busFactor.topCompaniesCount }} Companies ({{ card.busFactor.topCompaniesPercentage }}%)
<!-- Company Bus Factor (Inline) -->
@case ('bus-factor') {
@if (card.busFactor) {
<div class="flex-1 flex flex-col justify-end pb-2">
<div class="flex gap-0">
<!-- Top Companies Section -->
<div [style.width.%]="card.busFactor.topCompaniesPercentage" class="flex flex-col gap-1">
<div class="text-xs font-medium text-slate-700">
{{ card.busFactor.topCompaniesCount }} Companies ({{ card.busFactor.topCompaniesPercentage }}%)
</div>
<div class="h-4 rounded-l-sm bg-gray-300"></div>
</div>
<div class="h-4 rounded-l-sm bg-[#0094FF]"></div>
</div>

<!-- Other Companies Section -->
<div [style.width.%]="card.busFactor.otherCompaniesPercentage" class="flex flex-col gap-1">
<div class="text-xs text-slate-600 text-right">{{ card.busFactor.otherCompaniesCount }} Other Companies</div>
<div class="h-4 bg-slate-200 rounded-r-sm"></div>
<!-- Other Companies Section -->
<div [style.width.%]="card.busFactor.otherCompaniesPercentage" class="flex flex-col gap-1">
<div class="text-xs text-slate-600 text-right">{{ card.busFactor.otherCompaniesCount }} Other Companies</div>
<div class="h-4 bg-slate-200 rounded-r-sm"></div>
</div>
</div>
</div>
</div>
}
}
}

<!-- Project Health Scores -->
@case ('health-scores') {
@if (card.healthScores) {
<div class="flex-1 flex flex-col justify-end p-0">
<div class="flex items-end justify-between gap-2 h-16">
@for (item of healthScoreDistribution(); track item.category) {
<div class="flex-1 flex flex-col items-center gap-1">
<div
class="w-full rounded-t transition-all hover:opacity-80"
[style.backgroundColor]="item.color"
[style.height.px]="item.heightPx"></div>
<div class="text-[10px] text-center whitespace-nowrap">
<div class="font-medium">{{ item.category }}</div>
<div class="text-muted-foreground">{{ item.count }}</div>
<!-- Project Health Scores -->
@case ('health-scores') {
@if (card.healthScores) {
<div class="flex-1 flex flex-col justify-end p-0">
<div class="flex items-end justify-between gap-2 h-16">
@for (item of healthScoreDistribution(); track item.category) {
<div class="flex-1 flex flex-col items-center gap-1">
<div
class="w-full rounded-t transition-all hover:opacity-80"
[style.backgroundColor]="item.color"
[style.height.px]="item.heightPx"></div>
<div class="text-[10px] text-center whitespace-nowrap">
<div class="font-medium">{{ item.category }}</div>
<div class="text-muted-foreground">{{ item.count }}</div>
</div>
</div>
</div>
}
}
</div>
</div>
</div>
}
}
}
}

<!-- Card Footer (Value and Subtitle) -->
@if (card.value || card.subtitle) {
<div class="space-y-1">
@if (card.value) {
<div class="text-xl font-medium">{{ card.value }}</div>
}
@if (card.subtitle) {
<div class="text-xs text-gray-500">{{ card.subtitle }}</div>
}
</div>
}
<!-- Card Footer (Value and Subtitle) -->
@if (card.value || card.subtitle) {
<div class="space-y-1">
@if (card.value) {
<div class="text-xl font-medium">{{ card.value }}</div>
}
@if (card.subtitle) {
<div class="text-xs text-gray-500">{{ card.subtitle }}</div>
}
</div>
}
</div>
</div>
</div>
}
}
</div>
</div>
</div>
}
</section>
Loading