1- import { ChangeDetectionStrategy , Component , ElementRef , inject , Signal , viewChild } from "@angular/core" ;
1+ import { ChangeDetectionStrategy , Component , computed , ElementRef , inject , Signal , viewChild } from "@angular/core" ;
22import { AsyncPipe } from "@angular/common" ;
33import { ContributorCardComponent } from "../../components/contributor-card/contributor-card.component" ;
44import { ContributorService } from "../../../../services/contributor.service" ;
@@ -9,13 +9,9 @@ import { ThemeService } from "../../../../services/theme.service";
99import { ClipboardButtonComponent } from "../../../../shared/components/clipboard-button/clipboard-button.component" ;
1010import { ReasonCardComponent } from "../../../../shared/components/reason-card/reason-card.component" ;
1111import { SvgIconComponent } from "angular-svg-icon" ;
12- import { forkJoin , map , Observable , of , switchMap } from "rxjs" ;
13- import {
14- StackedCardCarouselComponent
15- } from "../../../../shared/components/stacked-card-carousel/stacked-card-carousel.component" ;
12+ import { map , Observable } from "rxjs" ;
13+ import { StackedCardCarouselComponent } from "../../components/stacked-card-carousel/stacked-card-carousel.component" ;
1614import { ContainerService } from "../../../../services/container.service" ;
17- import { DockerHubImage } from "../../../../models/docker-hub-image" ;
18- import { shareReplay } from "rxjs/operators" ;
1915
2016@Component ( {
2117 selector : 'app-landing' ,
@@ -71,15 +67,52 @@ export class LandingComponent {
7167 color : 300 ,
7268 }
7369 ] ;
70+ readonly containerMetadata = this . containerService . getAllContainersMetadataRes ( ) . value ;
71+ readonly containersInfo = this . containerService . getAllContainersInfoRes ( ) . value ;
72+ readonly mostRecentImages = computed ( ( ) => {
73+ const numberOfImages = 5 ;
74+ const containerMetadata = this . containerMetadata ( ) ;
75+ const containersInfo = this . containersInfo ( ) ;
76+
77+ if ( ! containerMetadata || ! containersInfo ) return [ ] ;
78+
79+ return [ ...containersInfo . values ( ) ]
80+ . sort ( ( a , b ) => {
81+ const lastUpdatedA = Date . parse ( a . last_updated ) ;
82+ const lastUpdatedB = Date . parse ( b . last_updated ) ;
83+ const creationDateA = Date . parse ( a . date_registered ) ;
84+ const creationDateB = Date . parse ( b . date_registered ) ;
85+ // Compare the most recent of either last_updated or creation_date
86+ return Math . max ( lastUpdatedB , creationDateB ) - Math . max ( lastUpdatedA , creationDateA ) ;
87+ } )
88+ . filter ( image => containerMetadata . has ( image . name ) )
89+ . slice ( 0 , numberOfImages )
90+ . map ( image => {
91+ const lastUpdatedDate = Date . parse ( image . last_updated ) ;
92+ const creationDate = Date . parse ( image . date_registered ) ;
93+ const type = lastUpdatedDate > creationDate ? 'updated' : 'new' ;
94+
95+ const version = this . containerService . getContainerTags ( image . name ) . pipe (
96+ map ( tags => {
97+ if ( tags . length > 1 ) {
98+ // Find the most recent tag based on last_updated, excluding tag latest
99+ return tags
100+ . filter ( tag => tag . name !== 'latest' )
101+ . sort ( ( a , b ) => Date . parse ( b . last_updated ) - Date . parse ( a . last_updated ) ) [ 0 ] . name ;
102+ }
103+ return tags [ 0 ] ?. name || '' ;
104+ } )
105+ ) ;
74106
75- recentImages$ : Observable < { type : string ; image : DockerHubImage ; version : string } [ ] > ;
107+ return { type, image, version } ;
108+ } ) ;
109+ } ) ;
76110
77111 /* State */
78112 searchClicked : boolean = false ;
79113
80114 constructor ( ) {
81115 this . isDarkTheme = this . themeService . isDarkTheme ( ) ;
82- this . recentImages$ = this . getMostRecentImages ( ) ;
83116 }
84117
85118 onSearchClick ( ) {
@@ -96,49 +129,4 @@ export class LandingComponent {
96129 getContributors ( ) : Observable < Contributor [ ] > {
97130 return this . contributorService . getContributors ( ) ;
98131 }
99-
100- getMostRecentImages ( ) : Observable < { type : string ; image : DockerHubImage ; version : string } [ ] > {
101- return this . containerService . getAllContainersInfo ( ) . pipe (
102- switchMap ( ( containersInfo ) => {
103- const sortedImages = [ ...containersInfo . values ( ) ]
104- . sort ( ( a , b ) => {
105- const lastUpdatedA = Date . parse ( a . last_updated ) ;
106- const lastUpdatedB = Date . parse ( b . last_updated ) ;
107- const creationDateA = Date . parse ( a . date_registered ) ;
108- const creationDateB = Date . parse ( b . date_registered ) ;
109-
110- // Compare the most recent of either last_updated or creation_date
111- return Math . max ( lastUpdatedB , creationDateB ) - Math . max ( lastUpdatedA , creationDateA ) ;
112- } )
113- . slice ( 0 , 5 ) ; // Take the top 5 most recent images
114-
115- if ( sortedImages . length === 0 ) {
116- return of ( [ ] ) ;
117- }
118-
119- // Batch the tag requests
120- const tagRequests = sortedImages . map ( image =>
121- this . containerService . getContainerTags ( image . name ) . pipe (
122- map ( tags => {
123- const lastUpdatedDate = Date . parse ( image . last_updated ) ;
124- const creationDate = Date . parse ( image . date_registered ) ;
125- const type = lastUpdatedDate > creationDate ? 'updated' : 'new' ;
126- let version = '' ;
127-
128- if ( type === 'updated' ) {
129- // Find the most recent tag based on last_updated, excluding tag latest
130- version = tags . filter ( tag => tag . name !== 'latest' ) . sort ( ( a , b ) => Date . parse ( b . last_updated ) - Date . parse ( a . last_updated ) ) [ 0 ] . name ;
131- }
132-
133- return { type, image, version } ;
134- } )
135- )
136- ) ;
137-
138- return forkJoin ( tagRequests ) ;
139- } ) ,
140- // Add shareReplay to prevent multiple subscriptions from triggering multiple API calls
141- shareReplay ( 1 )
142- ) ;
143- }
144132}
0 commit comments