@@ -22,6 +22,12 @@ const DEFAULT_PAGINATION_CONFIG = {
2222 pageSize : 25 ,
2323} ;
2424
25+ // Default sort configuration
26+ const DEFAULT_SORT_CONFIG = {
27+ sortField : "created_at" ,
28+ sortDirection : "desc" as "asc" | "desc" ,
29+ } ;
30+
2531export class GlobalState {
2632 isConnected : boolean = false ;
2733 // rollout_id -> EvaluationRow
@@ -37,6 +43,9 @@ export class GlobalState {
3743 // Pagination configuration
3844 currentPage : number ;
3945 pageSize : number ;
46+ // Sort configuration
47+ sortField : string ;
48+ sortDirection : "asc" | "desc" ;
4049 // Loading state
4150 isLoading : boolean = true ;
4251
@@ -64,6 +73,10 @@ export class GlobalState {
6473 const paginationConfig = this . loadPaginationConfig ( ) ;
6574 this . currentPage = paginationConfig . currentPage ;
6675 this . pageSize = paginationConfig . pageSize ;
76+ // Load sort config from localStorage or use defaults
77+ const sortConfig = this . loadSortConfig ( ) ;
78+ this . sortField = sortConfig . sortField ;
79+ this . sortDirection = sortConfig . sortDirection ;
6780 makeAutoObservable ( this ) ;
6881 }
6982
@@ -114,6 +127,21 @@ export class GlobalState {
114127 return DEFAULT_PAGINATION_CONFIG ;
115128 }
116129
130+ // Load sort configuration from localStorage
131+ private loadSortConfig ( ) {
132+ try {
133+ const stored = localStorage . getItem ( "sortConfig" ) ;
134+ if ( stored ) {
135+ const parsed = JSON . parse ( stored ) ;
136+ // Merge with defaults to handle any missing properties
137+ return { ...DEFAULT_SORT_CONFIG , ...parsed } ;
138+ }
139+ } catch ( error ) {
140+ console . warn ( "Failed to load sort config from localStorage:" , error ) ;
141+ }
142+ return DEFAULT_SORT_CONFIG ;
143+ }
144+
117145 // Save pivot configuration to localStorage
118146 private savePivotConfig ( ) {
119147 if ( this . savePivotConfigTimer ) clearTimeout ( this . savePivotConfigTimer ) ;
@@ -160,6 +188,24 @@ export class GlobalState {
160188 } , 200 ) ;
161189 }
162190
191+ // Save sort configuration to localStorage
192+ private saveSortConfig ( ) {
193+ if ( this . saveFilterConfigTimer ) clearTimeout ( this . saveFilterConfigTimer ) ;
194+ this . saveFilterConfigTimer = setTimeout ( ( ) => {
195+ try {
196+ localStorage . setItem (
197+ "sortConfig" ,
198+ JSON . stringify ( {
199+ sortField : this . sortField ,
200+ sortDirection : this . sortDirection ,
201+ } )
202+ ) ;
203+ } catch ( error ) {
204+ console . warn ( "Failed to save sort config to localStorage:" , error ) ;
205+ }
206+ } , 200 ) ;
207+ }
208+
163209 // Update pivot configuration and save to localStorage
164210 updatePivotConfig ( updates : Partial < PivotConfig > ) {
165211 Object . assign ( this . pivotConfig , updates ) ;
@@ -191,6 +237,29 @@ export class GlobalState {
191237 this . savePaginationConfig ( ) ;
192238 }
193239
240+ // Update sort configuration and save to localStorage
241+ updateSortConfig (
242+ updates : Partial < { sortField : string ; sortDirection : "asc" | "desc" } >
243+ ) {
244+ Object . assign ( this , updates ) ;
245+ // Reset to first page when sorting changes
246+ this . currentPage = 1 ;
247+ this . saveSortConfig ( ) ;
248+ }
249+
250+ // Handle sort field click - toggle direction if same field, set to asc if new field
251+ handleSortFieldClick ( field : string ) {
252+ if ( this . sortField === field ) {
253+ // Toggle direction for same field
254+ this . sortDirection = this . sortDirection === "asc" ? "desc" : "asc" ;
255+ } else {
256+ // New field, set to ascending
257+ this . sortField = field ;
258+ this . sortDirection = "asc" ;
259+ }
260+ this . saveSortConfig ( ) ;
261+ }
262+
194263 // Reset pivot configuration to defaults
195264 resetPivotConfig ( ) {
196265 this . pivotConfig = { ...DEFAULT_PIVOT_CONFIG } ;
@@ -211,6 +280,13 @@ export class GlobalState {
211280 this . savePaginationConfig ( ) ;
212281 }
213282
283+ // Reset sort configuration to defaults
284+ resetSortConfig ( ) {
285+ this . sortField = DEFAULT_SORT_CONFIG . sortField ;
286+ this . sortDirection = DEFAULT_SORT_CONFIG . sortDirection ;
287+ this . saveSortConfig ( ) ;
288+ }
289+
214290 // Set current page
215291 setCurrentPage ( page : number ) {
216292 this . currentPage = page ;
@@ -286,9 +362,48 @@ export class GlobalState {
286362
287363 // Computed values following MobX best practices
288364 get sortedIds ( ) {
289- return Object . keys ( this . dataset ) . sort (
290- ( a , b ) => ( this . createdAtMsById [ b ] ?? 0 ) - ( this . createdAtMsById [ a ] ?? 0 )
291- ) ;
365+ const ids = Object . keys ( this . dataset ) ;
366+
367+ if ( this . sortField === "created_at" ) {
368+ // Special case for created_at - use cached timestamp
369+ return ids . sort ( ( a , b ) => {
370+ const aTime = this . createdAtMsById [ a ] ?? 0 ;
371+ const bTime = this . createdAtMsById [ b ] ?? 0 ;
372+ return this . sortDirection === "asc" ? aTime - bTime : bTime - aTime ;
373+ } ) ;
374+ }
375+
376+ // For other fields, sort by flattened data
377+ return ids . sort ( ( a , b ) => {
378+ const aFlat = this . flattenedById [ a ] ;
379+ const bFlat = this . flattenedById [ b ] ;
380+
381+ if ( ! aFlat || ! bFlat ) return 0 ;
382+
383+ const aValue = aFlat [ this . sortField ] ;
384+ const bValue = bFlat [ this . sortField ] ;
385+
386+ // Handle undefined values
387+ if ( aValue === undefined && bValue === undefined ) return 0 ;
388+ if ( aValue === undefined ) return this . sortDirection === "asc" ? - 1 : 1 ;
389+ if ( bValue === undefined ) return this . sortDirection === "asc" ? 1 : - 1 ;
390+
391+ // Handle different types
392+ if ( typeof aValue === "string" && typeof bValue === "string" ) {
393+ const comparison = aValue . localeCompare ( bValue ) ;
394+ return this . sortDirection === "asc" ? comparison : - comparison ;
395+ }
396+
397+ if ( typeof aValue === "number" && typeof bValue === "number" ) {
398+ return this . sortDirection === "asc" ? aValue - bValue : bValue - aValue ;
399+ }
400+
401+ // Fallback to string comparison
402+ const aStr = String ( aValue ) ;
403+ const bStr = String ( bValue ) ;
404+ const comparison = aStr . localeCompare ( bStr ) ;
405+ return this . sortDirection === "asc" ? comparison : - comparison ;
406+ } ) ;
292407 }
293408
294409 get sortedDataset ( ) {
0 commit comments