@@ -23,6 +23,7 @@ import { catchError, of, switchMap, tap } from 'rxjs';
2323
2424import type {
2525 ActiveWeeksStreakResponse ,
26+ CodeCommitsDailyResponse ,
2627 DashboardMetricCard ,
2728 FoundationContributorsMentoredResponse ,
2829 HealthMetricsDailyResponse ,
@@ -59,6 +60,7 @@ export class RecentProgressComponent {
5960 contributorsMentored : true ,
6061 uniqueContributorsWeekly : true ,
6162 healthMetricsDaily : true ,
63+ codeCommitsDaily : true ,
6264 } ) ;
6365 public readonly projectSlug = computed ( ( ) => this . projectContextService . selectedFoundation ( ) ?. slug || this . projectContextService . selectedProject ( ) ?. slug ) ;
6466 private readonly entityType = computed < 'foundation' | 'project' > ( ( ) => ( this . projectContextService . selectedFoundation ( ) ? 'foundation' : 'project' ) ) ;
@@ -70,6 +72,7 @@ export class RecentProgressComponent {
7072 private readonly contributorsMentoredData = this . initializeContributorsMentoredData ( ) ;
7173 private readonly uniqueContributorsWeeklyData = this . initializeUniqueContributorsWeeklyData ( ) ;
7274 private readonly healthMetricsDailyData = this . initializeHealthMetricsDailyData ( ) ;
75+ private readonly codeCommitsDailyData = this . initializeCodeCommitsDailyData ( ) ;
7376 private readonly issuesTooltipData = this . initializeIssuesTooltipData ( ) ;
7477 private readonly prVelocityTooltipData = this . initializePrVelocityTooltipData ( ) ;
7578 private readonly uniqueContributorsTooltipData = this . initializeUniqueContributorsTooltipData ( ) ;
@@ -88,6 +91,7 @@ export class RecentProgressComponent {
8891 private readonly contributorsMentoredCard = this . initializeContributorsMentoredCard ( ) ;
8992 private readonly uniqueContributorsCard = this . initializeUniqueContributorsCard ( ) ;
9093 private readonly healthScoreCard = this . initializeHealthScoreCard ( ) ;
94+ private readonly codeCommitsDailyCard = this . initializeCodeCommitsDailyCard ( ) ;
9195
9296 // Filtered cards - materializes card values while benefiting from individual signal memoization
9397 protected readonly filteredProgressItems = this . initializeFilteredProgressItems ( ) ;
@@ -140,8 +144,6 @@ export class RecentProgressComponent {
140144 borderColor : lfxColors . emerald [ 500 ] ,
141145 backgroundColor : hexToRgba ( lfxColors . emerald [ 500 ] , 0.1 ) ,
142146 fill : true ,
143- tension : 0.4 ,
144- borderWidth : 2 ,
145147 pointRadius : 0 ,
146148 } ,
147149 ] ,
@@ -185,8 +187,6 @@ export class RecentProgressComponent {
185187 borderColor : lfxColors . blue [ 500 ] ,
186188 backgroundColor : hexToRgba ( lfxColors . blue [ 500 ] , 0.1 ) ,
187189 fill : true ,
188- tension : 0 ,
189- borderWidth : 2 ,
190190 pointRadius : 0 ,
191191 } ,
192192 ] ,
@@ -230,8 +230,6 @@ export class RecentProgressComponent {
230230 borderColor : lfxColors . blue [ 500 ] ,
231231 backgroundColor : hexToRgba ( lfxColors . blue [ 500 ] , 0.1 ) ,
232232 fill : true ,
233- tension : 0.4 ,
234- borderWidth : 2 ,
235233 pointRadius : 0 ,
236234 } ,
237235 ] ,
@@ -371,7 +369,6 @@ export class RecentProgressComponent {
371369 data : chartData . map ( ( row ) => row . AVG_MERGED_IN_DAYS ) ,
372370 borderColor : lfxColors . blue [ 500 ] ,
373371 backgroundColor : hexToRgba ( lfxColors . blue [ 500 ] , 0.5 ) ,
374- borderWidth : 0 ,
375372 borderRadius : 2 ,
376373 barPercentage : 0.95 ,
377374 categoryPercentage : 0.95 ,
@@ -449,8 +446,6 @@ export class RecentProgressComponent {
449446 borderColor : lfxColors . violet [ 500 ] ,
450447 backgroundColor : hexToRgba ( lfxColors . violet [ 500 ] , 0.1 ) ,
451448 fill : true ,
452- tension : 0.4 ,
453- borderWidth : 2 ,
454449 pointRadius : 0 ,
455450 } ,
456451 ] ,
@@ -507,7 +502,6 @@ export class RecentProgressComponent {
507502 data : chartData . map ( ( row ) => row . UNIQUE_CONTRIBUTORS ) ,
508503 backgroundColor : hexToRgba ( lfxColors . blue [ 500 ] , 0.5 ) ,
509504 borderColor : lfxColors . blue [ 500 ] ,
510- borderWidth : 0 ,
511505 borderRadius : 2 ,
512506 barPercentage : 0.95 ,
513507 categoryPercentage : 0.95 ,
@@ -588,8 +582,6 @@ export class RecentProgressComponent {
588582 borderColor : lfxColors . emerald [ 500 ] ,
589583 backgroundColor : hexToRgba ( lfxColors . emerald [ 500 ] , 0.1 ) ,
590584 fill : true ,
591- tension : 0.4 ,
592- borderWidth : 2 ,
593585 pointRadius : 0 ,
594586 } ,
595587 ] ,
@@ -617,6 +609,55 @@ export class RecentProgressComponent {
617609 } ;
618610 }
619611
612+ private transformCodeCommitsDaily ( data : CodeCommitsDailyResponse , metric : DashboardMetricCard ) : DashboardMetricCard {
613+ // Total commits from the API
614+ const totalCommits = data . totalCommits || 0 ;
615+
616+ // Determine trend based on commit count
617+ const trend = totalCommits > 0 ? 'up' : 'down' ;
618+
619+ return {
620+ ...metric ,
621+ loading : this . loadingState ( ) . codeCommitsDaily ,
622+ value : totalCommits . toLocaleString ( ) ,
623+ trend,
624+ chartData : {
625+ labels : data . data . map ( ( row ) => row . ACTIVITY_DATE ) ,
626+ datasets : [
627+ {
628+ label : 'Daily Commits' ,
629+ data : data . data . map ( ( row ) => row . DAILY_COMMIT_COUNT ) ,
630+ borderColor : lfxColors . blue [ 500 ] ,
631+ backgroundColor : hexToRgba ( lfxColors . blue [ 500 ] , 0.1 ) ,
632+ fill : true ,
633+ pointRadius : 0 ,
634+ } ,
635+ ] ,
636+ } ,
637+ chartOptions : {
638+ ...BASE_LINE_CHART_OPTIONS ,
639+ plugins : {
640+ ...BASE_LINE_CHART_OPTIONS . plugins ,
641+ tooltip : {
642+ ...( BASE_LINE_CHART_OPTIONS . plugins ?. tooltip ?? { } ) ,
643+ callbacks : {
644+ title : ( context : TooltipItem < 'line' > [ ] ) => {
645+ const dateStr = context [ 0 ] ?. label || '' ;
646+ if ( ! dateStr ) return '' ;
647+ const date = parseLocalDateString ( dateStr ) ;
648+ return date . toLocaleDateString ( 'en-US' , { month : 'short' , day : 'numeric' , year : 'numeric' } ) ;
649+ } ,
650+ label : ( context : TooltipItem < 'line' > ) => {
651+ const count = context . parsed . y ;
652+ return `Commits: ${ count . toLocaleString ( ) } ` ;
653+ } ,
654+ } ,
655+ } ,
656+ } ,
657+ } ,
658+ } ;
659+ }
660+
620661 private initializeActiveWeeksStreakData ( ) {
621662 return toSignal (
622663 toObservable ( this . personaService . currentPersona ) . pipe (
@@ -854,6 +895,35 @@ export class RecentProgressComponent {
854895 ) ;
855896 }
856897
898+ private initializeCodeCommitsDailyData ( ) {
899+ return toSignal (
900+ toObservable ( this . projectSlug ) . pipe (
901+ switchMap ( ( projectSlug ) => {
902+ if ( ! projectSlug ) {
903+ this . loadingState . update ( ( state ) => ( { ...state , codeCommitsDaily : false } ) ) ;
904+ return [ { data : [ ] , totalCommits : 0 , totalDays : 0 } ] ;
905+ }
906+ this . loadingState . update ( ( state ) => ( { ...state , codeCommitsDaily : true } ) ) ;
907+ const entityType = this . entityType ( ) ;
908+ return this . analyticsService . getCodeCommitsDaily ( projectSlug , entityType ) . pipe (
909+ tap ( ( ) => this . loadingState . update ( ( state ) => ( { ...state , codeCommitsDaily : false } ) ) ) ,
910+ catchError ( ( ) => {
911+ this . loadingState . update ( ( state ) => ( { ...state , codeCommitsDaily : false } ) ) ;
912+ return of ( { data : [ ] , totalCommits : 0 , totalDays : 0 } ) ;
913+ } )
914+ ) ;
915+ } )
916+ ) ,
917+ {
918+ initialValue : {
919+ data : [ ] ,
920+ totalCommits : 0 ,
921+ totalDays : 0 ,
922+ } ,
923+ }
924+ ) ;
925+ }
926+
857927 private initializeIsLoading ( ) {
858928 return computed < boolean > ( ( ) => {
859929 const state = this . loadingState ( ) ;
@@ -866,7 +936,8 @@ export class RecentProgressComponent {
866936 state . projectPullRequestsWeekly ||
867937 state . contributorsMentored ||
868938 state . uniqueContributorsWeekly ||
869- state . healthMetricsDaily
939+ state . healthMetricsDaily ||
940+ state . codeCommitsDaily
870941 ) ;
871942 }
872943
@@ -979,6 +1050,10 @@ export class RecentProgressComponent {
9791050 return computed ( ( ) => this . transformHealthMetricsDaily ( this . healthMetricsDailyData ( ) , this . getMetricConfig ( 'Health Score' ) ) ) ;
9801051 }
9811052
1053+ private initializeCodeCommitsDailyCard ( ) {
1054+ return computed ( ( ) => this . transformCodeCommitsDaily ( this . codeCommitsDailyData ( ) , this . getMetricConfig ( 'Code Commits' ) ) ) ;
1055+ }
1056+
9821057 private initializeFilteredProgressItems ( ) {
9831058 return computed < DashboardMetricCard [ ] > ( ( ) => {
9841059 const persona = this . personaService . currentPersona ( ) ;
@@ -989,6 +1064,7 @@ export class RecentProgressComponent {
9891064 const allCards = [
9901065 { card : this . issuesTrendCard ( ) , category : 'code' } ,
9911066 { card : this . prVelocityCard ( ) , category : 'code' } ,
1067+ { card : this . codeCommitsDailyCard ( ) , category : 'code' } ,
9921068 { card : this . contributorsMentoredCard ( ) , category : 'projectHealth' } ,
9931069 { card : this . uniqueContributorsCard ( ) , category : 'projectHealth' } ,
9941070 { card : this . healthScoreCard ( ) , category : 'projectHealth' } ,
0 commit comments