diff --git a/.changeset/sort-scopes-by-service.md b/.changeset/sort-scopes-by-service.md new file mode 100644 index 00000000..cdf55e2b --- /dev/null +++ b/.changeset/sort-scopes-by-service.md @@ -0,0 +1,5 @@ +--- +"@googleworkspace/cli": patch +--- + +Sort OAuth scopes in the TUI picker by service name first, then access level (read-only before write), then sensitivity classification, for easier browsing diff --git a/src/setup.rs b/src/setup.rs index 10aebe1b..df219e46 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -254,6 +254,16 @@ pub struct DiscoveredScope { pub classification: ScopeClassification, } +/// Compare two scopes for sorting: group by service, then read-only first, +/// then non-sensitive before restricted, then alphabetically. +fn compare_scopes(a: &DiscoveredScope, b: &DiscoveredScope) -> std::cmp::Ordering { + a.api_name + .cmp(&b.api_name) + .then_with(|| b.is_readonly.cmp(&a.is_readonly)) + .then_with(|| a.classification.cmp(&b.classification)) + .then_with(|| a.short.cmp(&b.short)) +} + /// Fetch scopes from discovery docs for the given enabled API IDs. pub async fn fetch_scopes_for_apis(enabled_api_ids: &[String]) -> Vec { let mut all_scopes: Vec = Vec::new(); @@ -359,12 +369,10 @@ pub async fn fetch_scopes_for_apis(enabled_api_ids: &[String]) -> Vec = scopes.iter().map(|s| s.short.as_str()).collect(); + assert_eq!( + sorted_shorts, + &[ + "drive.readonly", + "drive.metadata", + "drive", + "gmail.readonly", + "gmail", + ] + ); + + // Verify classification sorting for the Drive write scopes. + assert_eq!(scopes[1].classification, ScopeClassification::Sensitive); + assert_eq!(scopes[2].classification, ScopeClassification::Restricted); + } }