@@ -4,6 +4,7 @@ import React, { useEffect, useState } from "react";
44import { measureProgress } from "@site/src/pages/status/migration" ;
55import styles from "./styles.module.css" ;
66import Link from "@docusaurus/Link" ;
7+ import { SortableHeader } from "@site/src/components/SortableTable" ;
78
89const COLLAPSED_KEY = "migration-collapsed" ;
910const SORT_KEY = "migration-sort" ;
@@ -135,54 +136,30 @@ function TableContent({ collapsed, name, resort, rows, select, sort, fetched })
135136 </ th >
136137 </ tr >
137138 < tr className = { collapsed ? styles . collapsed : undefined } >
138- < th
139- onClick = { ( ) => resort ( "name" ) }
140- className = { sort . by === "name" ? styles [ sort . order ] : undefined }
141- >
139+ < SortableHeader sortKey = "name" currentSort = { sort } onSort = { resort } styles = { styles } >
142140 Name
143- </ th >
144- < th
145- onClick = { ( ) => resort ( "status" ) }
146- className = { sort . by === "status" ? styles [ sort . order ] : undefined }
147- >
141+ </ SortableHeader >
142+ < SortableHeader sortKey = "status" currentSort = { sort } onSort = { resort } styles = { styles } >
148143 PRs made
149- </ th >
150- < th
151- onClick = { ( ) => resort ( "done" ) }
152- className = { sort . by === "done" ? styles [ sort . order ] : undefined }
153- >
144+ </ SortableHeader >
145+ < SortableHeader sortKey = "done" currentSort = { sort } onSort = { resort } styles = { styles } >
154146 Done
155- </ th >
156- < th
157- onClick = { ( ) => resort ( "in-pr" ) }
158- className = { sort . by === "in-pr" ? styles [ sort . order ] : undefined }
159- >
147+ </ SortableHeader >
148+ < SortableHeader sortKey = "in-pr" currentSort = { sort } onSort = { resort } styles = { styles } >
160149 In PR
161- </ th >
162- < th
163- onClick = { ( ) => resort ( "awaiting-pr" ) }
164- className = { sort . by === "awaiting-pr" ? styles [ sort . order ] : undefined }
165- >
150+ </ SortableHeader >
151+ < SortableHeader sortKey = "awaiting-pr" currentSort = { sort } onSort = { resort } styles = { styles } >
166152 Awaiting PR
167- </ th >
168- < th
169- onClick = { ( ) => resort ( "awaiting-parents" ) }
170- className = { sort . by === "awaiting-parents" ? styles [ sort . order ] : undefined }
171- >
153+ </ SortableHeader >
154+ < SortableHeader sortKey = "awaiting-parents" currentSort = { sort } onSort = { resort } styles = { styles } >
172155 Awaiting parents
173- </ th >
174- < th
175- onClick = { ( ) => resort ( "not-solvable" ) }
176- className = { sort . by === "not-solvable" ? styles [ sort . order ] : undefined }
177- >
156+ </ SortableHeader >
157+ < SortableHeader sortKey = "not-solvable" currentSort = { sort } onSort = { resort } styles = { styles } >
178158 Not solvable
179- </ th >
180- < th
181- onClick = { ( ) => resort ( "bot-error" ) }
182- className = { sort . by === "bot-error" ? styles [ sort . order ] : undefined }
183- >
159+ </ SortableHeader >
160+ < SortableHeader sortKey = "bot-error" currentSort = { sort } onSort = { resort } styles = { styles } >
184161 Bot error
185- </ th >
162+ </ SortableHeader >
186163 </ tr >
187164 </ thead >
188165 < tbody className = { collapsed ? styles . collapsed : undefined } >
@@ -230,20 +207,81 @@ function TableContent({ collapsed, name, resort, rows, select, sort, fetched })
230207}
231208
232209// Returns a comparator function for sorting table columns.
233- function compare ( by , order ) {
210+ // Supports secondary sorting: when primary values are equal, falls back to previousSort
211+ export function compare ( by , order , previousSort = null ) {
212+ const secondaryComparator = previousSort ? compare ( previousSort . by , previousSort . order , null ) : null ;
213+
214+ const applySecondarySort = ( primaryResult , a , b ) => {
215+ if ( primaryResult !== 0 || ! secondaryComparator ) return primaryResult ;
216+ return secondaryComparator ( a , b ) ;
217+ } ;
218+
234219 switch ( by ) {
235220 case "name" :
236- return order === "ascending"
237- ? ( a , b ) => a . name . localeCompare ( b . name )
238- : ( a , b ) => b . name . localeCompare ( a . name ) ;
221+ return ( a , b ) => {
222+ const result = order === "ascending"
223+ ? a . name . localeCompare ( b . name )
224+ : b . name . localeCompare ( a . name ) ;
225+ return applySecondarySort ( result , a , b ) ;
226+ } ;
239227 case "status" :
240- return order === "ascending"
241- ? ( a , b ) => a . progress . percentage - b . progress . percentage
242- : ( a , b ) => b . progress . percentage - a . progress . percentage ;
228+ return ( a , b ) => {
229+ const result = order === "ascending"
230+ ? a . progress . percentage - b . progress . percentage
231+ : b . progress . percentage - a . progress . percentage ;
232+ return applySecondarySort ( result , a , b ) ;
233+ } ;
234+ case "migration_status" :
235+ return ( a , b ) => {
236+ const result = order === "ascending"
237+ ? ( a . migration_status_order ?? 999 ) - ( b . migration_status_order ?? 999 )
238+ : ( b . migration_status_order ?? 999 ) - ( a . migration_status_order ?? 999 ) ;
239+ return applySecondarySort ( result , a , b ) ;
240+ } ;
241+ case "ci_status" :
242+ return ( a , b ) => {
243+ const aOrder = a . ci_status_order ?? 999 ;
244+ const bOrder = b . ci_status_order ?? 999 ;
245+ let result ;
246+ // Always put items with no CI status (order >= 999) last
247+ if ( aOrder >= 999 && bOrder < 999 ) result = 1 ;
248+ else if ( aOrder < 999 && bOrder >= 999 ) result = - 1 ;
249+ else if ( aOrder >= 999 && bOrder >= 999 ) result = 0 ;
250+ else {
251+ // Normal sorting for items with CI status
252+ result = order === "ascending" ? aOrder - bOrder : bOrder - aOrder ;
253+ }
254+ return applySecondarySort ( result , a , b ) ;
255+ } ;
256+ case "num_descendants" :
257+ return ( a , b ) => {
258+ const result = order === "ascending"
259+ ? ( a . num_descendants ?? 0 ) - ( b . num_descendants ?? 0 )
260+ : ( b . num_descendants ?? 0 ) - ( a . num_descendants ?? 0 ) ;
261+ return applySecondarySort ( result , a , b ) ;
262+ } ;
263+ case "updated_at" :
264+ return ( a , b ) => {
265+ const aTimestamp = a . updated_at_timestamp ?? 0 ;
266+ const bTimestamp = b . updated_at_timestamp ?? 0 ;
267+ let result ;
268+ // Always put items with no timestamp (0) last
269+ if ( aTimestamp === 0 && bTimestamp !== 0 ) result = 1 ;
270+ else if ( aTimestamp !== 0 && bTimestamp === 0 ) result = - 1 ;
271+ else if ( aTimestamp === 0 && bTimestamp === 0 ) result = 0 ;
272+ else {
273+ // Normal sorting for items with timestamps
274+ result = order === "ascending" ? aTimestamp - bTimestamp : bTimestamp - aTimestamp ;
275+ }
276+ return applySecondarySort ( result , a , b ) ;
277+ } ;
243278 default :
244- return order === "ascending"
245- ? ( a , b ) => a . details [ by ] . length - b . details [ by ] . length
246- : ( a , b ) => b . details [ by ] . length - a . details [ by ] . length ;
279+ return ( a , b ) => {
280+ const result = order === "ascending"
281+ ? a . details [ by ] . length - b . details [ by ] . length
282+ : b . details [ by ] . length - a . details [ by ] . length ;
283+ return applySecondarySort ( result , a , b ) ;
284+ } ;
247285 }
248286}
249287
0 commit comments