@@ -495,27 +495,103 @@ defmodule CodexPooler.Admin.Stats do
495495 entries_by_identity = Enum . group_by ( settlements , & & 1 . upstream_identity_id )
496496
497497 quota_accounts
498- |> Enum . map ( fn account ->
499- entries = Map . get ( entries_by_identity , account . upstream_identity_id , [ ] )
498+ |> Enum . group_by ( & & 1 . upstream_identity_id )
499+ |> Enum . map ( fn { upstream_identity_id , accounts } ->
500+ entries = Map . get ( entries_by_identity , upstream_identity_id , [ ] )
501+ canonical_account = canonical_upstream_account ( accounts )
500502
501503 % {
502- pool_upstream_assignment_id: account . pool_upstream_assignment_id ,
503- upstream_identity_id: account . upstream_identity_id ,
504- assignment_label: account . assignment_label ,
505- upstream_label: account . upstream_label ,
506- status: account . assignment_status ,
507- health_status: account . health_status ,
508- quota_state: account . state ,
504+ pool_upstream_assignment_id: single_assignment_id ( accounts ) ,
505+ upstream_identity_id: upstream_identity_id ,
506+ assignment_label: shared_account_value ( accounts , :assignment_label ) ,
507+ upstream_label:
508+ shared_account_value ( accounts , :upstream_label ) || canonical_account . upstream_label ,
509+ status: aggregate_account_value ( accounts , :assignment_status ) ,
510+ health_status: aggregate_account_value ( accounts , :health_status ) ,
511+ quota_state: aggregate_account_value ( accounts , :state , :mixed ) ,
512+ assignment_count: length ( accounts ) ,
509513 requests: sum_integer ( entries , :request_count ) ,
510514 total_tokens: sum_integer ( entries , :total_tokens ) ,
511515 settled_cost_micros: sum_decimal_integer ( entries , :settled_cost_micros )
512516 }
513517 end )
514518 |> Enum . sort_by ( fn row ->
515- { - row . total_tokens , - row . requests , row . assignment_label || row . upstream_label || "" }
519+ { - row . total_tokens , - row . requests , upstream_table_label ( row ) ,
520+ row . upstream_identity_id || "" }
516521 end )
517522 end
518523
524+ @ spec canonical_upstream_account ( [ map ( ) ] ) :: map ( )
525+ defp canonical_upstream_account ( accounts ) do
526+ Enum . min_by ( accounts , & upstream_account_sort_key / 1 , fn -> % { } end )
527+ end
528+
529+ @ spec single_assignment_id ( [ map ( ) ] ) :: Ecto.UUID . t ( ) | nil
530+ defp single_assignment_id ( [ account ] ) , do: Map . get ( account , :pool_upstream_assignment_id )
531+ defp single_assignment_id ( _accounts ) , do: nil
532+
533+ @ spec shared_account_value ( [ map ( ) ] , atom ( ) ) :: term ( ) | nil
534+ defp shared_account_value ( accounts , field ) do
535+ case distinct_account_values ( accounts , field ) do
536+ [ value ] -> value
537+ _values -> nil
538+ end
539+ end
540+
541+ @ spec aggregate_account_value ( [ map ( ) ] , atom ( ) , term ( ) ) :: term ( ) | nil
542+ defp aggregate_account_value ( accounts , field , mixed_value \\ "mixed" ) do
543+ case distinct_account_values ( accounts , field ) do
544+ [ value ] -> value
545+ [ ] -> nil
546+ _values -> mixed_value
547+ end
548+ end
549+
550+ @ spec distinct_account_values ( [ map ( ) ] , atom ( ) ) :: [ term ( ) ]
551+ defp distinct_account_values ( accounts , field ) do
552+ accounts
553+ |> Enum . map ( & Map . get ( & 1 , field ) )
554+ |> Enum . reject ( & blank_value? / 1 )
555+ |> Enum . uniq ( )
556+ end
557+
558+ @ spec upstream_account_sort_key ( map ( ) ) :: { integer ( ) , String . t ( ) , String . t ( ) }
559+ defp upstream_account_sort_key ( account ) do
560+ {
561+ assignment_status_rank ( Map . get ( account , :assignment_status ) ) ,
562+ safe_string ( Map . get ( account , :assignment_label ) || Map . get ( account , :upstream_label ) ) ,
563+ safe_string ( Map . get ( account , :pool_upstream_assignment_id ) )
564+ }
565+ end
566+
567+ @ spec assignment_status_rank ( term ( ) ) :: non_neg_integer ( )
568+ defp assignment_status_rank ( "active" ) , do: 0
569+ defp assignment_status_rank ( "pending" ) , do: 1
570+ defp assignment_status_rank ( "refresh_due" ) , do: 2
571+ defp assignment_status_rank ( "refreshing" ) , do: 3
572+ defp assignment_status_rank ( "paused" ) , do: 4
573+ defp assignment_status_rank ( "refresh_failed" ) , do: 5
574+ defp assignment_status_rank ( "reauth_required" ) , do: 6
575+ defp assignment_status_rank ( "disabled" ) , do: 7
576+ defp assignment_status_rank ( "errored" ) , do: 8
577+ defp assignment_status_rank ( "deleted" ) , do: 9
578+ defp assignment_status_rank ( _status ) , do: 10
579+
580+ @ spec upstream_table_label ( map ( ) ) :: String . t ( )
581+ defp upstream_table_label ( row ) do
582+ safe_string ( row . assignment_label || row . upstream_label )
583+ end
584+
585+ @ spec blank_value? ( term ( ) ) :: boolean ( )
586+ defp blank_value? ( nil ) , do: true
587+ defp blank_value? ( value ) when is_binary ( value ) , do: String . trim ( value ) == ""
588+ defp blank_value? ( _value ) , do: false
589+
590+ @ spec safe_string ( term ( ) ) :: String . t ( )
591+ defp safe_string ( nil ) , do: ""
592+ defp safe_string ( value ) when is_binary ( value ) , do: value
593+ defp safe_string ( value ) , do: to_string ( value )
594+
519595 defp usage_pool_name ( entries , pool_names_by_id ) do
520596 entries
521597 |> Enum . map ( & & 1 . pool_id )
0 commit comments