@@ -115,6 +115,7 @@ export type Services = {
115115 id : string ;
116116 createdAt : string ;
117117 status ?: "idle" | "running" | "done" | "error" ;
118+ lastDeployDate ?: Date | null ;
118119} ;
119120
120121type Project = Awaited < ReturnType < typeof findProjectById > > ;
@@ -128,16 +129,34 @@ export const extractServicesFromEnvironment = (
128129 const allServices : Services [ ] = [ ] ;
129130
130131 const applications : Services [ ] =
131- environment . applications ?. map ( ( item ) => ( {
132- appName : item . appName ,
133- name : item . name ,
134- type : "application" ,
135- id : item . applicationId ,
136- createdAt : item . createdAt ,
137- status : item . applicationStatus ,
138- description : item . description ,
139- serverId : item . serverId ,
140- } ) ) || [ ] ;
132+ environment . applications ?. map ( ( item ) => {
133+ // Get the most recent deployment date
134+ let lastDeployDate : Date | null = null ;
135+ const deployments = ( item as any ) . deployments ;
136+ if ( deployments && deployments . length > 0 ) {
137+ for ( const deployment of deployments ) {
138+ const deployDate = new Date (
139+ deployment . finishedAt ||
140+ deployment . startedAt ||
141+ deployment . createdAt ,
142+ ) ;
143+ if ( ! lastDeployDate || deployDate > lastDeployDate ) {
144+ lastDeployDate = deployDate ;
145+ }
146+ }
147+ }
148+ return {
149+ appName : item . appName ,
150+ name : item . name ,
151+ type : "application" ,
152+ id : item . applicationId ,
153+ createdAt : item . createdAt ,
154+ status : item . applicationStatus ,
155+ description : item . description ,
156+ serverId : item . serverId ,
157+ lastDeployDate,
158+ } ;
159+ } ) || [ ] ;
141160
142161 const mariadb : Services [ ] =
143162 environment . mariadb ?. map ( ( item ) => ( {
@@ -200,16 +219,34 @@ export const extractServicesFromEnvironment = (
200219 } ) ) || [ ] ;
201220
202221 const compose : Services [ ] =
203- environment . compose ?. map ( ( item ) => ( {
204- appName : item . appName ,
205- name : item . name ,
206- type : "compose" ,
207- id : item . composeId ,
208- createdAt : item . createdAt ,
209- status : item . composeStatus ,
210- description : item . description ,
211- serverId : item . serverId ,
212- } ) ) || [ ] ;
222+ environment . compose ?. map ( ( item ) => {
223+ // Get the most recent deployment date
224+ let lastDeployDate : Date | null = null ;
225+ const deployments = ( item as any ) . deployments ;
226+ if ( deployments && deployments . length > 0 ) {
227+ for ( const deployment of deployments ) {
228+ const deployDate = new Date (
229+ deployment . finishedAt ||
230+ deployment . startedAt ||
231+ deployment . createdAt ,
232+ ) ;
233+ if ( ! lastDeployDate || deployDate > lastDeployDate ) {
234+ lastDeployDate = deployDate ;
235+ }
236+ }
237+ }
238+ return {
239+ appName : item . appName ,
240+ name : item . name ,
241+ type : "compose" ,
242+ id : item . composeId ,
243+ createdAt : item . createdAt ,
244+ status : item . composeStatus ,
245+ description : item . description ,
246+ serverId : item . serverId ,
247+ lastDeployDate,
248+ } ;
249+ } ) || [ ] ;
213250
214251 allServices . push (
215252 ...applications ,
@@ -237,9 +274,9 @@ const EnvironmentPage = (
237274 const { data : auth } = api . user . get . useQuery ( ) ;
238275 const [ sortBy , setSortBy ] = useState < string > ( ( ) => {
239276 if ( typeof window !== "undefined" ) {
240- return localStorage . getItem ( "servicesSort" ) || "createdAt -desc" ;
277+ return localStorage . getItem ( "servicesSort" ) || "lastDeploy -desc" ;
241278 }
242- return "createdAt -desc" ;
279+ return "lastDeploy -desc" ;
243280 } ) ;
244281
245282 useEffect ( ( ) => {
@@ -261,10 +298,45 @@ const EnvironmentPage = (
261298 comparison =
262299 new Date ( a . createdAt ) . getTime ( ) - new Date ( b . createdAt ) . getTime ( ) ;
263300 break ;
301+ case "lastDeploy" : {
302+ const aLastDeploy = a . lastDeployDate ;
303+ const bLastDeploy = b . lastDeployDate ;
304+
305+ if ( direction === "desc" ) {
306+ // For "desc" (newest first): services with deployments first, then those without
307+ if ( ! aLastDeploy && ! bLastDeploy ) {
308+ comparison = 0 ;
309+ } else if ( ! aLastDeploy ) {
310+ comparison = 1 ; // a (no deploy) goes after b (has deploy)
311+ } else if ( ! bLastDeploy ) {
312+ comparison = - 1 ; // a (has deploy) goes before b (no deploy)
313+ } else {
314+ // Both have deployments: newest first (negative if a is newer)
315+ comparison = bLastDeploy . getTime ( ) - aLastDeploy . getTime ( ) ;
316+ }
317+ } else {
318+ // For "asc" (oldest first): services with deployments first, then those without
319+ if ( ! aLastDeploy && ! bLastDeploy ) {
320+ comparison = 0 ;
321+ } else if ( ! aLastDeploy ) {
322+ comparison = 1 ; // a (no deploy) goes after b (has deploy)
323+ } else if ( ! bLastDeploy ) {
324+ comparison = - 1 ; // a (has deploy) goes before b (no deploy)
325+ } else {
326+ // Both have deployments: oldest first
327+ comparison = aLastDeploy . getTime ( ) - bLastDeploy . getTime ( ) ;
328+ }
329+ }
330+ break ;
331+ }
264332 default :
265333 comparison = 0 ;
266334 }
267- return direction === "asc" ? comparison : - comparison ;
335+ // For other fields, apply direction normally
336+ if ( field !== "lastDeploy" ) {
337+ return direction === "asc" ? comparison : - comparison ;
338+ }
339+ return comparison ;
268340 } ) ;
269341 } ;
270342
@@ -1217,6 +1289,9 @@ const EnvironmentPage = (
12171289 < SelectValue placeholder = "Sort by..." />
12181290 </ SelectTrigger >
12191291 < SelectContent >
1292+ < SelectItem value = "lastDeploy-desc" >
1293+ Recently deployed
1294+ </ SelectItem >
12201295 < SelectItem value = "createdAt-desc" >
12211296 Newest first
12221297 </ SelectItem >
0 commit comments